mirror of
https://github.com/ReneLergner/WPinternals.git
synced 2026-06-13 19:06:41 +10:00
Project: Move WPinternals code to a WPinternals folder
This commit is contained in:
+1
-1
@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31606.5
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WPinternals", "WPinternals.csproj", "{AED6DEB8-F54C-4B41-9655-793E7096AE6E}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WPinternals", "WPinternals\WPinternals.csproj", "{AED6DEB8-F54C-4B41-9655-793E7096AE6E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
+465
-465
@@ -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) {}
|
||||
*/
|
||||
}
|
||||
}
|
||||
+1692
-1692
File diff suppressed because it is too large
Load Diff
+243
-243
@@ -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(); }
|
||||
}
|
||||
}
|
||||
+127
-127
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+164
-164
@@ -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);
|
||||
}
|
||||
}
|
||||
+112
-112
@@ -1,112 +1,112 @@
|
||||
<!--
|
||||
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>
|
||||
<!--
|
||||
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 - @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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2109
-2109
File diff suppressed because it is too large
Load Diff
@@ -1,41 +1,41 @@
|
||||
<!--
|
||||
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>
|
||||
<!--
|
||||
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>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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; }
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
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 - @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 = 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,487 +1,487 @@
|
||||
// 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(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(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();
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,312 +1,312 @@
|
||||
// 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(
|
||||
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(
|
||||
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) { }
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,302 +1,302 @@
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,412 +1,412 @@
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,145 +1,145 @@
|
||||
// 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(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(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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,228 +1,228 @@
|
||||
// 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 = 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 = 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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,124 +1,124 @@
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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,174 @@
|
||||
// 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(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(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,379 +1,379 @@
|
||||
// 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(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(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,119 +1,119 @@
|
||||
// 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,
|
||||
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,
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,56 +1,56 @@
|
||||
// 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,
|
||||
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,
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,88 +1,88 @@
|
||||
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
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 = 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
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-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")]
|
||||
+63
-63
@@ -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>
|
||||
+26
-26
@@ -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 - @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,295 @@
|
||||
// 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);
|
||||
|
||||
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);
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +1,43 @@
|
||||
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+237
-237
@@ -1,237 +1,237 @@
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,490 +1,490 @@
|
||||
// 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.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class BackupViewModel : ContextViewModel
|
||||
{
|
||||
private readonly PhoneNotifierViewModel PhoneNotifier;
|
||||
private readonly Action Callback;
|
||||
private readonly Action SwitchToUnlockBoot;
|
||||
|
||||
internal BackupViewModel(PhoneNotifierViewModel PhoneNotifier, Action SwitchToUnlockBoot, Action Callback)
|
||||
: base()
|
||||
{
|
||||
IsFlashModeOperation = true;
|
||||
|
||||
this.PhoneNotifier = PhoneNotifier;
|
||||
this.SwitchToUnlockBoot = SwitchToUnlockBoot;
|
||||
this.Callback = Callback;
|
||||
}
|
||||
|
||||
internal override void EvaluateViewState()
|
||||
{
|
||||
if (!IsActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (SubContextViewModel == null)
|
||||
{
|
||||
ActivateSubContext(new BackupTargetSelectionViewModel(PhoneNotifier, SwitchToUnlockBoot, DoBackupArchive, DoBackup, DoBackupArchiveProvisioning));
|
||||
IsSwitchingInterface = false;
|
||||
}
|
||||
|
||||
if (SubContextViewModel is BackupTargetSelectionViewModel)
|
||||
{
|
||||
((BackupTargetSelectionViewModel)SubContextViewModel).EvaluateViewState();
|
||||
}
|
||||
}
|
||||
|
||||
internal async void DoBackup(string EFIESPPath, string MainOSPath, string DataPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
IsSwitchingInterface = true;
|
||||
await SwitchModeViewModel.SwitchToWithProgress(PhoneNotifier, PhoneInterfaces.Lumia_MassStorage,
|
||||
(msg, sub) => ActivateSubContext(new BusyViewModel(msg, sub)));
|
||||
BackupTask(EFIESPPath, MainOSPath, DataPath);
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel(Ex.Message, Callback));
|
||||
}
|
||||
}
|
||||
|
||||
internal async void DoBackupArchive(string ArchivePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
IsSwitchingInterface = true;
|
||||
await SwitchModeViewModel.SwitchToWithProgress(PhoneNotifier, PhoneInterfaces.Lumia_MassStorage,
|
||||
(msg, sub) => ActivateSubContext(new BusyViewModel(msg, sub)));
|
||||
BackupArchiveTask(ArchivePath);
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel(Ex.Message, Callback));
|
||||
}
|
||||
}
|
||||
|
||||
internal async void DoBackupArchiveProvisioning(string ArchiveProvisioningPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
IsSwitchingInterface = true;
|
||||
await SwitchModeViewModel.SwitchToWithProgress(PhoneNotifier, PhoneInterfaces.Lumia_MassStorage,
|
||||
(msg, sub) => ActivateSubContext(new BusyViewModel(msg, sub)));
|
||||
BackupArchiveProvisioningTask(ArchiveProvisioningPath);
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel(Ex.Message, Callback));
|
||||
}
|
||||
}
|
||||
|
||||
internal void BackupTask(string EFIESPPath, string MainOSPath, string DataPath)
|
||||
{
|
||||
IsSwitchingInterface = false;
|
||||
new Thread(() =>
|
||||
{
|
||||
bool Result = true;
|
||||
|
||||
ActivateSubContext(new BusyViewModel("Initializing backup..."));
|
||||
|
||||
ulong TotalSizeSectors = 0;
|
||||
int PartitionCount = 0;
|
||||
|
||||
MassStorage Phone = (MassStorage)PhoneNotifier.CurrentModel;
|
||||
|
||||
Phone.OpenVolume(false);
|
||||
byte[] GPTBuffer = Phone.ReadSectors(1, 33);
|
||||
GPT GPT = new(GPTBuffer);
|
||||
Partition Partition;
|
||||
try
|
||||
{
|
||||
if (EFIESPPath != null)
|
||||
{
|
||||
Partition = GPT.Partitions.First(p => p.Name == "EFIESP");
|
||||
TotalSizeSectors += Partition.SizeInSectors;
|
||||
PartitionCount++;
|
||||
}
|
||||
|
||||
if (MainOSPath != null)
|
||||
{
|
||||
Partition = GPT.Partitions.First(p => p.Name == "MainOS");
|
||||
TotalSizeSectors += Partition.SizeInSectors;
|
||||
PartitionCount++;
|
||||
}
|
||||
|
||||
if (DataPath != null)
|
||||
{
|
||||
Partition = GPT.Partitions.First(p => p.Name == "Data");
|
||||
TotalSizeSectors += Partition.SizeInSectors;
|
||||
PartitionCount++;
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
|
||||
BusyViewModel Busy = new("Create backup...", MaxProgressValue: TotalSizeSectors, UIContext: UIContext);
|
||||
ProgressUpdater Updater = Busy.ProgressUpdater;
|
||||
ActivateSubContext(Busy);
|
||||
|
||||
int i = 0;
|
||||
if (Result)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (EFIESPPath != null)
|
||||
{
|
||||
i++;
|
||||
Busy.Message = "Create backup of partition EFIESP (" + i.ToString() + "/" + PartitionCount.ToString() + ")";
|
||||
Phone.BackupPartition("EFIESP", EFIESPPath, Updater);
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (Result)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (MainOSPath != null)
|
||||
{
|
||||
i++;
|
||||
Busy.Message = "Create backup of partition MainOS (" + i.ToString() + "/" + PartitionCount.ToString() + ")";
|
||||
Phone.BackupPartition("MainOS", MainOSPath, Updater);
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (Result)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (DataPath != null)
|
||||
{
|
||||
i++;
|
||||
Busy.Message = "Create backup of partition Data (" + i.ToString() + "/" + PartitionCount.ToString() + ")";
|
||||
Phone.BackupPartition("Data", DataPath, Updater);
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
}
|
||||
|
||||
Phone.CloseVolume();
|
||||
|
||||
if (!Result)
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel("Failed to create backup!", Exit));
|
||||
return;
|
||||
}
|
||||
|
||||
ActivateSubContext(new MessageViewModel("Successfully created a backup!", Exit));
|
||||
}).Start();
|
||||
}
|
||||
|
||||
internal void BackupArchiveTask(string ArchivePath)
|
||||
{
|
||||
IsSwitchingInterface = false;
|
||||
new Thread(() =>
|
||||
{
|
||||
bool Result = true;
|
||||
|
||||
ActivateSubContext(new BusyViewModel("Initializing backup..."));
|
||||
|
||||
ulong TotalSizeSectors = 0;
|
||||
const int PartitionCount = 3;
|
||||
|
||||
MassStorage Phone = (MassStorage)PhoneNotifier.CurrentModel;
|
||||
|
||||
try
|
||||
{
|
||||
Phone.OpenVolume(false);
|
||||
byte[] GPTBuffer = Phone.ReadSectors(1, 33);
|
||||
GPT GPT = new(GPTBuffer);
|
||||
|
||||
Partition Partition;
|
||||
|
||||
try
|
||||
{
|
||||
Partition = GPT.Partitions.First(p => p.Name == "EFIESP");
|
||||
TotalSizeSectors += Partition.SizeInSectors;
|
||||
|
||||
Partition = GPT.Partitions.First(p => p.Name == "MainOS");
|
||||
TotalSizeSectors += Partition.SizeInSectors;
|
||||
|
||||
Partition = GPT.Partitions.First(p => p.Name == "Data");
|
||||
TotalSizeSectors += Partition.SizeInSectors;
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
|
||||
BusyViewModel Busy = new("Create backup...", MaxProgressValue: TotalSizeSectors, UIContext: UIContext);
|
||||
ProgressUpdater Updater = Busy.ProgressUpdater;
|
||||
ActivateSubContext(Busy);
|
||||
ZipArchiveEntry Entry;
|
||||
Stream EntryStream = null;
|
||||
|
||||
using FileStream FileStream = new(ArchivePath, FileMode.Create);
|
||||
using ZipArchive Archive = new(FileStream, ZipArchiveMode.Create);
|
||||
int i = 0;
|
||||
|
||||
if (Result)
|
||||
{
|
||||
try
|
||||
{
|
||||
Entry = Archive.CreateEntry("EFIESP.bin", CompressionLevel.Optimal);
|
||||
EntryStream = Entry.Open();
|
||||
i++;
|
||||
Busy.Message = "Create backup of partition EFIESP (" + i.ToString() + "/" + PartitionCount.ToString() + ")";
|
||||
Phone.BackupPartition("EFIESP", EntryStream, Updater);
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
EntryStream?.Close();
|
||||
EntryStream = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (Result)
|
||||
{
|
||||
try
|
||||
{
|
||||
Entry = Archive.CreateEntry("MainOS.bin", CompressionLevel.Optimal);
|
||||
EntryStream = Entry.Open();
|
||||
i++;
|
||||
Busy.Message = "Create backup of partition MainOS (" + i.ToString() + "/" + PartitionCount.ToString() + ")";
|
||||
Phone.BackupPartition("MainOS", EntryStream, Updater);
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
EntryStream?.Close();
|
||||
EntryStream = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (Result)
|
||||
{
|
||||
try
|
||||
{
|
||||
Entry = Archive.CreateEntry("Data.bin", CompressionLevel.Optimal);
|
||||
EntryStream = Entry.Open();
|
||||
i++;
|
||||
Busy.Message = "Create backup of partition Data (" + i.ToString() + "/" + PartitionCount.ToString() + ")";
|
||||
Phone.BackupPartition("Data", EntryStream, Updater);
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
EntryStream?.Close();
|
||||
EntryStream = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
finally
|
||||
{
|
||||
Phone.CloseVolume();
|
||||
}
|
||||
|
||||
if (!Result)
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel("Failed to create backup!", Exit));
|
||||
return;
|
||||
}
|
||||
|
||||
ActivateSubContext(new MessageViewModel("Successfully created a backup!", Exit));
|
||||
}).Start();
|
||||
}
|
||||
|
||||
private readonly static string[] ProvisioningPartitions = new string[]
|
||||
{
|
||||
"DPP",
|
||||
"MODEM_FSG",
|
||||
"MODEM_FS1",
|
||||
"MODEM_FS2",
|
||||
"MODEM_FSC",
|
||||
"DDR",
|
||||
"SEC",
|
||||
"APDP",
|
||||
"MSADP",
|
||||
"DPO",
|
||||
"SSD",
|
||||
"DBI",
|
||||
"UEFI_BS_NV",
|
||||
"UEFI_NV",
|
||||
"UEFI_RT_NV",
|
||||
"UEFI_RT_NV_RPMB",
|
||||
"BOOTMODE",
|
||||
"LIMITS"
|
||||
};
|
||||
|
||||
internal void BackupArchiveProvisioningTask(string ArchiveProvisioningPath)
|
||||
{
|
||||
IsSwitchingInterface = false;
|
||||
new Thread(() =>
|
||||
{
|
||||
bool Result = true;
|
||||
|
||||
ActivateSubContext(new BusyViewModel("Initializing backup..."));
|
||||
|
||||
ulong TotalSizeSectors = 0;
|
||||
int PartitionCount = 0;
|
||||
|
||||
MassStorage Phone = (MassStorage)PhoneNotifier.CurrentModel;
|
||||
|
||||
try
|
||||
{
|
||||
Phone.OpenVolume(false);
|
||||
byte[] GPTBuffer = Phone.ReadSectors(1, 33);
|
||||
GPT GPT = new(GPTBuffer);
|
||||
|
||||
Partition Partition;
|
||||
|
||||
try
|
||||
{
|
||||
foreach (string PartitionName in ProvisioningPartitions)
|
||||
{
|
||||
if (GPT.Partitions.Any(p => p.Name == PartitionName))
|
||||
{
|
||||
Partition = GPT.Partitions.First(p => p.Name == PartitionName);
|
||||
if (PartitionName == "UEFI_BS_NV" && GPT.Partitions.Any(p => p.Name == "BACKUP_BS_NV"))
|
||||
{
|
||||
Partition = GPT.Partitions.First(p => p.Name == "BACKUP_BS_NV");
|
||||
}
|
||||
|
||||
TotalSizeSectors += Partition.SizeInSectors;
|
||||
PartitionCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
|
||||
BusyViewModel Busy = new("Create backup...", MaxProgressValue: TotalSizeSectors, UIContext: UIContext);
|
||||
ProgressUpdater Updater = Busy.ProgressUpdater;
|
||||
ActivateSubContext(Busy);
|
||||
ZipArchiveEntry Entry;
|
||||
Stream EntryStream = null;
|
||||
|
||||
using FileStream FileStream = new(ArchiveProvisioningPath, FileMode.Create);
|
||||
using ZipArchive Archive = new(FileStream, ZipArchiveMode.Create);
|
||||
int i = 0;
|
||||
|
||||
foreach (string PartitionName in ProvisioningPartitions)
|
||||
{
|
||||
if (GPT.Partitions.Any(p => p.Name == PartitionName) && Result)
|
||||
{
|
||||
try
|
||||
{
|
||||
Entry = Archive.CreateEntry(PartitionName + ".bin", CompressionLevel.Optimal);
|
||||
EntryStream = Entry.Open();
|
||||
i++;
|
||||
Busy.Message = "Create backup of partition " + PartitionName + " (" + i.ToString() + "/" + PartitionCount.ToString() + ")";
|
||||
if (PartitionName == "UEFI_BS_NV" && GPT.Partitions.Any(p => p.Name == "BACKUP_BS_NV"))
|
||||
{
|
||||
Phone.BackupPartition("BACKUP_BS_NV", EntryStream, Updater);
|
||||
}
|
||||
else
|
||||
{
|
||||
Phone.BackupPartition(PartitionName, EntryStream, Updater);
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
EntryStream?.Close();
|
||||
EntryStream = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
finally
|
||||
{
|
||||
Phone.CloseVolume();
|
||||
}
|
||||
|
||||
if (!Result)
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel("Failed to create backup!", Exit));
|
||||
return;
|
||||
}
|
||||
|
||||
ActivateSubContext(new MessageViewModel("Successfully created a backup!", Exit));
|
||||
}).Start();
|
||||
}
|
||||
|
||||
private void Exit()
|
||||
{
|
||||
IsSwitchingInterface = false;
|
||||
ActivateSubContext(null);
|
||||
Callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class BackupViewModel : ContextViewModel
|
||||
{
|
||||
private readonly PhoneNotifierViewModel PhoneNotifier;
|
||||
private readonly Action Callback;
|
||||
private readonly Action SwitchToUnlockBoot;
|
||||
|
||||
internal BackupViewModel(PhoneNotifierViewModel PhoneNotifier, Action SwitchToUnlockBoot, Action Callback)
|
||||
: base()
|
||||
{
|
||||
IsFlashModeOperation = true;
|
||||
|
||||
this.PhoneNotifier = PhoneNotifier;
|
||||
this.SwitchToUnlockBoot = SwitchToUnlockBoot;
|
||||
this.Callback = Callback;
|
||||
}
|
||||
|
||||
internal override void EvaluateViewState()
|
||||
{
|
||||
if (!IsActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (SubContextViewModel == null)
|
||||
{
|
||||
ActivateSubContext(new BackupTargetSelectionViewModel(PhoneNotifier, SwitchToUnlockBoot, DoBackupArchive, DoBackup, DoBackupArchiveProvisioning));
|
||||
IsSwitchingInterface = false;
|
||||
}
|
||||
|
||||
if (SubContextViewModel is BackupTargetSelectionViewModel)
|
||||
{
|
||||
((BackupTargetSelectionViewModel)SubContextViewModel).EvaluateViewState();
|
||||
}
|
||||
}
|
||||
|
||||
internal async void DoBackup(string EFIESPPath, string MainOSPath, string DataPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
IsSwitchingInterface = true;
|
||||
await SwitchModeViewModel.SwitchToWithProgress(PhoneNotifier, PhoneInterfaces.Lumia_MassStorage,
|
||||
(msg, sub) => ActivateSubContext(new BusyViewModel(msg, sub)));
|
||||
BackupTask(EFIESPPath, MainOSPath, DataPath);
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel(Ex.Message, Callback));
|
||||
}
|
||||
}
|
||||
|
||||
internal async void DoBackupArchive(string ArchivePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
IsSwitchingInterface = true;
|
||||
await SwitchModeViewModel.SwitchToWithProgress(PhoneNotifier, PhoneInterfaces.Lumia_MassStorage,
|
||||
(msg, sub) => ActivateSubContext(new BusyViewModel(msg, sub)));
|
||||
BackupArchiveTask(ArchivePath);
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel(Ex.Message, Callback));
|
||||
}
|
||||
}
|
||||
|
||||
internal async void DoBackupArchiveProvisioning(string ArchiveProvisioningPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
IsSwitchingInterface = true;
|
||||
await SwitchModeViewModel.SwitchToWithProgress(PhoneNotifier, PhoneInterfaces.Lumia_MassStorage,
|
||||
(msg, sub) => ActivateSubContext(new BusyViewModel(msg, sub)));
|
||||
BackupArchiveProvisioningTask(ArchiveProvisioningPath);
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel(Ex.Message, Callback));
|
||||
}
|
||||
}
|
||||
|
||||
internal void BackupTask(string EFIESPPath, string MainOSPath, string DataPath)
|
||||
{
|
||||
IsSwitchingInterface = false;
|
||||
new Thread(() =>
|
||||
{
|
||||
bool Result = true;
|
||||
|
||||
ActivateSubContext(new BusyViewModel("Initializing backup..."));
|
||||
|
||||
ulong TotalSizeSectors = 0;
|
||||
int PartitionCount = 0;
|
||||
|
||||
MassStorage Phone = (MassStorage)PhoneNotifier.CurrentModel;
|
||||
|
||||
Phone.OpenVolume(false);
|
||||
byte[] GPTBuffer = Phone.ReadSectors(1, 33);
|
||||
GPT GPT = new(GPTBuffer);
|
||||
Partition Partition;
|
||||
try
|
||||
{
|
||||
if (EFIESPPath != null)
|
||||
{
|
||||
Partition = GPT.Partitions.First(p => p.Name == "EFIESP");
|
||||
TotalSizeSectors += Partition.SizeInSectors;
|
||||
PartitionCount++;
|
||||
}
|
||||
|
||||
if (MainOSPath != null)
|
||||
{
|
||||
Partition = GPT.Partitions.First(p => p.Name == "MainOS");
|
||||
TotalSizeSectors += Partition.SizeInSectors;
|
||||
PartitionCount++;
|
||||
}
|
||||
|
||||
if (DataPath != null)
|
||||
{
|
||||
Partition = GPT.Partitions.First(p => p.Name == "Data");
|
||||
TotalSizeSectors += Partition.SizeInSectors;
|
||||
PartitionCount++;
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
|
||||
BusyViewModel Busy = new("Create backup...", MaxProgressValue: TotalSizeSectors, UIContext: UIContext);
|
||||
ProgressUpdater Updater = Busy.ProgressUpdater;
|
||||
ActivateSubContext(Busy);
|
||||
|
||||
int i = 0;
|
||||
if (Result)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (EFIESPPath != null)
|
||||
{
|
||||
i++;
|
||||
Busy.Message = "Create backup of partition EFIESP (" + i.ToString() + "/" + PartitionCount.ToString() + ")";
|
||||
Phone.BackupPartition("EFIESP", EFIESPPath, Updater);
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (Result)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (MainOSPath != null)
|
||||
{
|
||||
i++;
|
||||
Busy.Message = "Create backup of partition MainOS (" + i.ToString() + "/" + PartitionCount.ToString() + ")";
|
||||
Phone.BackupPartition("MainOS", MainOSPath, Updater);
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (Result)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (DataPath != null)
|
||||
{
|
||||
i++;
|
||||
Busy.Message = "Create backup of partition Data (" + i.ToString() + "/" + PartitionCount.ToString() + ")";
|
||||
Phone.BackupPartition("Data", DataPath, Updater);
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
}
|
||||
|
||||
Phone.CloseVolume();
|
||||
|
||||
if (!Result)
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel("Failed to create backup!", Exit));
|
||||
return;
|
||||
}
|
||||
|
||||
ActivateSubContext(new MessageViewModel("Successfully created a backup!", Exit));
|
||||
}).Start();
|
||||
}
|
||||
|
||||
internal void BackupArchiveTask(string ArchivePath)
|
||||
{
|
||||
IsSwitchingInterface = false;
|
||||
new Thread(() =>
|
||||
{
|
||||
bool Result = true;
|
||||
|
||||
ActivateSubContext(new BusyViewModel("Initializing backup..."));
|
||||
|
||||
ulong TotalSizeSectors = 0;
|
||||
const int PartitionCount = 3;
|
||||
|
||||
MassStorage Phone = (MassStorage)PhoneNotifier.CurrentModel;
|
||||
|
||||
try
|
||||
{
|
||||
Phone.OpenVolume(false);
|
||||
byte[] GPTBuffer = Phone.ReadSectors(1, 33);
|
||||
GPT GPT = new(GPTBuffer);
|
||||
|
||||
Partition Partition;
|
||||
|
||||
try
|
||||
{
|
||||
Partition = GPT.Partitions.First(p => p.Name == "EFIESP");
|
||||
TotalSizeSectors += Partition.SizeInSectors;
|
||||
|
||||
Partition = GPT.Partitions.First(p => p.Name == "MainOS");
|
||||
TotalSizeSectors += Partition.SizeInSectors;
|
||||
|
||||
Partition = GPT.Partitions.First(p => p.Name == "Data");
|
||||
TotalSizeSectors += Partition.SizeInSectors;
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
|
||||
BusyViewModel Busy = new("Create backup...", MaxProgressValue: TotalSizeSectors, UIContext: UIContext);
|
||||
ProgressUpdater Updater = Busy.ProgressUpdater;
|
||||
ActivateSubContext(Busy);
|
||||
ZipArchiveEntry Entry;
|
||||
Stream EntryStream = null;
|
||||
|
||||
using FileStream FileStream = new(ArchivePath, FileMode.Create);
|
||||
using ZipArchive Archive = new(FileStream, ZipArchiveMode.Create);
|
||||
int i = 0;
|
||||
|
||||
if (Result)
|
||||
{
|
||||
try
|
||||
{
|
||||
Entry = Archive.CreateEntry("EFIESP.bin", CompressionLevel.Optimal);
|
||||
EntryStream = Entry.Open();
|
||||
i++;
|
||||
Busy.Message = "Create backup of partition EFIESP (" + i.ToString() + "/" + PartitionCount.ToString() + ")";
|
||||
Phone.BackupPartition("EFIESP", EntryStream, Updater);
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
EntryStream?.Close();
|
||||
EntryStream = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (Result)
|
||||
{
|
||||
try
|
||||
{
|
||||
Entry = Archive.CreateEntry("MainOS.bin", CompressionLevel.Optimal);
|
||||
EntryStream = Entry.Open();
|
||||
i++;
|
||||
Busy.Message = "Create backup of partition MainOS (" + i.ToString() + "/" + PartitionCount.ToString() + ")";
|
||||
Phone.BackupPartition("MainOS", EntryStream, Updater);
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
EntryStream?.Close();
|
||||
EntryStream = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (Result)
|
||||
{
|
||||
try
|
||||
{
|
||||
Entry = Archive.CreateEntry("Data.bin", CompressionLevel.Optimal);
|
||||
EntryStream = Entry.Open();
|
||||
i++;
|
||||
Busy.Message = "Create backup of partition Data (" + i.ToString() + "/" + PartitionCount.ToString() + ")";
|
||||
Phone.BackupPartition("Data", EntryStream, Updater);
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
EntryStream?.Close();
|
||||
EntryStream = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
finally
|
||||
{
|
||||
Phone.CloseVolume();
|
||||
}
|
||||
|
||||
if (!Result)
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel("Failed to create backup!", Exit));
|
||||
return;
|
||||
}
|
||||
|
||||
ActivateSubContext(new MessageViewModel("Successfully created a backup!", Exit));
|
||||
}).Start();
|
||||
}
|
||||
|
||||
private readonly static string[] ProvisioningPartitions = new string[]
|
||||
{
|
||||
"DPP",
|
||||
"MODEM_FSG",
|
||||
"MODEM_FS1",
|
||||
"MODEM_FS2",
|
||||
"MODEM_FSC",
|
||||
"DDR",
|
||||
"SEC",
|
||||
"APDP",
|
||||
"MSADP",
|
||||
"DPO",
|
||||
"SSD",
|
||||
"DBI",
|
||||
"UEFI_BS_NV",
|
||||
"UEFI_NV",
|
||||
"UEFI_RT_NV",
|
||||
"UEFI_RT_NV_RPMB",
|
||||
"BOOTMODE",
|
||||
"LIMITS"
|
||||
};
|
||||
|
||||
internal void BackupArchiveProvisioningTask(string ArchiveProvisioningPath)
|
||||
{
|
||||
IsSwitchingInterface = false;
|
||||
new Thread(() =>
|
||||
{
|
||||
bool Result = true;
|
||||
|
||||
ActivateSubContext(new BusyViewModel("Initializing backup..."));
|
||||
|
||||
ulong TotalSizeSectors = 0;
|
||||
int PartitionCount = 0;
|
||||
|
||||
MassStorage Phone = (MassStorage)PhoneNotifier.CurrentModel;
|
||||
|
||||
try
|
||||
{
|
||||
Phone.OpenVolume(false);
|
||||
byte[] GPTBuffer = Phone.ReadSectors(1, 33);
|
||||
GPT GPT = new(GPTBuffer);
|
||||
|
||||
Partition Partition;
|
||||
|
||||
try
|
||||
{
|
||||
foreach (string PartitionName in ProvisioningPartitions)
|
||||
{
|
||||
if (GPT.Partitions.Any(p => p.Name == PartitionName))
|
||||
{
|
||||
Partition = GPT.Partitions.First(p => p.Name == PartitionName);
|
||||
if (PartitionName == "UEFI_BS_NV" && GPT.Partitions.Any(p => p.Name == "BACKUP_BS_NV"))
|
||||
{
|
||||
Partition = GPT.Partitions.First(p => p.Name == "BACKUP_BS_NV");
|
||||
}
|
||||
|
||||
TotalSizeSectors += Partition.SizeInSectors;
|
||||
PartitionCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
|
||||
BusyViewModel Busy = new("Create backup...", MaxProgressValue: TotalSizeSectors, UIContext: UIContext);
|
||||
ProgressUpdater Updater = Busy.ProgressUpdater;
|
||||
ActivateSubContext(Busy);
|
||||
ZipArchiveEntry Entry;
|
||||
Stream EntryStream = null;
|
||||
|
||||
using FileStream FileStream = new(ArchiveProvisioningPath, FileMode.Create);
|
||||
using ZipArchive Archive = new(FileStream, ZipArchiveMode.Create);
|
||||
int i = 0;
|
||||
|
||||
foreach (string PartitionName in ProvisioningPartitions)
|
||||
{
|
||||
if (GPT.Partitions.Any(p => p.Name == PartitionName) && Result)
|
||||
{
|
||||
try
|
||||
{
|
||||
Entry = Archive.CreateEntry(PartitionName + ".bin", CompressionLevel.Optimal);
|
||||
EntryStream = Entry.Open();
|
||||
i++;
|
||||
Busy.Message = "Create backup of partition " + PartitionName + " (" + i.ToString() + "/" + PartitionCount.ToString() + ")";
|
||||
if (PartitionName == "UEFI_BS_NV" && GPT.Partitions.Any(p => p.Name == "BACKUP_BS_NV"))
|
||||
{
|
||||
Phone.BackupPartition("BACKUP_BS_NV", EntryStream, Updater);
|
||||
}
|
||||
else
|
||||
{
|
||||
Phone.BackupPartition(PartitionName, EntryStream, Updater);
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
EntryStream?.Close();
|
||||
EntryStream = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
finally
|
||||
{
|
||||
Phone.CloseVolume();
|
||||
}
|
||||
|
||||
if (!Result)
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel("Failed to create backup!", Exit));
|
||||
return;
|
||||
}
|
||||
|
||||
ActivateSubContext(new MessageViewModel("Successfully created a backup!", Exit));
|
||||
}).Start();
|
||||
}
|
||||
|
||||
private void Exit()
|
||||
{
|
||||
IsSwitchingInterface = false;
|
||||
ActivateSubContext(null);
|
||||
Callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,217 +1,217 @@
|
||||
// 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 BusyViewModel : ContextViewModel
|
||||
{
|
||||
private readonly ulong MaxProgressValue = 0;
|
||||
internal ProgressUpdater ProgressUpdater = null;
|
||||
|
||||
// UIContext can be passed to BusyViewModel, when it needs to update progress-controls and it is created on a worker-thread.
|
||||
internal BusyViewModel(string Message, string SubMessage = null, ulong? MaxProgressValue = null, SynchronizationContext UIContext = null, bool ShowAnimation = true, bool ShowRebootHelp = false)
|
||||
{
|
||||
LogFile.Log(Message);
|
||||
|
||||
this.UIContext = UIContext ?? SynchronizationContext.Current;
|
||||
|
||||
this.Message = Message;
|
||||
this.SubMessage = SubMessage;
|
||||
this.ShowAnimation = ShowAnimation;
|
||||
this.ShowRebootHelp = ShowRebootHelp;
|
||||
if (MaxProgressValue != null)
|
||||
{
|
||||
ProgressPercentage = 0;
|
||||
this.MaxProgressValue = (ulong)MaxProgressValue;
|
||||
ProgressUpdater = new ProgressUpdater((ulong)MaxProgressValue, (p, t) =>
|
||||
{
|
||||
if ((this.UIContext == null) || (this.UIContext == SynchronizationContext.Current))
|
||||
{
|
||||
ProgressPercentage = p;
|
||||
TimeRemaining = t;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.UIContext.Post((s) =>
|
||||
{
|
||||
ProgressPercentage = p;
|
||||
TimeRemaining = t;
|
||||
}, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetShowRebootHelp(bool Value)
|
||||
{
|
||||
ShowRebootHelp = Value;
|
||||
}
|
||||
|
||||
internal void SetProgress(ulong Value)
|
||||
{
|
||||
if (ProgressUpdater != null)
|
||||
{
|
||||
UIContext.Post((s) => ProgressUpdater.SetProgress(Value), null);
|
||||
}
|
||||
}
|
||||
|
||||
private string _Message = null;
|
||||
public string Message
|
||||
{
|
||||
get
|
||||
{
|
||||
return _Message;
|
||||
}
|
||||
set
|
||||
{
|
||||
_Message = value;
|
||||
OnPropertyChanged(nameof(Message));
|
||||
}
|
||||
}
|
||||
|
||||
private string _SubMessage = null;
|
||||
public string SubMessage
|
||||
{
|
||||
get
|
||||
{
|
||||
return _SubMessage;
|
||||
}
|
||||
set
|
||||
{
|
||||
_SubMessage = value;
|
||||
OnPropertyChanged(nameof(SubMessage));
|
||||
}
|
||||
}
|
||||
|
||||
private int? _ProgressPercentage = null;
|
||||
public int? ProgressPercentage
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ProgressPercentage;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_ProgressPercentage != value)
|
||||
{
|
||||
_ProgressPercentage = value;
|
||||
OnPropertyChanged(nameof(ProgressPercentage));
|
||||
OnPropertyChanged(nameof(ShowAnimation));
|
||||
UpdateProgressText();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private TimeSpan? _TimeRemaining = null;
|
||||
public TimeSpan? TimeRemaining
|
||||
{
|
||||
get
|
||||
{
|
||||
return _TimeRemaining;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_TimeRemaining != value)
|
||||
{
|
||||
_TimeRemaining = value;
|
||||
OnPropertyChanged(nameof(TimeRemaining));
|
||||
UpdateProgressText();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateProgressText()
|
||||
{
|
||||
string NewText = null;
|
||||
if (ProgressPercentage != null)
|
||||
{
|
||||
NewText = "Progress: " + ((int)ProgressPercentage).ToString() + "%";
|
||||
}
|
||||
if (TimeRemaining != null)
|
||||
{
|
||||
if (NewText == null)
|
||||
{
|
||||
NewText = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
NewText += " - ";
|
||||
}
|
||||
|
||||
NewText += "Estimated time remaining: " + ((TimeSpan)TimeRemaining).ToString(@"h\:mm\:ss");
|
||||
}
|
||||
ProgressText = NewText;
|
||||
}
|
||||
|
||||
private string _ProgressText = null;
|
||||
public string ProgressText
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ProgressText;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_ProgressText != value)
|
||||
{
|
||||
_ProgressText = value;
|
||||
OnPropertyChanged(nameof(ProgressText));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _ShowAnimation = true;
|
||||
public bool ShowAnimation
|
||||
{
|
||||
get
|
||||
{
|
||||
return (_ProgressPercentage == null) && _ShowAnimation;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_ShowAnimation != value)
|
||||
{
|
||||
_ShowAnimation = value;
|
||||
OnPropertyChanged(nameof(ShowAnimation));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _ShowRebootHelp = false;
|
||||
public bool ShowRebootHelp
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ShowRebootHelp;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_ShowRebootHelp != value)
|
||||
{
|
||||
_ShowRebootHelp = value;
|
||||
OnPropertyChanged(nameof(ShowRebootHelp));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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 BusyViewModel : ContextViewModel
|
||||
{
|
||||
private readonly ulong MaxProgressValue = 0;
|
||||
internal ProgressUpdater ProgressUpdater = null;
|
||||
|
||||
// UIContext can be passed to BusyViewModel, when it needs to update progress-controls and it is created on a worker-thread.
|
||||
internal BusyViewModel(string Message, string SubMessage = null, ulong? MaxProgressValue = null, SynchronizationContext UIContext = null, bool ShowAnimation = true, bool ShowRebootHelp = false)
|
||||
{
|
||||
LogFile.Log(Message);
|
||||
|
||||
this.UIContext = UIContext ?? SynchronizationContext.Current;
|
||||
|
||||
this.Message = Message;
|
||||
this.SubMessage = SubMessage;
|
||||
this.ShowAnimation = ShowAnimation;
|
||||
this.ShowRebootHelp = ShowRebootHelp;
|
||||
if (MaxProgressValue != null)
|
||||
{
|
||||
ProgressPercentage = 0;
|
||||
this.MaxProgressValue = (ulong)MaxProgressValue;
|
||||
ProgressUpdater = new ProgressUpdater((ulong)MaxProgressValue, (p, t) =>
|
||||
{
|
||||
if ((this.UIContext == null) || (this.UIContext == SynchronizationContext.Current))
|
||||
{
|
||||
ProgressPercentage = p;
|
||||
TimeRemaining = t;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.UIContext.Post((s) =>
|
||||
{
|
||||
ProgressPercentage = p;
|
||||
TimeRemaining = t;
|
||||
}, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetShowRebootHelp(bool Value)
|
||||
{
|
||||
ShowRebootHelp = Value;
|
||||
}
|
||||
|
||||
internal void SetProgress(ulong Value)
|
||||
{
|
||||
if (ProgressUpdater != null)
|
||||
{
|
||||
UIContext.Post((s) => ProgressUpdater.SetProgress(Value), null);
|
||||
}
|
||||
}
|
||||
|
||||
private string _Message = null;
|
||||
public string Message
|
||||
{
|
||||
get
|
||||
{
|
||||
return _Message;
|
||||
}
|
||||
set
|
||||
{
|
||||
_Message = value;
|
||||
OnPropertyChanged(nameof(Message));
|
||||
}
|
||||
}
|
||||
|
||||
private string _SubMessage = null;
|
||||
public string SubMessage
|
||||
{
|
||||
get
|
||||
{
|
||||
return _SubMessage;
|
||||
}
|
||||
set
|
||||
{
|
||||
_SubMessage = value;
|
||||
OnPropertyChanged(nameof(SubMessage));
|
||||
}
|
||||
}
|
||||
|
||||
private int? _ProgressPercentage = null;
|
||||
public int? ProgressPercentage
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ProgressPercentage;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_ProgressPercentage != value)
|
||||
{
|
||||
_ProgressPercentage = value;
|
||||
OnPropertyChanged(nameof(ProgressPercentage));
|
||||
OnPropertyChanged(nameof(ShowAnimation));
|
||||
UpdateProgressText();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private TimeSpan? _TimeRemaining = null;
|
||||
public TimeSpan? TimeRemaining
|
||||
{
|
||||
get
|
||||
{
|
||||
return _TimeRemaining;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_TimeRemaining != value)
|
||||
{
|
||||
_TimeRemaining = value;
|
||||
OnPropertyChanged(nameof(TimeRemaining));
|
||||
UpdateProgressText();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateProgressText()
|
||||
{
|
||||
string NewText = null;
|
||||
if (ProgressPercentage != null)
|
||||
{
|
||||
NewText = "Progress: " + ((int)ProgressPercentage).ToString() + "%";
|
||||
}
|
||||
if (TimeRemaining != null)
|
||||
{
|
||||
if (NewText == null)
|
||||
{
|
||||
NewText = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
NewText += " - ";
|
||||
}
|
||||
|
||||
NewText += "Estimated time remaining: " + ((TimeSpan)TimeRemaining).ToString(@"h\:mm\:ss");
|
||||
}
|
||||
ProgressText = NewText;
|
||||
}
|
||||
|
||||
private string _ProgressText = null;
|
||||
public string ProgressText
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ProgressText;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_ProgressText != value)
|
||||
{
|
||||
_ProgressText = value;
|
||||
OnPropertyChanged(nameof(ProgressText));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _ShowAnimation = true;
|
||||
public bool ShowAnimation
|
||||
{
|
||||
get
|
||||
{
|
||||
return (_ProgressPercentage == null) && _ShowAnimation;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_ShowAnimation != value)
|
||||
{
|
||||
_ShowAnimation = value;
|
||||
OnPropertyChanged(nameof(ShowAnimation));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _ShowRebootHelp = false;
|
||||
public bool ShowRebootHelp
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ShowRebootHelp;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_ShowRebootHelp != value)
|
||||
{
|
||||
_ShowRebootHelp = value;
|
||||
OnPropertyChanged(nameof(ShowRebootHelp));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,157 +1,157 @@
|
||||
// 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.ComponentModel;
|
||||
using System.Threading;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class ContextViewModel : INotifyPropertyChanged
|
||||
{
|
||||
protected SynchronizationContext UIContext;
|
||||
|
||||
public bool IsSwitchingInterface = false;
|
||||
public bool IsFlashModeOperation = false;
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged = delegate { };
|
||||
|
||||
protected void OnPropertyChanged(string propertyName)
|
||||
{
|
||||
if ((UIContext == null) && (SynchronizationContext.Current != null))
|
||||
{
|
||||
UIContext = SynchronizationContext.Current;
|
||||
}
|
||||
|
||||
if (this.PropertyChanged != null)
|
||||
{
|
||||
if (SynchronizationContext.Current == UIContext)
|
||||
{
|
||||
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
else
|
||||
{
|
||||
UIContext.Post((s) => PropertyChanged(this, new PropertyChangedEventArgs(propertyName)), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ContextViewModel _SubContextViewModel;
|
||||
public ContextViewModel SubContextViewModel
|
||||
{
|
||||
get
|
||||
{
|
||||
return _SubContextViewModel;
|
||||
}
|
||||
private set
|
||||
{
|
||||
if (_SubContextViewModel != null)
|
||||
{
|
||||
_SubContextViewModel.IsActive = false;
|
||||
}
|
||||
|
||||
_SubContextViewModel = value;
|
||||
if (_SubContextViewModel != null)
|
||||
{
|
||||
_SubContextViewModel.IsActive = IsActive;
|
||||
}
|
||||
|
||||
OnPropertyChanged(nameof(SubContextViewModel));
|
||||
}
|
||||
}
|
||||
|
||||
internal ContextViewModel()
|
||||
{
|
||||
UIContext = SynchronizationContext.Current;
|
||||
}
|
||||
|
||||
internal ContextViewModel(MainViewModel Main) : this()
|
||||
{
|
||||
}
|
||||
|
||||
internal ContextViewModel(MainViewModel Main, ContextViewModel SubContext) : this(Main)
|
||||
{
|
||||
SubContextViewModel = SubContext;
|
||||
}
|
||||
|
||||
internal bool IsActive { get; set; } = false;
|
||||
|
||||
internal virtual void EvaluateViewState()
|
||||
{
|
||||
}
|
||||
|
||||
internal void Activate()
|
||||
{
|
||||
IsActive = true;
|
||||
EvaluateViewState();
|
||||
SubContextViewModel?.Activate();
|
||||
}
|
||||
|
||||
internal void ActivateSubContext(ContextViewModel NewSubContext)
|
||||
{
|
||||
if (_SubContextViewModel != null)
|
||||
{
|
||||
_SubContextViewModel.IsActive = false;
|
||||
}
|
||||
|
||||
if (NewSubContext != null)
|
||||
{
|
||||
if (IsActive)
|
||||
{
|
||||
NewSubContext.Activate();
|
||||
}
|
||||
else
|
||||
{
|
||||
NewSubContext.IsActive = false;
|
||||
}
|
||||
}
|
||||
SubContextViewModel = NewSubContext;
|
||||
}
|
||||
|
||||
internal void SetWorkingStatus(string Message, string SubMessage, ulong? MaxProgressValue, bool ShowAnimation = true, WPinternalsStatus Status = WPinternalsStatus.Undefined)
|
||||
{
|
||||
ActivateSubContext(new BusyViewModel(Message, SubMessage, MaxProgressValue, UIContext: UIContext, ShowAnimation: ShowAnimation, ShowRebootHelp: Status == WPinternalsStatus.WaitingForManualReset));
|
||||
}
|
||||
|
||||
internal void UpdateWorkingStatus(string Message, string SubMessage, ulong? CurrentProgressValue, WPinternalsStatus Status = WPinternalsStatus.Undefined)
|
||||
{
|
||||
if (SubContextViewModel is BusyViewModel Busy)
|
||||
{
|
||||
if (Message != null)
|
||||
{
|
||||
Busy.Message = Message;
|
||||
Busy.SubMessage = SubMessage;
|
||||
}
|
||||
if ((CurrentProgressValue != null) && (Busy.ProgressUpdater != null))
|
||||
{
|
||||
try
|
||||
{
|
||||
Busy.ProgressUpdater.SetProgress((ulong)CurrentProgressValue);
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
}
|
||||
}
|
||||
Busy.SetShowRebootHelp(Status == WPinternalsStatus.WaitingForManualReset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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.ComponentModel;
|
||||
using System.Threading;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class ContextViewModel : INotifyPropertyChanged
|
||||
{
|
||||
protected SynchronizationContext UIContext;
|
||||
|
||||
public bool IsSwitchingInterface = false;
|
||||
public bool IsFlashModeOperation = false;
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged = delegate { };
|
||||
|
||||
protected void OnPropertyChanged(string propertyName)
|
||||
{
|
||||
if ((UIContext == null) && (SynchronizationContext.Current != null))
|
||||
{
|
||||
UIContext = SynchronizationContext.Current;
|
||||
}
|
||||
|
||||
if (this.PropertyChanged != null)
|
||||
{
|
||||
if (SynchronizationContext.Current == UIContext)
|
||||
{
|
||||
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
else
|
||||
{
|
||||
UIContext.Post((s) => PropertyChanged(this, new PropertyChangedEventArgs(propertyName)), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ContextViewModel _SubContextViewModel;
|
||||
public ContextViewModel SubContextViewModel
|
||||
{
|
||||
get
|
||||
{
|
||||
return _SubContextViewModel;
|
||||
}
|
||||
private set
|
||||
{
|
||||
if (_SubContextViewModel != null)
|
||||
{
|
||||
_SubContextViewModel.IsActive = false;
|
||||
}
|
||||
|
||||
_SubContextViewModel = value;
|
||||
if (_SubContextViewModel != null)
|
||||
{
|
||||
_SubContextViewModel.IsActive = IsActive;
|
||||
}
|
||||
|
||||
OnPropertyChanged(nameof(SubContextViewModel));
|
||||
}
|
||||
}
|
||||
|
||||
internal ContextViewModel()
|
||||
{
|
||||
UIContext = SynchronizationContext.Current;
|
||||
}
|
||||
|
||||
internal ContextViewModel(MainViewModel Main) : this()
|
||||
{
|
||||
}
|
||||
|
||||
internal ContextViewModel(MainViewModel Main, ContextViewModel SubContext) : this(Main)
|
||||
{
|
||||
SubContextViewModel = SubContext;
|
||||
}
|
||||
|
||||
internal bool IsActive { get; set; } = false;
|
||||
|
||||
internal virtual void EvaluateViewState()
|
||||
{
|
||||
}
|
||||
|
||||
internal void Activate()
|
||||
{
|
||||
IsActive = true;
|
||||
EvaluateViewState();
|
||||
SubContextViewModel?.Activate();
|
||||
}
|
||||
|
||||
internal void ActivateSubContext(ContextViewModel NewSubContext)
|
||||
{
|
||||
if (_SubContextViewModel != null)
|
||||
{
|
||||
_SubContextViewModel.IsActive = false;
|
||||
}
|
||||
|
||||
if (NewSubContext != null)
|
||||
{
|
||||
if (IsActive)
|
||||
{
|
||||
NewSubContext.Activate();
|
||||
}
|
||||
else
|
||||
{
|
||||
NewSubContext.IsActive = false;
|
||||
}
|
||||
}
|
||||
SubContextViewModel = NewSubContext;
|
||||
}
|
||||
|
||||
internal void SetWorkingStatus(string Message, string SubMessage, ulong? MaxProgressValue, bool ShowAnimation = true, WPinternalsStatus Status = WPinternalsStatus.Undefined)
|
||||
{
|
||||
ActivateSubContext(new BusyViewModel(Message, SubMessage, MaxProgressValue, UIContext: UIContext, ShowAnimation: ShowAnimation, ShowRebootHelp: Status == WPinternalsStatus.WaitingForManualReset));
|
||||
}
|
||||
|
||||
internal void UpdateWorkingStatus(string Message, string SubMessage, ulong? CurrentProgressValue, WPinternalsStatus Status = WPinternalsStatus.Undefined)
|
||||
{
|
||||
if (SubContextViewModel is BusyViewModel Busy)
|
||||
{
|
||||
if (Message != null)
|
||||
{
|
||||
Busy.Message = Message;
|
||||
Busy.SubMessage = SubMessage;
|
||||
}
|
||||
if ((CurrentProgressValue != null) && (Busy.ProgressUpdater != null))
|
||||
{
|
||||
try
|
||||
{
|
||||
Busy.ProgressUpdater.SetProgress((ulong)CurrentProgressValue);
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
}
|
||||
}
|
||||
Busy.SetShowRebootHelp(Status == WPinternalsStatus.WaitingForManualReset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+60
-60
@@ -1,60 +1,60 @@
|
||||
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Windows;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class DisclaimerAndNdaViewModel : ContextViewModel
|
||||
{
|
||||
private readonly Action Accepted;
|
||||
|
||||
internal DisclaimerAndNdaViewModel(Action Accepted)
|
||||
: base()
|
||||
{
|
||||
this.Accepted = Accepted;
|
||||
}
|
||||
|
||||
private DelegateCommand _ExitCommand = null;
|
||||
public DelegateCommand ExitCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ExitCommand ??= new DelegateCommand(() => Application.Current.Shutdown());
|
||||
}
|
||||
}
|
||||
|
||||
private DelegateCommand _ContinueCommand = null;
|
||||
public DelegateCommand ContinueCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ContinueCommand ??= new DelegateCommand(() =>
|
||||
{
|
||||
Registry.CurrentUser.OpenSubKey("Software\\WPInternals", true).SetValue("DisclaimerAccepted", 1, RegistryValueKind.DWord);
|
||||
Registry.CurrentUser.OpenSubKey("Software\\WPInternals", true).SetValue("NdaAccepted", 1, RegistryValueKind.DWord);
|
||||
Accepted();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
using System;
|
||||
using System.Windows;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class DisclaimerAndNdaViewModel : ContextViewModel
|
||||
{
|
||||
private readonly Action Accepted;
|
||||
|
||||
internal DisclaimerAndNdaViewModel(Action Accepted)
|
||||
: base()
|
||||
{
|
||||
this.Accepted = Accepted;
|
||||
}
|
||||
|
||||
private DelegateCommand _ExitCommand = null;
|
||||
public DelegateCommand ExitCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ExitCommand ??= new DelegateCommand(() => Application.Current.Shutdown());
|
||||
}
|
||||
}
|
||||
|
||||
private DelegateCommand _ContinueCommand = null;
|
||||
public DelegateCommand ContinueCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ContinueCommand ??= new DelegateCommand(() =>
|
||||
{
|
||||
Registry.CurrentUser.OpenSubKey("Software\\WPInternals", true).SetValue("DisclaimerAccepted", 1, RegistryValueKind.DWord);
|
||||
Registry.CurrentUser.OpenSubKey("Software\\WPInternals", true).SetValue("NdaAccepted", 1, RegistryValueKind.DWord);
|
||||
Accepted();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +1,61 @@
|
||||
// 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;
|
||||
using System;
|
||||
using System.Windows;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal delegate void DisclaimerAcceptedHandler();
|
||||
|
||||
internal class DisclaimerViewModel : ContextViewModel
|
||||
{
|
||||
private readonly Action Accepted;
|
||||
|
||||
internal DisclaimerViewModel(Action Accepted)
|
||||
: base()
|
||||
{
|
||||
this.Accepted = Accepted;
|
||||
}
|
||||
|
||||
private DelegateCommand _ExitCommand = null;
|
||||
public DelegateCommand ExitCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ExitCommand ??= new DelegateCommand(() => Application.Current.Shutdown());
|
||||
}
|
||||
}
|
||||
|
||||
private DelegateCommand _ContinueCommand = null;
|
||||
public DelegateCommand ContinueCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ContinueCommand ??= new DelegateCommand(() =>
|
||||
{
|
||||
Registry.CurrentUser.OpenSubKey("Software\\WPInternals", true).SetValue("DisclaimerAccepted", 1, RegistryValueKind.DWord);
|
||||
Accepted();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
using System;
|
||||
using System.Windows;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal delegate void DisclaimerAcceptedHandler();
|
||||
|
||||
internal class DisclaimerViewModel : ContextViewModel
|
||||
{
|
||||
private readonly Action Accepted;
|
||||
|
||||
internal DisclaimerViewModel(Action Accepted)
|
||||
: base()
|
||||
{
|
||||
this.Accepted = Accepted;
|
||||
}
|
||||
|
||||
private DelegateCommand _ExitCommand = null;
|
||||
public DelegateCommand ExitCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ExitCommand ??= new DelegateCommand(() => Application.Current.Shutdown());
|
||||
}
|
||||
}
|
||||
|
||||
private DelegateCommand _ContinueCommand = null;
|
||||
public DelegateCommand ContinueCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ContinueCommand ??= new DelegateCommand(() =>
|
||||
{
|
||||
Registry.CurrentUser.OpenSubKey("Software\\WPInternals", true).SetValue("DisclaimerAccepted", 1, RegistryValueKind.DWord);
|
||||
Accepted();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
+228
-228
@@ -1,228 +1,228 @@
|
||||
// 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 DumpRomTargetSelectionViewModel : ContextViewModel
|
||||
{
|
||||
private readonly Action<string, string, bool, string, bool, string, bool> DumpCallback;
|
||||
internal Action SwitchToUnlockBoot;
|
||||
internal Action SwitchToUnlockRoot;
|
||||
internal Action SwitchToFlashRom;
|
||||
|
||||
internal DumpRomTargetSelectionViewModel(Action SwitchToUnlockBoot, Action SwitchToUnlockRoot, Action SwitchToFlashRom, Action<string, string, bool, string, bool, string, bool> DumpCallback)
|
||||
: base()
|
||||
{
|
||||
this.SwitchToUnlockBoot = SwitchToUnlockBoot;
|
||||
this.SwitchToUnlockRoot = SwitchToUnlockRoot;
|
||||
this.SwitchToFlashRom = SwitchToFlashRom;
|
||||
this.DumpCallback = DumpCallback;
|
||||
|
||||
new Thread(() => EvaluateViewState()).Start();
|
||||
}
|
||||
|
||||
private string _FFUPath;
|
||||
public string FFUPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _FFUPath;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _FFUPath)
|
||||
{
|
||||
_FFUPath = value;
|
||||
OnPropertyChanged(nameof(FFUPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _EFIESPPath;
|
||||
public string EFIESPPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _EFIESPPath;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _EFIESPPath)
|
||||
{
|
||||
_EFIESPPath = value;
|
||||
OnPropertyChanged(nameof(EFIESPPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _CompressEFIESP;
|
||||
public bool CompressEFIESP
|
||||
{
|
||||
get
|
||||
{
|
||||
return _CompressEFIESP;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _CompressEFIESP)
|
||||
{
|
||||
_CompressEFIESP = value;
|
||||
OnPropertyChanged(nameof(CompressEFIESP));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _MainOSPath;
|
||||
public string MainOSPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _MainOSPath;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _MainOSPath)
|
||||
{
|
||||
_MainOSPath = value;
|
||||
OnPropertyChanged(nameof(MainOSPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _CompressMainOS;
|
||||
public bool CompressMainOS
|
||||
{
|
||||
get
|
||||
{
|
||||
return _CompressMainOS;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _CompressMainOS)
|
||||
{
|
||||
_CompressMainOS = value;
|
||||
OnPropertyChanged(nameof(CompressMainOS));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _DataPath;
|
||||
public string DataPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _DataPath;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _DataPath)
|
||||
{
|
||||
_DataPath = value;
|
||||
OnPropertyChanged(nameof(DataPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _CompressData = true;
|
||||
public bool CompressData
|
||||
{
|
||||
get
|
||||
{
|
||||
return _CompressData;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _CompressData)
|
||||
{
|
||||
_CompressData = value;
|
||||
OnPropertyChanged(nameof(CompressData));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 _DumpCommand;
|
||||
public DelegateCommand DumpCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _DumpCommand ??= new DelegateCommand(() => DumpCallback(FFUPath, EFIESPPath, CompressEFIESP, MainOSPath, CompressMainOS, DataPath, CompressData), () => (FFUPath != null) && ((EFIESPPath != null) || (MainOSPath != null) || (DataPath != null)));
|
||||
}
|
||||
}
|
||||
|
||||
internal override void EvaluateViewState()
|
||||
{
|
||||
DumpCommand.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 DumpRomTargetSelectionViewModel : ContextViewModel
|
||||
{
|
||||
private readonly Action<string, string, bool, string, bool, string, bool> DumpCallback;
|
||||
internal Action SwitchToUnlockBoot;
|
||||
internal Action SwitchToUnlockRoot;
|
||||
internal Action SwitchToFlashRom;
|
||||
|
||||
internal DumpRomTargetSelectionViewModel(Action SwitchToUnlockBoot, Action SwitchToUnlockRoot, Action SwitchToFlashRom, Action<string, string, bool, string, bool, string, bool> DumpCallback)
|
||||
: base()
|
||||
{
|
||||
this.SwitchToUnlockBoot = SwitchToUnlockBoot;
|
||||
this.SwitchToUnlockRoot = SwitchToUnlockRoot;
|
||||
this.SwitchToFlashRom = SwitchToFlashRom;
|
||||
this.DumpCallback = DumpCallback;
|
||||
|
||||
new Thread(() => EvaluateViewState()).Start();
|
||||
}
|
||||
|
||||
private string _FFUPath;
|
||||
public string FFUPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _FFUPath;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _FFUPath)
|
||||
{
|
||||
_FFUPath = value;
|
||||
OnPropertyChanged(nameof(FFUPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _EFIESPPath;
|
||||
public string EFIESPPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _EFIESPPath;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _EFIESPPath)
|
||||
{
|
||||
_EFIESPPath = value;
|
||||
OnPropertyChanged(nameof(EFIESPPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _CompressEFIESP;
|
||||
public bool CompressEFIESP
|
||||
{
|
||||
get
|
||||
{
|
||||
return _CompressEFIESP;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _CompressEFIESP)
|
||||
{
|
||||
_CompressEFIESP = value;
|
||||
OnPropertyChanged(nameof(CompressEFIESP));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _MainOSPath;
|
||||
public string MainOSPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _MainOSPath;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _MainOSPath)
|
||||
{
|
||||
_MainOSPath = value;
|
||||
OnPropertyChanged(nameof(MainOSPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _CompressMainOS;
|
||||
public bool CompressMainOS
|
||||
{
|
||||
get
|
||||
{
|
||||
return _CompressMainOS;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _CompressMainOS)
|
||||
{
|
||||
_CompressMainOS = value;
|
||||
OnPropertyChanged(nameof(CompressMainOS));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _DataPath;
|
||||
public string DataPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _DataPath;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _DataPath)
|
||||
{
|
||||
_DataPath = value;
|
||||
OnPropertyChanged(nameof(DataPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _CompressData = true;
|
||||
public bool CompressData
|
||||
{
|
||||
get
|
||||
{
|
||||
return _CompressData;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _CompressData)
|
||||
{
|
||||
_CompressData = value;
|
||||
OnPropertyChanged(nameof(CompressData));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 _DumpCommand;
|
||||
public DelegateCommand DumpCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _DumpCommand ??= new DelegateCommand(() => DumpCallback(FFUPath, EFIESPPath, CompressEFIESP, MainOSPath, CompressMainOS, DataPath, CompressData), () => (FFUPath != null) && ((EFIESPPath != null) || (MainOSPath != null) || (DataPath != null)));
|
||||
}
|
||||
}
|
||||
|
||||
internal override void EvaluateViewState()
|
||||
{
|
||||
DumpCommand.RaiseCanExecuteChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,173 +1,173 @@
|
||||
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class DumpRomViewModel : ContextViewModel
|
||||
{
|
||||
private readonly Action SwitchToUnlockBoot;
|
||||
private readonly Action SwitchToUnlockRoot;
|
||||
private readonly Action SwitchToFlashRom;
|
||||
|
||||
internal DumpRomViewModel(Action SwitchToUnlockBoot, Action SwitchToUnlockRoot, Action SwitchToFlashRom)
|
||||
: base()
|
||||
{
|
||||
this.SwitchToUnlockBoot = SwitchToUnlockBoot;
|
||||
this.SwitchToUnlockRoot = SwitchToUnlockRoot;
|
||||
this.SwitchToFlashRom = SwitchToFlashRom;
|
||||
}
|
||||
|
||||
internal override void EvaluateViewState()
|
||||
{
|
||||
if (!IsActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (SubContextViewModel == null)
|
||||
{
|
||||
ActivateSubContext(new DumpRomTargetSelectionViewModel(SwitchToUnlockBoot, SwitchToUnlockRoot, SwitchToFlashRom, DoDumpRom));
|
||||
}
|
||||
}
|
||||
|
||||
internal void DoDumpRom(string FFUPath, string EFIESPPath, bool CompressEFIESP, string MainOSPath, bool CompressMainOS, string DataPath, bool CompressData)
|
||||
{
|
||||
new Thread(() =>
|
||||
{
|
||||
bool Result = true;
|
||||
|
||||
ActivateSubContext(new BusyViewModel("Initializing ROM dump..."));
|
||||
|
||||
ulong TotalSizeSectors = 0;
|
||||
int PartitionCount = 0;
|
||||
Partition Partition;
|
||||
FFU FFU = null;
|
||||
try
|
||||
{
|
||||
FFU = new FFU(FFUPath);
|
||||
|
||||
if (EFIESPPath != null)
|
||||
{
|
||||
Partition = FFU.GPT.Partitions.First(p => p.Name == "EFIESP");
|
||||
TotalSizeSectors += Partition.SizeInSectors;
|
||||
PartitionCount++;
|
||||
}
|
||||
|
||||
if (MainOSPath != null)
|
||||
{
|
||||
Partition = FFU.GPT.Partitions.First(p => p.Name == "MainOS");
|
||||
TotalSizeSectors += Partition.SizeInSectors;
|
||||
PartitionCount++;
|
||||
}
|
||||
|
||||
if (DataPath != null)
|
||||
{
|
||||
Partition = FFU.GPT.Partitions.First(p => p.Name == "Data");
|
||||
TotalSizeSectors += Partition.SizeInSectors;
|
||||
PartitionCount++;
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
|
||||
// We are on a worker thread!
|
||||
// So we must pass the SynchronizationContext of the UI thread
|
||||
BusyViewModel Busy = new("Dumping ROM...", MaxProgressValue: TotalSizeSectors, UIContext: UIContext);
|
||||
ProgressUpdater Updater = Busy.ProgressUpdater;
|
||||
ActivateSubContext(Busy);
|
||||
|
||||
int i = 0;
|
||||
if (Result)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (EFIESPPath != null)
|
||||
{
|
||||
i++;
|
||||
Busy.Message = "Dumping partition EFIESP (" + i.ToString() + "/" + PartitionCount.ToString() + ")";
|
||||
FFU.WritePartition("EFIESP", EFIESPPath, Updater, CompressEFIESP);
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (Result)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (MainOSPath != null)
|
||||
{
|
||||
i++;
|
||||
Busy.Message = "Dumping partition MainOS (" + i.ToString() + "/" + PartitionCount.ToString() + ")";
|
||||
FFU.WritePartition("MainOS", MainOSPath, Updater, CompressMainOS);
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (Result)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (DataPath != null)
|
||||
{
|
||||
i++;
|
||||
Busy.Message = "Dumping partition Data (" + i.ToString() + "/" + PartitionCount.ToString() + ")";
|
||||
FFU.WritePartition("Data", DataPath, Updater, CompressData);
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Result)
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel("Failed to dump ROM partitions!", Restart));
|
||||
return;
|
||||
}
|
||||
|
||||
ActivateSubContext(new MessageViewModel("Successfully dumped ROM partitions!", Restart));
|
||||
}).Start();
|
||||
}
|
||||
|
||||
internal void Restart()
|
||||
{
|
||||
ActivateSubContext(new DumpRomTargetSelectionViewModel(SwitchToUnlockBoot, SwitchToUnlockRoot, SwitchToFlashRom, DoDumpRom));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class DumpRomViewModel : ContextViewModel
|
||||
{
|
||||
private readonly Action SwitchToUnlockBoot;
|
||||
private readonly Action SwitchToUnlockRoot;
|
||||
private readonly Action SwitchToFlashRom;
|
||||
|
||||
internal DumpRomViewModel(Action SwitchToUnlockBoot, Action SwitchToUnlockRoot, Action SwitchToFlashRom)
|
||||
: base()
|
||||
{
|
||||
this.SwitchToUnlockBoot = SwitchToUnlockBoot;
|
||||
this.SwitchToUnlockRoot = SwitchToUnlockRoot;
|
||||
this.SwitchToFlashRom = SwitchToFlashRom;
|
||||
}
|
||||
|
||||
internal override void EvaluateViewState()
|
||||
{
|
||||
if (!IsActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (SubContextViewModel == null)
|
||||
{
|
||||
ActivateSubContext(new DumpRomTargetSelectionViewModel(SwitchToUnlockBoot, SwitchToUnlockRoot, SwitchToFlashRom, DoDumpRom));
|
||||
}
|
||||
}
|
||||
|
||||
internal void DoDumpRom(string FFUPath, string EFIESPPath, bool CompressEFIESP, string MainOSPath, bool CompressMainOS, string DataPath, bool CompressData)
|
||||
{
|
||||
new Thread(() =>
|
||||
{
|
||||
bool Result = true;
|
||||
|
||||
ActivateSubContext(new BusyViewModel("Initializing ROM dump..."));
|
||||
|
||||
ulong TotalSizeSectors = 0;
|
||||
int PartitionCount = 0;
|
||||
Partition Partition;
|
||||
FFU FFU = null;
|
||||
try
|
||||
{
|
||||
FFU = new FFU(FFUPath);
|
||||
|
||||
if (EFIESPPath != null)
|
||||
{
|
||||
Partition = FFU.GPT.Partitions.First(p => p.Name == "EFIESP");
|
||||
TotalSizeSectors += Partition.SizeInSectors;
|
||||
PartitionCount++;
|
||||
}
|
||||
|
||||
if (MainOSPath != null)
|
||||
{
|
||||
Partition = FFU.GPT.Partitions.First(p => p.Name == "MainOS");
|
||||
TotalSizeSectors += Partition.SizeInSectors;
|
||||
PartitionCount++;
|
||||
}
|
||||
|
||||
if (DataPath != null)
|
||||
{
|
||||
Partition = FFU.GPT.Partitions.First(p => p.Name == "Data");
|
||||
TotalSizeSectors += Partition.SizeInSectors;
|
||||
PartitionCount++;
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
|
||||
// We are on a worker thread!
|
||||
// So we must pass the SynchronizationContext of the UI thread
|
||||
BusyViewModel Busy = new("Dumping ROM...", MaxProgressValue: TotalSizeSectors, UIContext: UIContext);
|
||||
ProgressUpdater Updater = Busy.ProgressUpdater;
|
||||
ActivateSubContext(Busy);
|
||||
|
||||
int i = 0;
|
||||
if (Result)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (EFIESPPath != null)
|
||||
{
|
||||
i++;
|
||||
Busy.Message = "Dumping partition EFIESP (" + i.ToString() + "/" + PartitionCount.ToString() + ")";
|
||||
FFU.WritePartition("EFIESP", EFIESPPath, Updater, CompressEFIESP);
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (Result)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (MainOSPath != null)
|
||||
{
|
||||
i++;
|
||||
Busy.Message = "Dumping partition MainOS (" + i.ToString() + "/" + PartitionCount.ToString() + ")";
|
||||
FFU.WritePartition("MainOS", MainOSPath, Updater, CompressMainOS);
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (Result)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (DataPath != null)
|
||||
{
|
||||
i++;
|
||||
Busy.Message = "Dumping partition Data (" + i.ToString() + "/" + PartitionCount.ToString() + ")";
|
||||
FFU.WritePartition("Data", DataPath, Updater, CompressData);
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Result)
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel("Failed to dump ROM partitions!", Restart));
|
||||
return;
|
||||
}
|
||||
|
||||
ActivateSubContext(new MessageViewModel("Successfully dumped ROM partitions!", Restart));
|
||||
}).Start();
|
||||
}
|
||||
|
||||
internal void Restart()
|
||||
{
|
||||
ActivateSubContext(new DumpRomTargetSelectionViewModel(SwitchToUnlockBoot, SwitchToUnlockRoot, SwitchToFlashRom, DoDumpRom));
|
||||
}
|
||||
}
|
||||
}
|
||||
+47
-47
@@ -1,47 +1,47 @@
|
||||
// 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 GettingStartedViewModel : ContextViewModel
|
||||
{
|
||||
internal Action ShowDisclaimer;
|
||||
internal Action SwitchToUnlockBoot;
|
||||
internal Action SwitchToUnlockRoot;
|
||||
internal Action SwitchToBackup;
|
||||
internal Action SwitchToDumpRom;
|
||||
internal Action SwitchToFlashRom;
|
||||
internal Action SwitchToDownload;
|
||||
|
||||
internal GettingStartedViewModel(Action ShowDisclaimer, Action SwitchToUnlockBoot, Action SwitchToUnlockRoot, Action SwitchToBackup, Action SwitchToDumpRom, Action SwitchToFlashRom, Action SwitchToDownload)
|
||||
: base()
|
||||
{
|
||||
this.ShowDisclaimer = ShowDisclaimer;
|
||||
this.SwitchToUnlockBoot = SwitchToUnlockBoot;
|
||||
this.SwitchToUnlockRoot = SwitchToUnlockRoot;
|
||||
this.SwitchToBackup = SwitchToBackup;
|
||||
this.SwitchToFlashRom = SwitchToFlashRom;
|
||||
this.SwitchToDumpRom = SwitchToDumpRom;
|
||||
this.SwitchToDownload = SwitchToDownload;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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 GettingStartedViewModel : ContextViewModel
|
||||
{
|
||||
internal Action ShowDisclaimer;
|
||||
internal Action SwitchToUnlockBoot;
|
||||
internal Action SwitchToUnlockRoot;
|
||||
internal Action SwitchToBackup;
|
||||
internal Action SwitchToDumpRom;
|
||||
internal Action SwitchToFlashRom;
|
||||
internal Action SwitchToDownload;
|
||||
|
||||
internal GettingStartedViewModel(Action ShowDisclaimer, Action SwitchToUnlockBoot, Action SwitchToUnlockRoot, Action SwitchToBackup, Action SwitchToDumpRom, Action SwitchToFlashRom, Action SwitchToDownload)
|
||||
: base()
|
||||
{
|
||||
this.ShowDisclaimer = ShowDisclaimer;
|
||||
this.SwitchToUnlockBoot = SwitchToUnlockBoot;
|
||||
this.SwitchToUnlockRoot = SwitchToUnlockRoot;
|
||||
this.SwitchToBackup = SwitchToBackup;
|
||||
this.SwitchToFlashRom = SwitchToFlashRom;
|
||||
this.SwitchToDumpRom = SwitchToDumpRom;
|
||||
this.SwitchToDownload = SwitchToDownload;
|
||||
}
|
||||
}
|
||||
}
|
||||
+279
-279
@@ -1,279 +1,279 @@
|
||||
// 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 LumiaFlashRomSourceSelectionViewModel : ContextViewModel
|
||||
{
|
||||
private readonly PhoneNotifierViewModel PhoneNotifier;
|
||||
private readonly Action<string, string, string> FlashPartitionsCallback;
|
||||
private readonly Action<string> FlashFFUCallback;
|
||||
private readonly Action<string> FlashMMOSCallback;
|
||||
private readonly Action<string> FlashArchiveCallback;
|
||||
internal Action SwitchToUnlockBoot;
|
||||
internal Action SwitchToUnlockRoot;
|
||||
internal Action SwitchToDumpFFU;
|
||||
internal Action SwitchToBackup;
|
||||
|
||||
internal LumiaFlashRomSourceSelectionViewModel(PhoneNotifierViewModel PhoneNotifier, Action SwitchToUnlockBoot, Action SwitchToUnlockRoot, Action SwitchToDumpFFU, Action SwitchToBackup, Action<string, string, string> FlashPartitionsCallback, Action<string> FlashArchiveCallback, Action<string> FlashFFUCallback, Action<string> FlashMMOSCallback)
|
||||
: base()
|
||||
{
|
||||
this.PhoneNotifier = PhoneNotifier;
|
||||
this.SwitchToUnlockBoot = SwitchToUnlockBoot;
|
||||
this.SwitchToUnlockRoot = SwitchToUnlockRoot;
|
||||
this.SwitchToDumpFFU = SwitchToDumpFFU;
|
||||
this.SwitchToBackup = SwitchToBackup;
|
||||
this.FlashPartitionsCallback = FlashPartitionsCallback;
|
||||
this.FlashArchiveCallback = FlashArchiveCallback;
|
||||
this.FlashFFUCallback = FlashFFUCallback;
|
||||
this.FlashMMOSCallback = FlashMMOSCallback;
|
||||
|
||||
this.PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
this.PhoneNotifier.DeviceRemoved += DeviceRemoved;
|
||||
|
||||
new Thread(() => EvaluateViewState()).Start();
|
||||
}
|
||||
|
||||
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 _ArchivePath;
|
||||
public string ArchivePath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ArchivePath;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _ArchivePath)
|
||||
{
|
||||
_ArchivePath = value;
|
||||
OnPropertyChanged(nameof(ArchivePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _FFUPath;
|
||||
public string FFUPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _FFUPath;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _FFUPath)
|
||||
{
|
||||
_FFUPath = value;
|
||||
OnPropertyChanged(nameof(FFUPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _MMOSPath;
|
||||
public string MMOSPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _MMOSPath;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _MMOSPath)
|
||||
{
|
||||
_MMOSPath = value;
|
||||
OnPropertyChanged(nameof(MMOSPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _IsPhoneDisconnected;
|
||||
public bool IsPhoneDisconnected
|
||||
{
|
||||
get
|
||||
{
|
||||
return _IsPhoneDisconnected;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _IsPhoneDisconnected)
|
||||
{
|
||||
_IsPhoneDisconnected = value;
|
||||
OnPropertyChanged(nameof(IsPhoneDisconnected));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _IsPhoneInFlashMode;
|
||||
public bool IsPhoneInFlashMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return _IsPhoneInFlashMode;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _IsPhoneInFlashMode)
|
||||
{
|
||||
_IsPhoneInFlashMode = value;
|
||||
OnPropertyChanged(nameof(IsPhoneInFlashMode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _IsPhoneInOtherMode;
|
||||
public bool IsPhoneInOtherMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return _IsPhoneInOtherMode;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _IsPhoneInOtherMode)
|
||||
{
|
||||
_IsPhoneInOtherMode = value;
|
||||
OnPropertyChanged(nameof(IsPhoneInOtherMode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DelegateCommand _FlashPartitionsCommand;
|
||||
public DelegateCommand FlashPartitionsCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _FlashPartitionsCommand ??= new DelegateCommand(() => FlashPartitionsCallback(EFIESPPath, MainOSPath, DataPath), () => ((EFIESPPath != null) || (MainOSPath != null) || (DataPath != null)) && (PhoneNotifier.CurrentInterface != null));
|
||||
}
|
||||
}
|
||||
|
||||
private DelegateCommand _FlashFFUCommand;
|
||||
public DelegateCommand FlashFFUCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _FlashFFUCommand ??= new DelegateCommand(() => FlashFFUCallback(FFUPath), () => (FFUPath != null) && (PhoneNotifier.CurrentInterface != null));
|
||||
}
|
||||
}
|
||||
|
||||
private DelegateCommand _FlashMMOSCommand;
|
||||
public DelegateCommand FlashMMOSCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _FlashMMOSCommand ??= new DelegateCommand(() => FlashMMOSCallback(MMOSPath), () => (MMOSPath != null) && (PhoneNotifier.CurrentInterface != null));
|
||||
}
|
||||
}
|
||||
|
||||
private DelegateCommand _FlashArchiveCommand;
|
||||
public DelegateCommand FlashArchiveCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _FlashArchiveCommand ??= new DelegateCommand(() => FlashArchiveCallback(ArchivePath), () => (ArchivePath != null) && (PhoneNotifier.CurrentInterface != null));
|
||||
}
|
||||
}
|
||||
|
||||
~LumiaFlashRomSourceSelectionViewModel()
|
||||
{
|
||||
PhoneNotifier.NewDeviceArrived -= NewDeviceArrived;
|
||||
}
|
||||
|
||||
private void NewDeviceArrived(ArrivalEventArgs Args)
|
||||
{
|
||||
new Thread(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
EvaluateViewState();
|
||||
}
|
||||
catch { }
|
||||
}).Start();
|
||||
}
|
||||
|
||||
private void DeviceRemoved()
|
||||
{
|
||||
new Thread(() => EvaluateViewState()).Start();
|
||||
}
|
||||
|
||||
internal override void EvaluateViewState()
|
||||
{
|
||||
IsPhoneDisconnected = PhoneNotifier.CurrentInterface == null;
|
||||
IsPhoneInFlashMode = PhoneNotifier.CurrentInterface == PhoneInterfaces.Lumia_Flash;
|
||||
IsPhoneInOtherMode = !IsPhoneDisconnected && !IsPhoneInFlashMode;
|
||||
FlashPartitionsCommand.RaiseCanExecuteChanged();
|
||||
FlashArchiveCommand.RaiseCanExecuteChanged();
|
||||
FlashFFUCommand.RaiseCanExecuteChanged();
|
||||
FlashMMOSCommand.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 LumiaFlashRomSourceSelectionViewModel : ContextViewModel
|
||||
{
|
||||
private readonly PhoneNotifierViewModel PhoneNotifier;
|
||||
private readonly Action<string, string, string> FlashPartitionsCallback;
|
||||
private readonly Action<string> FlashFFUCallback;
|
||||
private readonly Action<string> FlashMMOSCallback;
|
||||
private readonly Action<string> FlashArchiveCallback;
|
||||
internal Action SwitchToUnlockBoot;
|
||||
internal Action SwitchToUnlockRoot;
|
||||
internal Action SwitchToDumpFFU;
|
||||
internal Action SwitchToBackup;
|
||||
|
||||
internal LumiaFlashRomSourceSelectionViewModel(PhoneNotifierViewModel PhoneNotifier, Action SwitchToUnlockBoot, Action SwitchToUnlockRoot, Action SwitchToDumpFFU, Action SwitchToBackup, Action<string, string, string> FlashPartitionsCallback, Action<string> FlashArchiveCallback, Action<string> FlashFFUCallback, Action<string> FlashMMOSCallback)
|
||||
: base()
|
||||
{
|
||||
this.PhoneNotifier = PhoneNotifier;
|
||||
this.SwitchToUnlockBoot = SwitchToUnlockBoot;
|
||||
this.SwitchToUnlockRoot = SwitchToUnlockRoot;
|
||||
this.SwitchToDumpFFU = SwitchToDumpFFU;
|
||||
this.SwitchToBackup = SwitchToBackup;
|
||||
this.FlashPartitionsCallback = FlashPartitionsCallback;
|
||||
this.FlashArchiveCallback = FlashArchiveCallback;
|
||||
this.FlashFFUCallback = FlashFFUCallback;
|
||||
this.FlashMMOSCallback = FlashMMOSCallback;
|
||||
|
||||
this.PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
this.PhoneNotifier.DeviceRemoved += DeviceRemoved;
|
||||
|
||||
new Thread(() => EvaluateViewState()).Start();
|
||||
}
|
||||
|
||||
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 _ArchivePath;
|
||||
public string ArchivePath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ArchivePath;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _ArchivePath)
|
||||
{
|
||||
_ArchivePath = value;
|
||||
OnPropertyChanged(nameof(ArchivePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _FFUPath;
|
||||
public string FFUPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _FFUPath;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _FFUPath)
|
||||
{
|
||||
_FFUPath = value;
|
||||
OnPropertyChanged(nameof(FFUPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _MMOSPath;
|
||||
public string MMOSPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _MMOSPath;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _MMOSPath)
|
||||
{
|
||||
_MMOSPath = value;
|
||||
OnPropertyChanged(nameof(MMOSPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _IsPhoneDisconnected;
|
||||
public bool IsPhoneDisconnected
|
||||
{
|
||||
get
|
||||
{
|
||||
return _IsPhoneDisconnected;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _IsPhoneDisconnected)
|
||||
{
|
||||
_IsPhoneDisconnected = value;
|
||||
OnPropertyChanged(nameof(IsPhoneDisconnected));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _IsPhoneInFlashMode;
|
||||
public bool IsPhoneInFlashMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return _IsPhoneInFlashMode;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _IsPhoneInFlashMode)
|
||||
{
|
||||
_IsPhoneInFlashMode = value;
|
||||
OnPropertyChanged(nameof(IsPhoneInFlashMode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _IsPhoneInOtherMode;
|
||||
public bool IsPhoneInOtherMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return _IsPhoneInOtherMode;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _IsPhoneInOtherMode)
|
||||
{
|
||||
_IsPhoneInOtherMode = value;
|
||||
OnPropertyChanged(nameof(IsPhoneInOtherMode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DelegateCommand _FlashPartitionsCommand;
|
||||
public DelegateCommand FlashPartitionsCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _FlashPartitionsCommand ??= new DelegateCommand(() => FlashPartitionsCallback(EFIESPPath, MainOSPath, DataPath), () => ((EFIESPPath != null) || (MainOSPath != null) || (DataPath != null)) && (PhoneNotifier.CurrentInterface != null));
|
||||
}
|
||||
}
|
||||
|
||||
private DelegateCommand _FlashFFUCommand;
|
||||
public DelegateCommand FlashFFUCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _FlashFFUCommand ??= new DelegateCommand(() => FlashFFUCallback(FFUPath), () => (FFUPath != null) && (PhoneNotifier.CurrentInterface != null));
|
||||
}
|
||||
}
|
||||
|
||||
private DelegateCommand _FlashMMOSCommand;
|
||||
public DelegateCommand FlashMMOSCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _FlashMMOSCommand ??= new DelegateCommand(() => FlashMMOSCallback(MMOSPath), () => (MMOSPath != null) && (PhoneNotifier.CurrentInterface != null));
|
||||
}
|
||||
}
|
||||
|
||||
private DelegateCommand _FlashArchiveCommand;
|
||||
public DelegateCommand FlashArchiveCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _FlashArchiveCommand ??= new DelegateCommand(() => FlashArchiveCallback(ArchivePath), () => (ArchivePath != null) && (PhoneNotifier.CurrentInterface != null));
|
||||
}
|
||||
}
|
||||
|
||||
~LumiaFlashRomSourceSelectionViewModel()
|
||||
{
|
||||
PhoneNotifier.NewDeviceArrived -= NewDeviceArrived;
|
||||
}
|
||||
|
||||
private void NewDeviceArrived(ArrivalEventArgs Args)
|
||||
{
|
||||
new Thread(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
EvaluateViewState();
|
||||
}
|
||||
catch { }
|
||||
}).Start();
|
||||
}
|
||||
|
||||
private void DeviceRemoved()
|
||||
{
|
||||
new Thread(() => EvaluateViewState()).Start();
|
||||
}
|
||||
|
||||
internal override void EvaluateViewState()
|
||||
{
|
||||
IsPhoneDisconnected = PhoneNotifier.CurrentInterface == null;
|
||||
IsPhoneInFlashMode = PhoneNotifier.CurrentInterface == PhoneInterfaces.Lumia_Flash;
|
||||
IsPhoneInOtherMode = !IsPhoneDisconnected && !IsPhoneInFlashMode;
|
||||
FlashPartitionsCommand.RaiseCanExecuteChanged();
|
||||
FlashArchiveCommand.RaiseCanExecuteChanged();
|
||||
FlashFFUCommand.RaiseCanExecuteChanged();
|
||||
FlashMMOSCommand.RaiseCanExecuteChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
+773
-773
File diff suppressed because it is too large
Load Diff
@@ -1,88 +1,88 @@
|
||||
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class LumiaInfoViewModel : ContextViewModel
|
||||
{
|
||||
internal PhoneInterfaces? CurrentInterface;
|
||||
internal IDisposable CurrentModel;
|
||||
internal PhoneNotifierViewModel PhoneNotifier;
|
||||
private readonly Action<PhoneInterfaces> ModeSwitchRequestCallback;
|
||||
private readonly Action SwitchToGettingStarted;
|
||||
|
||||
internal LumiaInfoViewModel(PhoneNotifierViewModel PhoneNotifier, Action<PhoneInterfaces> ModeSwitchRequestCallback, Action SwitchToGettingStarted)
|
||||
: base()
|
||||
{
|
||||
this.PhoneNotifier = PhoneNotifier;
|
||||
this.ModeSwitchRequestCallback = ModeSwitchRequestCallback;
|
||||
this.SwitchToGettingStarted = SwitchToGettingStarted;
|
||||
|
||||
CurrentInterface = PhoneNotifier.CurrentInterface;
|
||||
CurrentModel = PhoneNotifier.CurrentModel;
|
||||
|
||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
PhoneNotifier.DeviceRemoved += DeviceRemoved;
|
||||
}
|
||||
|
||||
~LumiaInfoViewModel()
|
||||
{
|
||||
PhoneNotifier.NewDeviceArrived -= NewDeviceArrived;
|
||||
PhoneNotifier.DeviceRemoved -= DeviceRemoved;
|
||||
}
|
||||
|
||||
private void DeviceRemoved()
|
||||
{
|
||||
CurrentInterface = null;
|
||||
CurrentModel = null;
|
||||
ActivateSubContext(null);
|
||||
}
|
||||
|
||||
private void NewDeviceArrived(ArrivalEventArgs Args)
|
||||
{
|
||||
CurrentInterface = Args.NewInterface;
|
||||
CurrentModel = Args.NewModel;
|
||||
|
||||
// Determine SubcontextViewModel
|
||||
switch (CurrentInterface)
|
||||
{
|
||||
case null:
|
||||
case PhoneInterfaces.Lumia_Bootloader:
|
||||
ActivateSubContext(null);
|
||||
//ActivateSubContext(new NokiaBootloaderViewModel((NokiaFlashModel)CurrentModel, ModeSwitchRequestCallback, SwitchToGettingStarted));
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Normal:
|
||||
ActivateSubContext(new NokiaNormalViewModel((NokiaPhoneModel)CurrentModel, ModeSwitchRequestCallback));
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Flash:
|
||||
ActivateSubContext(new NokiaFlashViewModel((NokiaFlashModel)CurrentModel, ModeSwitchRequestCallback, SwitchToGettingStarted));
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Label:
|
||||
ActivateSubContext(new NokiaLabelViewModel((NokiaPhoneModel)CurrentModel, ModeSwitchRequestCallback));
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_MassStorage:
|
||||
ActivateSubContext(new NokiaMassStorageViewModel((MassStorage)CurrentModel));
|
||||
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;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class LumiaInfoViewModel : ContextViewModel
|
||||
{
|
||||
internal PhoneInterfaces? CurrentInterface;
|
||||
internal IDisposable CurrentModel;
|
||||
internal PhoneNotifierViewModel PhoneNotifier;
|
||||
private readonly Action<PhoneInterfaces> ModeSwitchRequestCallback;
|
||||
private readonly Action SwitchToGettingStarted;
|
||||
|
||||
internal LumiaInfoViewModel(PhoneNotifierViewModel PhoneNotifier, Action<PhoneInterfaces> ModeSwitchRequestCallback, Action SwitchToGettingStarted)
|
||||
: base()
|
||||
{
|
||||
this.PhoneNotifier = PhoneNotifier;
|
||||
this.ModeSwitchRequestCallback = ModeSwitchRequestCallback;
|
||||
this.SwitchToGettingStarted = SwitchToGettingStarted;
|
||||
|
||||
CurrentInterface = PhoneNotifier.CurrentInterface;
|
||||
CurrentModel = PhoneNotifier.CurrentModel;
|
||||
|
||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
PhoneNotifier.DeviceRemoved += DeviceRemoved;
|
||||
}
|
||||
|
||||
~LumiaInfoViewModel()
|
||||
{
|
||||
PhoneNotifier.NewDeviceArrived -= NewDeviceArrived;
|
||||
PhoneNotifier.DeviceRemoved -= DeviceRemoved;
|
||||
}
|
||||
|
||||
private void DeviceRemoved()
|
||||
{
|
||||
CurrentInterface = null;
|
||||
CurrentModel = null;
|
||||
ActivateSubContext(null);
|
||||
}
|
||||
|
||||
private void NewDeviceArrived(ArrivalEventArgs Args)
|
||||
{
|
||||
CurrentInterface = Args.NewInterface;
|
||||
CurrentModel = Args.NewModel;
|
||||
|
||||
// Determine SubcontextViewModel
|
||||
switch (CurrentInterface)
|
||||
{
|
||||
case null:
|
||||
case PhoneInterfaces.Lumia_Bootloader:
|
||||
ActivateSubContext(null);
|
||||
//ActivateSubContext(new NokiaBootloaderViewModel((NokiaFlashModel)CurrentModel, ModeSwitchRequestCallback, SwitchToGettingStarted));
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Normal:
|
||||
ActivateSubContext(new NokiaNormalViewModel((NokiaPhoneModel)CurrentModel, ModeSwitchRequestCallback));
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Flash:
|
||||
ActivateSubContext(new NokiaFlashViewModel((NokiaFlashModel)CurrentModel, ModeSwitchRequestCallback, SwitchToGettingStarted));
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Label:
|
||||
ActivateSubContext(new NokiaLabelViewModel((NokiaPhoneModel)CurrentModel, ModeSwitchRequestCallback));
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_MassStorage:
|
||||
ActivateSubContext(new NokiaMassStorageViewModel((MassStorage)CurrentModel));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,132 +1,132 @@
|
||||
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class LumiaModeViewModel : ContextViewModel
|
||||
{
|
||||
internal PhoneInterfaces? CurrentInterface;
|
||||
internal IDisposable CurrentModel;
|
||||
internal PhoneNotifierViewModel PhoneNotifier;
|
||||
private readonly Action Callback;
|
||||
|
||||
internal LumiaModeViewModel(PhoneNotifierViewModel PhoneNotifier, Action Callback)
|
||||
: base()
|
||||
{
|
||||
this.PhoneNotifier = PhoneNotifier;
|
||||
this.Callback = Callback;
|
||||
|
||||
CurrentInterface = PhoneNotifier.CurrentInterface;
|
||||
CurrentModel = PhoneNotifier.CurrentModel;
|
||||
|
||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
PhoneNotifier.DeviceRemoved += DeviceRemoved;
|
||||
}
|
||||
|
||||
~LumiaModeViewModel()
|
||||
{
|
||||
PhoneNotifier.NewDeviceArrived -= NewDeviceArrived;
|
||||
PhoneNotifier.DeviceRemoved -= DeviceRemoved;
|
||||
}
|
||||
|
||||
private void DeviceRemoved()
|
||||
{
|
||||
CurrentInterface = null;
|
||||
CurrentModel = null;
|
||||
|
||||
if (!IsSwitchingInterface)
|
||||
{
|
||||
ActivateSubContext(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void NewDeviceArrived(ArrivalEventArgs Args)
|
||||
{
|
||||
CurrentInterface = Args.NewInterface;
|
||||
CurrentModel = Args.NewModel;
|
||||
|
||||
if (!IsSwitchingInterface && IsActive)
|
||||
{
|
||||
Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
internal override void EvaluateViewState()
|
||||
{
|
||||
if (!IsSwitchingInterface && IsActive)
|
||||
{
|
||||
Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
private void Refresh()
|
||||
{
|
||||
// Determine SubcontextViewModel
|
||||
switch (CurrentInterface)
|
||||
{
|
||||
case null:
|
||||
ActivateSubContext(null);
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Bootloader:
|
||||
ActivateSubContext(null);
|
||||
//ActivateSubContext(new NokiaModeBootloaderViewModel((NokiaFlashModel)CurrentModel, OnModeSwitchRequested));
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Normal:
|
||||
ActivateSubContext(new NokiaModeNormalViewModel((NokiaPhoneModel)CurrentModel, OnModeSwitchRequested));
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Flash:
|
||||
ActivateSubContext(new NokiaModeFlashViewModel((NokiaFlashModel)CurrentModel, OnModeSwitchRequested));
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Label:
|
||||
ActivateSubContext(new NokiaModeLabelViewModel((NokiaPhoneModel)CurrentModel, OnModeSwitchRequested));
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_MassStorage:
|
||||
ActivateSubContext(new NokiaModeMassStorageViewModel((MassStorage)CurrentModel, OnModeSwitchRequested));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Called from eventhandler, so "async void" is valid here.
|
||||
internal async void OnModeSwitchRequested(PhoneInterfaces? TargetInterface)
|
||||
{
|
||||
IsSwitchingInterface = true;
|
||||
|
||||
try
|
||||
{
|
||||
await SwitchModeViewModel.SwitchToWithStatus(PhoneNotifier, TargetInterface, SetWorkingStatus, UpdateWorkingStatus, null); // This is a manual switch. We don't care about which volume arrives.
|
||||
|
||||
IsSwitchingInterface = false;
|
||||
Callback();
|
||||
Refresh();
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
IsSwitchingInterface = false;
|
||||
ActivateSubContext(new MessageViewModel(Ex.Message, () =>
|
||||
{
|
||||
Callback();
|
||||
Refresh();
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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 LumiaModeViewModel : ContextViewModel
|
||||
{
|
||||
internal PhoneInterfaces? CurrentInterface;
|
||||
internal IDisposable CurrentModel;
|
||||
internal PhoneNotifierViewModel PhoneNotifier;
|
||||
private readonly Action Callback;
|
||||
|
||||
internal LumiaModeViewModel(PhoneNotifierViewModel PhoneNotifier, Action Callback)
|
||||
: base()
|
||||
{
|
||||
this.PhoneNotifier = PhoneNotifier;
|
||||
this.Callback = Callback;
|
||||
|
||||
CurrentInterface = PhoneNotifier.CurrentInterface;
|
||||
CurrentModel = PhoneNotifier.CurrentModel;
|
||||
|
||||
PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
PhoneNotifier.DeviceRemoved += DeviceRemoved;
|
||||
}
|
||||
|
||||
~LumiaModeViewModel()
|
||||
{
|
||||
PhoneNotifier.NewDeviceArrived -= NewDeviceArrived;
|
||||
PhoneNotifier.DeviceRemoved -= DeviceRemoved;
|
||||
}
|
||||
|
||||
private void DeviceRemoved()
|
||||
{
|
||||
CurrentInterface = null;
|
||||
CurrentModel = null;
|
||||
|
||||
if (!IsSwitchingInterface)
|
||||
{
|
||||
ActivateSubContext(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void NewDeviceArrived(ArrivalEventArgs Args)
|
||||
{
|
||||
CurrentInterface = Args.NewInterface;
|
||||
CurrentModel = Args.NewModel;
|
||||
|
||||
if (!IsSwitchingInterface && IsActive)
|
||||
{
|
||||
Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
internal override void EvaluateViewState()
|
||||
{
|
||||
if (!IsSwitchingInterface && IsActive)
|
||||
{
|
||||
Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
private void Refresh()
|
||||
{
|
||||
// Determine SubcontextViewModel
|
||||
switch (CurrentInterface)
|
||||
{
|
||||
case null:
|
||||
ActivateSubContext(null);
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Bootloader:
|
||||
ActivateSubContext(null);
|
||||
//ActivateSubContext(new NokiaModeBootloaderViewModel((NokiaFlashModel)CurrentModel, OnModeSwitchRequested));
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Normal:
|
||||
ActivateSubContext(new NokiaModeNormalViewModel((NokiaPhoneModel)CurrentModel, OnModeSwitchRequested));
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Flash:
|
||||
ActivateSubContext(new NokiaModeFlashViewModel((NokiaFlashModel)CurrentModel, OnModeSwitchRequested));
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_Label:
|
||||
ActivateSubContext(new NokiaModeLabelViewModel((NokiaPhoneModel)CurrentModel, OnModeSwitchRequested));
|
||||
break;
|
||||
case PhoneInterfaces.Lumia_MassStorage:
|
||||
ActivateSubContext(new NokiaModeMassStorageViewModel((MassStorage)CurrentModel, OnModeSwitchRequested));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Called from eventhandler, so "async void" is valid here.
|
||||
internal async void OnModeSwitchRequested(PhoneInterfaces? TargetInterface)
|
||||
{
|
||||
IsSwitchingInterface = true;
|
||||
|
||||
try
|
||||
{
|
||||
await SwitchModeViewModel.SwitchToWithStatus(PhoneNotifier, TargetInterface, SetWorkingStatus, UpdateWorkingStatus, null); // This is a manual switch. We don't care about which volume arrives.
|
||||
|
||||
IsSwitchingInterface = false;
|
||||
Callback();
|
||||
Refresh();
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
IsSwitchingInterface = false;
|
||||
ActivateSubContext(new MessageViewModel(Ex.Message, () =>
|
||||
{
|
||||
Callback();
|
||||
Refresh();
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1105
-1105
File diff suppressed because it is too large
Load Diff
+190
-190
@@ -1,190 +1,190 @@
|
||||
// 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 LumiaUnlockRootTargetSelectionViewModel : LumiaRootAccessTargetSelectionViewModel
|
||||
{
|
||||
public LumiaUnlockRootTargetSelectionViewModel(PhoneNotifierViewModel PhoneNotifier, Action SwitchToUnlockBoot, Action SwitchToDumpRom, Action SwitchToFlashRom, Action UnlockPhoneCallback, Action<string, string> UnlockImageCallback)
|
||||
: base(PhoneNotifier, SwitchToUnlockBoot, SwitchToDumpRom, SwitchToFlashRom, UnlockPhoneCallback, UnlockImageCallback) { }
|
||||
}
|
||||
|
||||
internal class LumiaUndoRootTargetSelectionViewModel : LumiaRootAccessTargetSelectionViewModel
|
||||
{
|
||||
public LumiaUndoRootTargetSelectionViewModel(PhoneNotifierViewModel PhoneNotifier, Action SwitchToUnlockBoot, Action SwitchToDumpRom, Action SwitchToFlashRom, Action UnlockPhoneCallback, Action<string, string> UnlockImageCallback)
|
||||
: base(PhoneNotifier, SwitchToUnlockBoot, SwitchToDumpRom, SwitchToFlashRom, UnlockPhoneCallback, UnlockImageCallback) { }
|
||||
}
|
||||
|
||||
internal class LumiaRootAccessTargetSelectionViewModel : ContextViewModel
|
||||
{
|
||||
private readonly PhoneNotifierViewModel PhoneNotifier;
|
||||
internal Action SwitchToUnlockBoot;
|
||||
internal Action SwitchToDumpRom;
|
||||
internal Action SwitchToFlashRom;
|
||||
private readonly Action UnlockPhoneCallback;
|
||||
private readonly Action<string, string> UnlockImageCallback;
|
||||
|
||||
internal LumiaRootAccessTargetSelectionViewModel(PhoneNotifierViewModel PhoneNotifier, Action SwitchToUnlockBoot, Action SwitchToDumpRom, Action SwitchToFlashRom, Action UnlockPhoneCallback, Action<string, string> UnlockImageCallback)
|
||||
: base()
|
||||
{
|
||||
this.PhoneNotifier = PhoneNotifier;
|
||||
this.SwitchToDumpRom = SwitchToDumpRom;
|
||||
this.SwitchToFlashRom = SwitchToFlashRom;
|
||||
this.SwitchToUnlockBoot = SwitchToUnlockBoot;
|
||||
this.UnlockPhoneCallback = UnlockPhoneCallback;
|
||||
this.UnlockImageCallback = UnlockImageCallback;
|
||||
|
||||
this.PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
this.PhoneNotifier.DeviceRemoved += DeviceRemoved;
|
||||
|
||||
new Thread(() => EvaluateViewState()).Start();
|
||||
}
|
||||
|
||||
private string _EFIESPMountPoint;
|
||||
public string EFIESPMountPoint
|
||||
{
|
||||
get
|
||||
{
|
||||
return _EFIESPMountPoint;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _EFIESPMountPoint)
|
||||
{
|
||||
_EFIESPMountPoint = value;
|
||||
OnPropertyChanged(nameof(EFIESPMountPoint));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _MainOSMountPoint;
|
||||
public string MainOSMountPoint
|
||||
{
|
||||
get
|
||||
{
|
||||
return _MainOSMountPoint;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _MainOSMountPoint)
|
||||
{
|
||||
_MainOSMountPoint = value;
|
||||
OnPropertyChanged(nameof(MainOSMountPoint));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 _UnlockPhoneCommand;
|
||||
public DelegateCommand UnlockPhoneCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _UnlockPhoneCommand ??= new DelegateCommand(() => UnlockPhoneCallback(), () => !IsPhoneDisconnected);
|
||||
}
|
||||
}
|
||||
|
||||
private DelegateCommand _UnlockImageCommand;
|
||||
public DelegateCommand UnlockImageCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _UnlockImageCommand ??= new DelegateCommand(() => UnlockImageCallback(EFIESPMountPoint, MainOSMountPoint), () => (EFIESPMountPoint != null) || (MainOSMountPoint != null));
|
||||
}
|
||||
}
|
||||
|
||||
~LumiaRootAccessTargetSelectionViewModel()
|
||||
{
|
||||
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;
|
||||
UnlockPhoneCommand.RaiseCanExecuteChanged();
|
||||
UnlockImageCommand.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 LumiaUnlockRootTargetSelectionViewModel : LumiaRootAccessTargetSelectionViewModel
|
||||
{
|
||||
public LumiaUnlockRootTargetSelectionViewModel(PhoneNotifierViewModel PhoneNotifier, Action SwitchToUnlockBoot, Action SwitchToDumpRom, Action SwitchToFlashRom, Action UnlockPhoneCallback, Action<string, string> UnlockImageCallback)
|
||||
: base(PhoneNotifier, SwitchToUnlockBoot, SwitchToDumpRom, SwitchToFlashRom, UnlockPhoneCallback, UnlockImageCallback) { }
|
||||
}
|
||||
|
||||
internal class LumiaUndoRootTargetSelectionViewModel : LumiaRootAccessTargetSelectionViewModel
|
||||
{
|
||||
public LumiaUndoRootTargetSelectionViewModel(PhoneNotifierViewModel PhoneNotifier, Action SwitchToUnlockBoot, Action SwitchToDumpRom, Action SwitchToFlashRom, Action UnlockPhoneCallback, Action<string, string> UnlockImageCallback)
|
||||
: base(PhoneNotifier, SwitchToUnlockBoot, SwitchToDumpRom, SwitchToFlashRom, UnlockPhoneCallback, UnlockImageCallback) { }
|
||||
}
|
||||
|
||||
internal class LumiaRootAccessTargetSelectionViewModel : ContextViewModel
|
||||
{
|
||||
private readonly PhoneNotifierViewModel PhoneNotifier;
|
||||
internal Action SwitchToUnlockBoot;
|
||||
internal Action SwitchToDumpRom;
|
||||
internal Action SwitchToFlashRom;
|
||||
private readonly Action UnlockPhoneCallback;
|
||||
private readonly Action<string, string> UnlockImageCallback;
|
||||
|
||||
internal LumiaRootAccessTargetSelectionViewModel(PhoneNotifierViewModel PhoneNotifier, Action SwitchToUnlockBoot, Action SwitchToDumpRom, Action SwitchToFlashRom, Action UnlockPhoneCallback, Action<string, string> UnlockImageCallback)
|
||||
: base()
|
||||
{
|
||||
this.PhoneNotifier = PhoneNotifier;
|
||||
this.SwitchToDumpRom = SwitchToDumpRom;
|
||||
this.SwitchToFlashRom = SwitchToFlashRom;
|
||||
this.SwitchToUnlockBoot = SwitchToUnlockBoot;
|
||||
this.UnlockPhoneCallback = UnlockPhoneCallback;
|
||||
this.UnlockImageCallback = UnlockImageCallback;
|
||||
|
||||
this.PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
this.PhoneNotifier.DeviceRemoved += DeviceRemoved;
|
||||
|
||||
new Thread(() => EvaluateViewState()).Start();
|
||||
}
|
||||
|
||||
private string _EFIESPMountPoint;
|
||||
public string EFIESPMountPoint
|
||||
{
|
||||
get
|
||||
{
|
||||
return _EFIESPMountPoint;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _EFIESPMountPoint)
|
||||
{
|
||||
_EFIESPMountPoint = value;
|
||||
OnPropertyChanged(nameof(EFIESPMountPoint));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _MainOSMountPoint;
|
||||
public string MainOSMountPoint
|
||||
{
|
||||
get
|
||||
{
|
||||
return _MainOSMountPoint;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _MainOSMountPoint)
|
||||
{
|
||||
_MainOSMountPoint = value;
|
||||
OnPropertyChanged(nameof(MainOSMountPoint));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 _UnlockPhoneCommand;
|
||||
public DelegateCommand UnlockPhoneCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _UnlockPhoneCommand ??= new DelegateCommand(() => UnlockPhoneCallback(), () => !IsPhoneDisconnected);
|
||||
}
|
||||
}
|
||||
|
||||
private DelegateCommand _UnlockImageCommand;
|
||||
public DelegateCommand UnlockImageCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _UnlockImageCommand ??= new DelegateCommand(() => UnlockImageCallback(EFIESPMountPoint, MainOSMountPoint), () => (EFIESPMountPoint != null) || (MainOSMountPoint != null));
|
||||
}
|
||||
}
|
||||
|
||||
~LumiaRootAccessTargetSelectionViewModel()
|
||||
{
|
||||
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;
|
||||
UnlockPhoneCommand.RaiseCanExecuteChanged();
|
||||
UnlockImageCommand.RaiseCanExecuteChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
+290
-290
@@ -1,290 +1,290 @@
|
||||
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class LumiaUnlockRootViewModel : ContextViewModel
|
||||
{
|
||||
private readonly PhoneNotifierViewModel PhoneNotifier;
|
||||
private readonly Action SwitchToUnlockBoot;
|
||||
private readonly Action SwitchToDumpRom;
|
||||
private readonly Action SwitchToFlashRom;
|
||||
private readonly Action Callback;
|
||||
private readonly bool DoUnlock;
|
||||
|
||||
internal LumiaUnlockRootViewModel(PhoneNotifierViewModel PhoneNotifier, Action SwitchToUnlockBoot, Action SwitchToDumpRom, Action SwitchToFlashRom, bool DoUnlock, Action Callback)
|
||||
: base()
|
||||
{
|
||||
IsSwitchingInterface = false;
|
||||
IsFlashModeOperation = true;
|
||||
|
||||
this.PhoneNotifier = PhoneNotifier;
|
||||
this.SwitchToDumpRom = SwitchToDumpRom;
|
||||
this.SwitchToFlashRom = SwitchToFlashRom;
|
||||
this.SwitchToUnlockBoot = SwitchToUnlockBoot;
|
||||
this.DoUnlock = DoUnlock;
|
||||
this.Callback = Callback;
|
||||
}
|
||||
|
||||
internal override void EvaluateViewState()
|
||||
{
|
||||
if (!IsActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (DoUnlock)
|
||||
{
|
||||
if ((SubContextViewModel == null) || (SubContextViewModel is LumiaUndoRootTargetSelectionViewModel))
|
||||
{
|
||||
ActivateSubContext(new LumiaUnlockRootTargetSelectionViewModel(PhoneNotifier, SwitchToUnlockBoot, SwitchToDumpRom, SwitchToFlashRom, DoUnlockPhone, DoUnlockImage));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((SubContextViewModel == null) || (SubContextViewModel is LumiaUnlockRootTargetSelectionViewModel))
|
||||
{
|
||||
ActivateSubContext(new LumiaUndoRootTargetSelectionViewModel(PhoneNotifier, SwitchToUnlockBoot, SwitchToDumpRom, SwitchToFlashRom, DoUnlockPhone, DoUnlockImage));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal async void DoUnlockPhone()
|
||||
{
|
||||
try
|
||||
{
|
||||
IsSwitchingInterface = true;
|
||||
await SwitchModeViewModel.SwitchToWithProgress(PhoneNotifier, PhoneInterfaces.Lumia_MassStorage,
|
||||
(msg, sub) =>
|
||||
ActivateSubContext(new BusyViewModel(msg, sub)));
|
||||
bool HasNewBootloader = HasNewBootloaderFromMassStorage();
|
||||
string EFIESPPath = HasNewBootloader ? null : ((MassStorage)PhoneNotifier.CurrentModel).Drive + @"\EFIESP\";
|
||||
string MainOSPath = ((MassStorage)PhoneNotifier.CurrentModel).Drive + @"\";
|
||||
|
||||
bool HasV11Patches = HasV11PatchesFromMassStorage();
|
||||
|
||||
StartPatch(EFIESPPath, MainOSPath, HasNewBootloader, HasV11Patches);
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel(Ex.Message, () =>
|
||||
{
|
||||
Callback();
|
||||
ActivateSubContext(null);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
internal void DoUnlockImage(string EFIESPMountPoint, string MainOSMountPoint)
|
||||
{
|
||||
StartPatch(EFIESPMountPoint, MainOSMountPoint, false, false); // Unlock image is only supported for Lumia's with bootloader Spec A. Due to complexity of Spec B bootloader hack, it cannot be applied on a mounted image.
|
||||
}
|
||||
|
||||
// Magic!
|
||||
// Apply patches for Root Access
|
||||
private void StartPatch(string EFIESP, string MainOS, bool HasNewBootloader, bool HasV11Patches)
|
||||
{
|
||||
IsSwitchingInterface = false;
|
||||
new Thread(() =>
|
||||
{
|
||||
if (DoUnlock)
|
||||
{
|
||||
LogFile.BeginAction("EnableRootAccess");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile.BeginAction("DisableRootAccess");
|
||||
}
|
||||
|
||||
bool Result = false;
|
||||
|
||||
if (EFIESP != null && !HasV11Patches)
|
||||
{
|
||||
if (DoUnlock)
|
||||
{
|
||||
ActivateSubContext(new BusyViewModel("Enable Root Access on EFIESP..."));
|
||||
}
|
||||
else
|
||||
{
|
||||
ActivateSubContext(new BusyViewModel("Disable Root Access on EFIESP..."));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
App.PatchEngine.TargetPath = EFIESP;
|
||||
if (DoUnlock)
|
||||
{
|
||||
Result = App.PatchEngine.Patch("SecureBootHack-V1-EFIESP");
|
||||
|
||||
if (!Result)
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel("Failed to enable Root Access on EFIESP! Check the OS version on the phone and verify the compatibility-list in the \"Getting started\" section.", Exit));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
App.PatchEngine.Restore("SecureBootHack-V1-EFIESP");
|
||||
Result = true;
|
||||
}
|
||||
}
|
||||
catch (UnauthorizedAccessException Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
ActivateSubContext(new MessageViewModel("Failed to enable Root Access on EFIESP! Not enough privileges to perform action. Try to logon to Windows with an administrator account.", Exit));
|
||||
return;
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
|
||||
if (!Result)
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel("Failed to enable Root Access on EFIESP!", Exit));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (MainOS != null)
|
||||
{
|
||||
if (DoUnlock)
|
||||
{
|
||||
ActivateSubContext(new BusyViewModel("Enable Root Access on MainOS..."));
|
||||
}
|
||||
else
|
||||
{
|
||||
ActivateSubContext(new BusyViewModel("Disable Root Access on MainOS..."));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
App.PatchEngine.TargetPath = MainOS;
|
||||
if (DoUnlock)
|
||||
{
|
||||
Result = App.PatchEngine.Patch("RootAccess-MainOS");
|
||||
|
||||
if (Result)
|
||||
{
|
||||
Result = App.PatchEngine.Patch("SecureBootHack-MainOS");
|
||||
}
|
||||
|
||||
if (!Result)
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel("Failed to enable Root Access on MainOS! Check the OS version on the phone and verify the compatibility-list in the \"Getting started\" section.", Exit));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
App.PatchEngine.Restore("RootAccess-MainOS");
|
||||
|
||||
if (!HasNewBootloader)
|
||||
{
|
||||
App.PatchEngine.Restore("SecureBootHack-MainOS");
|
||||
}
|
||||
|
||||
Result = true;
|
||||
}
|
||||
}
|
||||
catch (UnauthorizedAccessException Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
ActivateSubContext(new MessageViewModel("Failed to enable Root Access on MainOS! Not enough privileges to perform action. Try to logon to Windows with an administrator account.", Exit));
|
||||
Result = false;
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
|
||||
if (!Result)
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel("Failed to enable Root Access on MainOS!", Exit));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (DoUnlock)
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel("Root Access successfully enabled!", Exit));
|
||||
}
|
||||
else
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel("Root Access successfully disabled!", Exit));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DoUnlock)
|
||||
{
|
||||
LogFile.EndAction("EnableRootAccess");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile.EndAction("DisableRootAccess");
|
||||
}
|
||||
}).Start();
|
||||
}
|
||||
|
||||
private void Exit()
|
||||
{
|
||||
IsSwitchingInterface = false;
|
||||
Callback();
|
||||
ActivateSubContext(null);
|
||||
}
|
||||
|
||||
private bool HasNewBootloaderFromMassStorage()
|
||||
{
|
||||
bool Result = false;
|
||||
MassStorage Phone = (MassStorage)PhoneNotifier.CurrentModel;
|
||||
Phone.OpenVolume(false);
|
||||
byte[] GPTBuffer = Phone.ReadSectors(1, 33);
|
||||
GPT GPT = new(GPTBuffer);
|
||||
Partition Partition = GPT.GetPartition("UEFI");
|
||||
byte[] UefiBuffer = Phone.ReadSectors(Partition.FirstSector, Partition.LastSector - Partition.FirstSector + 1);
|
||||
UEFI UEFI = new(UefiBuffer);
|
||||
string BootMgrName = UEFI.EFIs.First(efi => (efi.Name != null) && (efi.Name.Contains("BootMgrApp") || efi.Name.Contains("FlashApp"))).Name;
|
||||
byte[] BootMgr = UEFI.GetFile(BootMgrName);
|
||||
// "Header V2"
|
||||
Result = ByteOperations.FindAscii(BootMgr, "Header V2") != null;
|
||||
Phone.CloseVolume();
|
||||
return Result;
|
||||
}
|
||||
|
||||
private bool HasV11PatchesFromMassStorage()
|
||||
{
|
||||
bool Result = false;
|
||||
MassStorage Phone = (MassStorage)PhoneNotifier.CurrentModel;
|
||||
Phone.OpenVolume(false);
|
||||
byte[] GPTBuffer = Phone.ReadSectors(1, 33);
|
||||
GPT GPT = new(GPTBuffer);
|
||||
Partition Partition = GPT.GetPartition("BACKUP_BS_NV");
|
||||
Result = Partition != null;
|
||||
Phone.CloseVolume();
|
||||
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.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class LumiaUnlockRootViewModel : ContextViewModel
|
||||
{
|
||||
private readonly PhoneNotifierViewModel PhoneNotifier;
|
||||
private readonly Action SwitchToUnlockBoot;
|
||||
private readonly Action SwitchToDumpRom;
|
||||
private readonly Action SwitchToFlashRom;
|
||||
private readonly Action Callback;
|
||||
private readonly bool DoUnlock;
|
||||
|
||||
internal LumiaUnlockRootViewModel(PhoneNotifierViewModel PhoneNotifier, Action SwitchToUnlockBoot, Action SwitchToDumpRom, Action SwitchToFlashRom, bool DoUnlock, Action Callback)
|
||||
: base()
|
||||
{
|
||||
IsSwitchingInterface = false;
|
||||
IsFlashModeOperation = true;
|
||||
|
||||
this.PhoneNotifier = PhoneNotifier;
|
||||
this.SwitchToDumpRom = SwitchToDumpRom;
|
||||
this.SwitchToFlashRom = SwitchToFlashRom;
|
||||
this.SwitchToUnlockBoot = SwitchToUnlockBoot;
|
||||
this.DoUnlock = DoUnlock;
|
||||
this.Callback = Callback;
|
||||
}
|
||||
|
||||
internal override void EvaluateViewState()
|
||||
{
|
||||
if (!IsActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (DoUnlock)
|
||||
{
|
||||
if ((SubContextViewModel == null) || (SubContextViewModel is LumiaUndoRootTargetSelectionViewModel))
|
||||
{
|
||||
ActivateSubContext(new LumiaUnlockRootTargetSelectionViewModel(PhoneNotifier, SwitchToUnlockBoot, SwitchToDumpRom, SwitchToFlashRom, DoUnlockPhone, DoUnlockImage));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((SubContextViewModel == null) || (SubContextViewModel is LumiaUnlockRootTargetSelectionViewModel))
|
||||
{
|
||||
ActivateSubContext(new LumiaUndoRootTargetSelectionViewModel(PhoneNotifier, SwitchToUnlockBoot, SwitchToDumpRom, SwitchToFlashRom, DoUnlockPhone, DoUnlockImage));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal async void DoUnlockPhone()
|
||||
{
|
||||
try
|
||||
{
|
||||
IsSwitchingInterface = true;
|
||||
await SwitchModeViewModel.SwitchToWithProgress(PhoneNotifier, PhoneInterfaces.Lumia_MassStorage,
|
||||
(msg, sub) =>
|
||||
ActivateSubContext(new BusyViewModel(msg, sub)));
|
||||
bool HasNewBootloader = HasNewBootloaderFromMassStorage();
|
||||
string EFIESPPath = HasNewBootloader ? null : ((MassStorage)PhoneNotifier.CurrentModel).Drive + @"\EFIESP\";
|
||||
string MainOSPath = ((MassStorage)PhoneNotifier.CurrentModel).Drive + @"\";
|
||||
|
||||
bool HasV11Patches = HasV11PatchesFromMassStorage();
|
||||
|
||||
StartPatch(EFIESPPath, MainOSPath, HasNewBootloader, HasV11Patches);
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel(Ex.Message, () =>
|
||||
{
|
||||
Callback();
|
||||
ActivateSubContext(null);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
internal void DoUnlockImage(string EFIESPMountPoint, string MainOSMountPoint)
|
||||
{
|
||||
StartPatch(EFIESPMountPoint, MainOSMountPoint, false, false); // Unlock image is only supported for Lumia's with bootloader Spec A. Due to complexity of Spec B bootloader hack, it cannot be applied on a mounted image.
|
||||
}
|
||||
|
||||
// Magic!
|
||||
// Apply patches for Root Access
|
||||
private void StartPatch(string EFIESP, string MainOS, bool HasNewBootloader, bool HasV11Patches)
|
||||
{
|
||||
IsSwitchingInterface = false;
|
||||
new Thread(() =>
|
||||
{
|
||||
if (DoUnlock)
|
||||
{
|
||||
LogFile.BeginAction("EnableRootAccess");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile.BeginAction("DisableRootAccess");
|
||||
}
|
||||
|
||||
bool Result = false;
|
||||
|
||||
if (EFIESP != null && !HasV11Patches)
|
||||
{
|
||||
if (DoUnlock)
|
||||
{
|
||||
ActivateSubContext(new BusyViewModel("Enable Root Access on EFIESP..."));
|
||||
}
|
||||
else
|
||||
{
|
||||
ActivateSubContext(new BusyViewModel("Disable Root Access on EFIESP..."));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
App.PatchEngine.TargetPath = EFIESP;
|
||||
if (DoUnlock)
|
||||
{
|
||||
Result = App.PatchEngine.Patch("SecureBootHack-V1-EFIESP");
|
||||
|
||||
if (!Result)
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel("Failed to enable Root Access on EFIESP! Check the OS version on the phone and verify the compatibility-list in the \"Getting started\" section.", Exit));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
App.PatchEngine.Restore("SecureBootHack-V1-EFIESP");
|
||||
Result = true;
|
||||
}
|
||||
}
|
||||
catch (UnauthorizedAccessException Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
ActivateSubContext(new MessageViewModel("Failed to enable Root Access on EFIESP! Not enough privileges to perform action. Try to logon to Windows with an administrator account.", Exit));
|
||||
return;
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
|
||||
if (!Result)
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel("Failed to enable Root Access on EFIESP!", Exit));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (MainOS != null)
|
||||
{
|
||||
if (DoUnlock)
|
||||
{
|
||||
ActivateSubContext(new BusyViewModel("Enable Root Access on MainOS..."));
|
||||
}
|
||||
else
|
||||
{
|
||||
ActivateSubContext(new BusyViewModel("Disable Root Access on MainOS..."));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
App.PatchEngine.TargetPath = MainOS;
|
||||
if (DoUnlock)
|
||||
{
|
||||
Result = App.PatchEngine.Patch("RootAccess-MainOS");
|
||||
|
||||
if (Result)
|
||||
{
|
||||
Result = App.PatchEngine.Patch("SecureBootHack-MainOS");
|
||||
}
|
||||
|
||||
if (!Result)
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel("Failed to enable Root Access on MainOS! Check the OS version on the phone and verify the compatibility-list in the \"Getting started\" section.", Exit));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
App.PatchEngine.Restore("RootAccess-MainOS");
|
||||
|
||||
if (!HasNewBootloader)
|
||||
{
|
||||
App.PatchEngine.Restore("SecureBootHack-MainOS");
|
||||
}
|
||||
|
||||
Result = true;
|
||||
}
|
||||
}
|
||||
catch (UnauthorizedAccessException Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
ActivateSubContext(new MessageViewModel("Failed to enable Root Access on MainOS! Not enough privileges to perform action. Try to logon to Windows with an administrator account.", Exit));
|
||||
Result = false;
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
Result = false;
|
||||
}
|
||||
|
||||
if (!Result)
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel("Failed to enable Root Access on MainOS!", Exit));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (DoUnlock)
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel("Root Access successfully enabled!", Exit));
|
||||
}
|
||||
else
|
||||
{
|
||||
ActivateSubContext(new MessageViewModel("Root Access successfully disabled!", Exit));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DoUnlock)
|
||||
{
|
||||
LogFile.EndAction("EnableRootAccess");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile.EndAction("DisableRootAccess");
|
||||
}
|
||||
}).Start();
|
||||
}
|
||||
|
||||
private void Exit()
|
||||
{
|
||||
IsSwitchingInterface = false;
|
||||
Callback();
|
||||
ActivateSubContext(null);
|
||||
}
|
||||
|
||||
private bool HasNewBootloaderFromMassStorage()
|
||||
{
|
||||
bool Result = false;
|
||||
MassStorage Phone = (MassStorage)PhoneNotifier.CurrentModel;
|
||||
Phone.OpenVolume(false);
|
||||
byte[] GPTBuffer = Phone.ReadSectors(1, 33);
|
||||
GPT GPT = new(GPTBuffer);
|
||||
Partition Partition = GPT.GetPartition("UEFI");
|
||||
byte[] UefiBuffer = Phone.ReadSectors(Partition.FirstSector, Partition.LastSector - Partition.FirstSector + 1);
|
||||
UEFI UEFI = new(UefiBuffer);
|
||||
string BootMgrName = UEFI.EFIs.First(efi => (efi.Name != null) && (efi.Name.Contains("BootMgrApp") || efi.Name.Contains("FlashApp"))).Name;
|
||||
byte[] BootMgr = UEFI.GetFile(BootMgrName);
|
||||
// "Header V2"
|
||||
Result = ByteOperations.FindAscii(BootMgr, "Header V2") != null;
|
||||
Phone.CloseVolume();
|
||||
return Result;
|
||||
}
|
||||
|
||||
private bool HasV11PatchesFromMassStorage()
|
||||
{
|
||||
bool Result = false;
|
||||
MassStorage Phone = (MassStorage)PhoneNotifier.CurrentModel;
|
||||
Phone.OpenVolume(false);
|
||||
byte[] GPTBuffer = Phone.ReadSectors(1, 33);
|
||||
GPT GPT = new(GPTBuffer);
|
||||
Partition Partition = GPT.GetPartition("BACKUP_BS_NV");
|
||||
Result = Partition != null;
|
||||
Phone.CloseVolume();
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
}
|
||||
+3004
-3004
File diff suppressed because it is too large
Load Diff
@@ -1,485 +1,485 @@
|
||||
// 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;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
public enum NavigationSubject
|
||||
{
|
||||
Info,
|
||||
Mode,
|
||||
Install,
|
||||
About
|
||||
};
|
||||
|
||||
public enum PhoneInterfaces
|
||||
{
|
||||
Lumia_Normal,
|
||||
Lumia_Flash,
|
||||
Lumia_Label,
|
||||
Lumia_MassStorage,
|
||||
Lumia_Bootloader,
|
||||
Qualcomm_Download,
|
||||
Qualcomm_Flash,
|
||||
Lumia_BadMassStorage
|
||||
};
|
||||
|
||||
// Create this class on the UI thread, after the main-window of the application is initialized.
|
||||
// It is necessary to create the object on the UI thread, because notification events to the View need to be fired on that thread.
|
||||
// The Model for this ViewModel communicates over USB and for that it uses the hWnd of the main window.
|
||||
// Therefore the main window must be created before the ViewModel is created.
|
||||
internal class MainViewModel : INotifyPropertyChanged
|
||||
{
|
||||
public PhoneInterfaces? CurrentInterface = null;
|
||||
public PhoneInterfaces? LastInterface = null;
|
||||
public NokiaPhoneModel CurrentModel = null;
|
||||
public PhoneNotifierViewModel PhoneNotifier;
|
||||
public LumiaInfoViewModel InfoViewModel;
|
||||
public LumiaModeViewModel ModeViewModel;
|
||||
public LumiaUnlockBootViewModel BootUnlockViewModel;
|
||||
public LumiaUnlockBootViewModel BootRestoreViewModel;
|
||||
public LumiaUnlockRootViewModel RootUnlockViewModel;
|
||||
public LumiaUnlockRootViewModel RootRestoreViewModel;
|
||||
public BackupViewModel BackupViewModel;
|
||||
public RestoreViewModel RestoreViewModel;
|
||||
public LumiaFlashRomViewModel LumiaFlashRomViewModel;
|
||||
public DumpRomViewModel DumpRomViewModel;
|
||||
public DownloadsViewModel DownloadsViewModel;
|
||||
private GettingStartedViewModel _GettingStartedViewModel = null;
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
private void OnPropertyChanged(string propertyName)
|
||||
{
|
||||
if (this.PropertyChanged != null)
|
||||
{
|
||||
if (MainSyncContext == SynchronizationContext.Current)
|
||||
{
|
||||
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
else
|
||||
{
|
||||
MainSyncContext.Post(s => PropertyChanged(this, new PropertyChangedEventArgs(propertyName)), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ContextViewModel _ContextViewModel;
|
||||
public ContextViewModel ContextViewModel
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ContextViewModel;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_ContextViewModel != value)
|
||||
{
|
||||
if (_ContextViewModel != null)
|
||||
{
|
||||
_ContextViewModel.IsActive = false;
|
||||
}
|
||||
|
||||
_ContextViewModel = value;
|
||||
_ContextViewModel?.Activate();
|
||||
OnPropertyChanged(nameof(ContextViewModel));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly SynchronizationContext MainSyncContext;
|
||||
|
||||
public MainViewModel()
|
||||
{
|
||||
MainSyncContext = SynchronizationContext.Current;
|
||||
|
||||
LogFile.LogApplicationVersion();
|
||||
|
||||
// Set global callback for cases where Dependency Injection is not possible.
|
||||
App.NavigateToGettingStarted = () => GettingStartedCommand.Execute(null);
|
||||
App.NavigateToUnlockBoot = () => BootUnlockCommand.Execute(null);
|
||||
|
||||
if (Registry.CurrentUser.OpenSubKey("Software\\WPInternals") == null)
|
||||
{
|
||||
Registry.CurrentUser.OpenSubKey("Software", true).CreateSubKey("WPInternals");
|
||||
}
|
||||
|
||||
if (Registration.IsPrerelease && (Registry.CurrentUser.OpenSubKey("Software\\WPInternals").GetValue("NdaAccepted") == null))
|
||||
{
|
||||
this.ContextViewModel = new DisclaimerAndNdaViewModel(Disclaimer_Accepted);
|
||||
}
|
||||
else if (Registry.CurrentUser.OpenSubKey("Software\\WPInternals").GetValue("DisclaimerAccepted") == null)
|
||||
{
|
||||
this.ContextViewModel = new DisclaimerViewModel(Disclaimer_Accepted);
|
||||
}
|
||||
else if (Registration.IsPrerelease && !Registration.IsRegistered())
|
||||
{
|
||||
ContextViewModel = new RegistrationViewModel(Registration_Completed, Registration_Failed);
|
||||
}
|
||||
else
|
||||
{
|
||||
StartOperation();
|
||||
}
|
||||
}
|
||||
|
||||
private void Disclaimer_Accepted()
|
||||
{
|
||||
ContextViewModel = null;
|
||||
|
||||
if (Registration.IsPrerelease && !Registration.IsRegistered())
|
||||
{
|
||||
ContextViewModel = new RegistrationViewModel(Registration_Completed, Registration_Failed);
|
||||
}
|
||||
else
|
||||
{
|
||||
StartOperation();
|
||||
}
|
||||
}
|
||||
|
||||
private void Registration_Completed()
|
||||
{
|
||||
ContextViewModel = null;
|
||||
StartOperation();
|
||||
}
|
||||
|
||||
private void Registration_Failed()
|
||||
{
|
||||
ContextViewModel = new MessageViewModel("Registration failed", () => Environment.Exit(0));
|
||||
((MessageViewModel)ContextViewModel).SubMessage = "Check your filewall settings";
|
||||
}
|
||||
|
||||
public void StartOperation()
|
||||
{
|
||||
IsMenuEnabled = true;
|
||||
|
||||
_GettingStartedViewModel = new GettingStartedViewModel(
|
||||
() =>
|
||||
{
|
||||
ContextViewModel = new DisclaimerViewModel(
|
||||
() => ContextViewModel = _GettingStartedViewModel
|
||||
);
|
||||
},
|
||||
SwitchToUnlockBoot,
|
||||
SwitchToUnlockRoot,
|
||||
SwitchToBackup,
|
||||
SwitchToDumpFFU,
|
||||
SwitchToFlashRom,
|
||||
SwitchToDownload
|
||||
);
|
||||
this.ContextViewModel = _GettingStartedViewModel;
|
||||
|
||||
PhoneNotifier = new PhoneNotifierViewModel();
|
||||
PhoneNotifier.NewDeviceArrived += PhoneNotifier_NewDeviceArrived;
|
||||
PhoneNotifier.DeviceRemoved += PhoneNotifier_DeviceRemoved;
|
||||
|
||||
InfoViewModel = new LumiaInfoViewModel(PhoneNotifier, (TargetInterface) =>
|
||||
{
|
||||
ModeViewModel.OnModeSwitchRequested(TargetInterface);
|
||||
ContextViewModel = ModeViewModel;
|
||||
},
|
||||
() => ContextViewModel = _GettingStartedViewModel);
|
||||
InfoViewModel.ActivateSubContext(null);
|
||||
|
||||
ModeViewModel = new LumiaModeViewModel(PhoneNotifier, SwitchToInfoViewModel);
|
||||
ModeViewModel.ActivateSubContext(null);
|
||||
|
||||
BootUnlockViewModel = new LumiaUnlockBootViewModel(PhoneNotifier, SwitchToFlashRom, SwitchToUndoRoot, SwitchToDownload, true, SwitchToInfoViewModel);
|
||||
BootUnlockViewModel.ActivateSubContext(null);
|
||||
|
||||
BootRestoreViewModel = new LumiaUnlockBootViewModel(PhoneNotifier, SwitchToFlashRom, SwitchToUndoRoot, SwitchToDownload, false, SwitchToInfoViewModel);
|
||||
BootRestoreViewModel.ActivateSubContext(null);
|
||||
|
||||
RootUnlockViewModel = new LumiaUnlockRootViewModel(PhoneNotifier, SwitchToUnlockBoot, SwitchToDumpFFU, SwitchToFlashRom, true, SwitchToInfoViewModel);
|
||||
RootUnlockViewModel.ActivateSubContext(null);
|
||||
|
||||
RootRestoreViewModel = new LumiaUnlockRootViewModel(PhoneNotifier, SwitchToUnlockBoot, SwitchToDumpFFU, SwitchToFlashRom, false, SwitchToInfoViewModel);
|
||||
RootRestoreViewModel.ActivateSubContext(null);
|
||||
|
||||
BackupViewModel = new BackupViewModel(PhoneNotifier, SwitchToUnlockBoot, SwitchToInfoViewModel);
|
||||
BackupViewModel.ActivateSubContext(null);
|
||||
|
||||
RestoreViewModel = new RestoreViewModel(PhoneNotifier, SwitchToDifferentInterface, SwitchToUnlockBoot, SwitchToFlashRom, SwitchToInfoViewModel);
|
||||
RestoreViewModel.ActivateSubContext(null);
|
||||
|
||||
LumiaFlashRomViewModel = new LumiaFlashRomViewModel(PhoneNotifier, SwitchToUnlockBoot, SwitchToUnlockRoot, SwitchToDumpFFU, SwitchToBackup, SwitchToInfoViewModel);
|
||||
LumiaFlashRomViewModel.ActivateSubContext(null);
|
||||
|
||||
DumpRomViewModel = new DumpRomViewModel(SwitchToUnlockBoot, SwitchToUnlockRoot, SwitchToFlashRom);
|
||||
DumpRomViewModel.ActivateSubContext(null);
|
||||
|
||||
DownloadsViewModel = new DownloadsViewModel(PhoneNotifier);
|
||||
App.DownloadManager = DownloadsViewModel;
|
||||
|
||||
PhoneNotifier.Start();
|
||||
}
|
||||
|
||||
internal void SwitchToInfoViewModel()
|
||||
{
|
||||
ContextViewModel = InfoViewModel;
|
||||
}
|
||||
|
||||
internal void SwitchToUnlockBoot()
|
||||
{
|
||||
ContextViewModel = BootUnlockViewModel;
|
||||
}
|
||||
|
||||
internal void SwitchToRestoreBoot()
|
||||
{
|
||||
ContextViewModel = BootRestoreViewModel;
|
||||
}
|
||||
|
||||
internal void SwitchToUnlockRoot()
|
||||
{
|
||||
ContextViewModel = RootUnlockViewModel;
|
||||
}
|
||||
|
||||
internal void SwitchToUndoRoot()
|
||||
{
|
||||
ContextViewModel = RootRestoreViewModel;
|
||||
}
|
||||
|
||||
internal void SwitchToBackup()
|
||||
{
|
||||
ContextViewModel = BackupViewModel;
|
||||
}
|
||||
|
||||
internal void SwitchToFlashRom()
|
||||
{
|
||||
ContextViewModel = LumiaFlashRomViewModel;
|
||||
}
|
||||
|
||||
internal void SwitchToDumpFFU()
|
||||
{
|
||||
ContextViewModel = DumpRomViewModel;
|
||||
}
|
||||
|
||||
internal void SwitchToDownload()
|
||||
{
|
||||
ContextViewModel = DownloadsViewModel;
|
||||
}
|
||||
|
||||
internal void SwitchToDifferentInterface(PhoneInterfaces TargetInterface)
|
||||
{
|
||||
ModeViewModel.OnModeSwitchRequested(TargetInterface);
|
||||
ContextViewModel = ModeViewModel;
|
||||
}
|
||||
|
||||
private void PhoneNotifier_DeviceRemoved()
|
||||
{
|
||||
InfoViewModel.ActivateSubContext(null);
|
||||
}
|
||||
|
||||
private void PhoneNotifier_NewDeviceArrived(ArrivalEventArgs Args)
|
||||
{
|
||||
PhoneInterfaces? PreviousInterface = LastInterface;
|
||||
LastInterface = Args.NewInterface;
|
||||
|
||||
if (App.InterruptBoot && (Args.NewInterface == PhoneInterfaces.Lumia_Bootloader))
|
||||
{
|
||||
App.InterruptBoot = false;
|
||||
LogFile.Log("Found Lumia BootMgr and user forced to interrupt the boot process. Force to Flash-mode.");
|
||||
Task.Run(() => SwitchModeViewModel.SwitchTo(PhoneNotifier, PhoneInterfaces.Lumia_Flash));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Args.NewInterface != PhoneInterfaces.Qualcomm_Download)
|
||||
{
|
||||
App.InterruptBoot = false;
|
||||
}
|
||||
|
||||
if (ContextViewModel == null)
|
||||
{
|
||||
ContextViewModel = InfoViewModel;
|
||||
}
|
||||
else if (ContextViewModel.IsFlashModeOperation)
|
||||
{
|
||||
if ((!ContextViewModel.IsSwitchingInterface) && (Args.NewInterface == PhoneInterfaces.Lumia_Bootloader))
|
||||
{
|
||||
// The current screen is marked as "Flash operation".
|
||||
// When the bootloader is detected at this stage, it means a phone is booting and
|
||||
// it is possible that the phone is in a non-booting stage (not possible to boot past UEFI).
|
||||
// We will try to boot straight to Flash-mode, so that it will be possible to flash a new ROM.
|
||||
LogFile.Log("Found Lumia BootMgr while mode is not being switched. Screen is marked as Flash Operation. Force to Flash-mode.");
|
||||
Task.Run(() => SwitchModeViewModel.SwitchTo(PhoneNotifier, PhoneInterfaces.Lumia_Flash));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((!ContextViewModel.IsSwitchingInterface) && (Args.NewInterface != PhoneInterfaces.Lumia_Bootloader))
|
||||
{
|
||||
ContextViewModel = InfoViewModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _InfoCommand = null;
|
||||
public ICommand InfoCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _InfoCommand ??= new DelegateCommand(() => ContextViewModel = InfoViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _ModeCommand = null;
|
||||
public ICommand ModeCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ModeCommand ??= new DelegateCommand(() => ContextViewModel = ModeViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _BootUnlockCommand = null;
|
||||
public ICommand BootUnlockCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _BootUnlockCommand ??= new DelegateCommand(() => ContextViewModel = BootUnlockViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _BootRestoreCommand = null;
|
||||
public ICommand BootRestoreCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _BootRestoreCommand ??= new DelegateCommand(() => ContextViewModel = BootRestoreViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _RootUnlockCommand = null;
|
||||
public ICommand RootUnlockCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _RootUnlockCommand ??= new DelegateCommand(() => ContextViewModel = RootUnlockViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _RootUndoCommand = null;
|
||||
public ICommand RootUndoCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _RootUndoCommand ??= new DelegateCommand(() => ContextViewModel = RootRestoreViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _BackupCommand = null;
|
||||
public ICommand BackupCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _BackupCommand ??= new DelegateCommand(() => ContextViewModel = BackupViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _RestoreCommand = null;
|
||||
public ICommand RestoreCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _RestoreCommand ??= new DelegateCommand(() => ContextViewModel = RestoreViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _LumiaFlashRomCommand = null;
|
||||
public ICommand LumiaFlashRomCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _LumiaFlashRomCommand ??= new DelegateCommand(() => ContextViewModel = LumiaFlashRomViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _DumpRomCommand = null;
|
||||
public ICommand DumpRomCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _DumpRomCommand ??= new DelegateCommand(() => ContextViewModel = DumpRomViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _AboutCommand = null;
|
||||
public ICommand AboutCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _AboutCommand ??= new DelegateCommand(() => ContextViewModel = new AboutViewModel());
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _DonateCommand = null;
|
||||
public ICommand DonateCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _DonateCommand ??= new DelegateCommand(() =>
|
||||
{
|
||||
Process process = new();
|
||||
process.StartInfo.UseShellExecute = true;
|
||||
process.StartInfo.FileName = "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=VY8N7BCBT9CS4";
|
||||
process.Start();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _GettingStartedCommand = null;
|
||||
public ICommand GettingStartedCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _GettingStartedCommand ??= new DelegateCommand(() => ContextViewModel = _GettingStartedViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _DownloadCommand = null;
|
||||
public ICommand DownloadCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _DownloadCommand ??= new DelegateCommand(() => ContextViewModel = DownloadsViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private bool _IsMenuEnabled = false;
|
||||
public bool IsMenuEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return _IsMenuEnabled;
|
||||
}
|
||||
set
|
||||
{
|
||||
_IsMenuEnabled = value;
|
||||
OnPropertyChanged(nameof(IsMenuEnabled));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
public enum NavigationSubject
|
||||
{
|
||||
Info,
|
||||
Mode,
|
||||
Install,
|
||||
About
|
||||
};
|
||||
|
||||
public enum PhoneInterfaces
|
||||
{
|
||||
Lumia_Normal,
|
||||
Lumia_Flash,
|
||||
Lumia_Label,
|
||||
Lumia_MassStorage,
|
||||
Lumia_Bootloader,
|
||||
Qualcomm_Download,
|
||||
Qualcomm_Flash,
|
||||
Lumia_BadMassStorage
|
||||
};
|
||||
|
||||
// Create this class on the UI thread, after the main-window of the application is initialized.
|
||||
// It is necessary to create the object on the UI thread, because notification events to the View need to be fired on that thread.
|
||||
// The Model for this ViewModel communicates over USB and for that it uses the hWnd of the main window.
|
||||
// Therefore the main window must be created before the ViewModel is created.
|
||||
internal class MainViewModel : INotifyPropertyChanged
|
||||
{
|
||||
public PhoneInterfaces? CurrentInterface = null;
|
||||
public PhoneInterfaces? LastInterface = null;
|
||||
public NokiaPhoneModel CurrentModel = null;
|
||||
public PhoneNotifierViewModel PhoneNotifier;
|
||||
public LumiaInfoViewModel InfoViewModel;
|
||||
public LumiaModeViewModel ModeViewModel;
|
||||
public LumiaUnlockBootViewModel BootUnlockViewModel;
|
||||
public LumiaUnlockBootViewModel BootRestoreViewModel;
|
||||
public LumiaUnlockRootViewModel RootUnlockViewModel;
|
||||
public LumiaUnlockRootViewModel RootRestoreViewModel;
|
||||
public BackupViewModel BackupViewModel;
|
||||
public RestoreViewModel RestoreViewModel;
|
||||
public LumiaFlashRomViewModel LumiaFlashRomViewModel;
|
||||
public DumpRomViewModel DumpRomViewModel;
|
||||
public DownloadsViewModel DownloadsViewModel;
|
||||
private GettingStartedViewModel _GettingStartedViewModel = null;
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
private void OnPropertyChanged(string propertyName)
|
||||
{
|
||||
if (this.PropertyChanged != null)
|
||||
{
|
||||
if (MainSyncContext == SynchronizationContext.Current)
|
||||
{
|
||||
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
else
|
||||
{
|
||||
MainSyncContext.Post(s => PropertyChanged(this, new PropertyChangedEventArgs(propertyName)), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ContextViewModel _ContextViewModel;
|
||||
public ContextViewModel ContextViewModel
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ContextViewModel;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_ContextViewModel != value)
|
||||
{
|
||||
if (_ContextViewModel != null)
|
||||
{
|
||||
_ContextViewModel.IsActive = false;
|
||||
}
|
||||
|
||||
_ContextViewModel = value;
|
||||
_ContextViewModel?.Activate();
|
||||
OnPropertyChanged(nameof(ContextViewModel));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly SynchronizationContext MainSyncContext;
|
||||
|
||||
public MainViewModel()
|
||||
{
|
||||
MainSyncContext = SynchronizationContext.Current;
|
||||
|
||||
LogFile.LogApplicationVersion();
|
||||
|
||||
// Set global callback for cases where Dependency Injection is not possible.
|
||||
App.NavigateToGettingStarted = () => GettingStartedCommand.Execute(null);
|
||||
App.NavigateToUnlockBoot = () => BootUnlockCommand.Execute(null);
|
||||
|
||||
if (Registry.CurrentUser.OpenSubKey("Software\\WPInternals") == null)
|
||||
{
|
||||
Registry.CurrentUser.OpenSubKey("Software", true).CreateSubKey("WPInternals");
|
||||
}
|
||||
|
||||
if (Registration.IsPrerelease && (Registry.CurrentUser.OpenSubKey("Software\\WPInternals").GetValue("NdaAccepted") == null))
|
||||
{
|
||||
this.ContextViewModel = new DisclaimerAndNdaViewModel(Disclaimer_Accepted);
|
||||
}
|
||||
else if (Registry.CurrentUser.OpenSubKey("Software\\WPInternals").GetValue("DisclaimerAccepted") == null)
|
||||
{
|
||||
this.ContextViewModel = new DisclaimerViewModel(Disclaimer_Accepted);
|
||||
}
|
||||
else if (Registration.IsPrerelease && !Registration.IsRegistered())
|
||||
{
|
||||
ContextViewModel = new RegistrationViewModel(Registration_Completed, Registration_Failed);
|
||||
}
|
||||
else
|
||||
{
|
||||
StartOperation();
|
||||
}
|
||||
}
|
||||
|
||||
private void Disclaimer_Accepted()
|
||||
{
|
||||
ContextViewModel = null;
|
||||
|
||||
if (Registration.IsPrerelease && !Registration.IsRegistered())
|
||||
{
|
||||
ContextViewModel = new RegistrationViewModel(Registration_Completed, Registration_Failed);
|
||||
}
|
||||
else
|
||||
{
|
||||
StartOperation();
|
||||
}
|
||||
}
|
||||
|
||||
private void Registration_Completed()
|
||||
{
|
||||
ContextViewModel = null;
|
||||
StartOperation();
|
||||
}
|
||||
|
||||
private void Registration_Failed()
|
||||
{
|
||||
ContextViewModel = new MessageViewModel("Registration failed", () => Environment.Exit(0));
|
||||
((MessageViewModel)ContextViewModel).SubMessage = "Check your filewall settings";
|
||||
}
|
||||
|
||||
public void StartOperation()
|
||||
{
|
||||
IsMenuEnabled = true;
|
||||
|
||||
_GettingStartedViewModel = new GettingStartedViewModel(
|
||||
() =>
|
||||
{
|
||||
ContextViewModel = new DisclaimerViewModel(
|
||||
() => ContextViewModel = _GettingStartedViewModel
|
||||
);
|
||||
},
|
||||
SwitchToUnlockBoot,
|
||||
SwitchToUnlockRoot,
|
||||
SwitchToBackup,
|
||||
SwitchToDumpFFU,
|
||||
SwitchToFlashRom,
|
||||
SwitchToDownload
|
||||
);
|
||||
this.ContextViewModel = _GettingStartedViewModel;
|
||||
|
||||
PhoneNotifier = new PhoneNotifierViewModel();
|
||||
PhoneNotifier.NewDeviceArrived += PhoneNotifier_NewDeviceArrived;
|
||||
PhoneNotifier.DeviceRemoved += PhoneNotifier_DeviceRemoved;
|
||||
|
||||
InfoViewModel = new LumiaInfoViewModel(PhoneNotifier, (TargetInterface) =>
|
||||
{
|
||||
ModeViewModel.OnModeSwitchRequested(TargetInterface);
|
||||
ContextViewModel = ModeViewModel;
|
||||
},
|
||||
() => ContextViewModel = _GettingStartedViewModel);
|
||||
InfoViewModel.ActivateSubContext(null);
|
||||
|
||||
ModeViewModel = new LumiaModeViewModel(PhoneNotifier, SwitchToInfoViewModel);
|
||||
ModeViewModel.ActivateSubContext(null);
|
||||
|
||||
BootUnlockViewModel = new LumiaUnlockBootViewModel(PhoneNotifier, SwitchToFlashRom, SwitchToUndoRoot, SwitchToDownload, true, SwitchToInfoViewModel);
|
||||
BootUnlockViewModel.ActivateSubContext(null);
|
||||
|
||||
BootRestoreViewModel = new LumiaUnlockBootViewModel(PhoneNotifier, SwitchToFlashRom, SwitchToUndoRoot, SwitchToDownload, false, SwitchToInfoViewModel);
|
||||
BootRestoreViewModel.ActivateSubContext(null);
|
||||
|
||||
RootUnlockViewModel = new LumiaUnlockRootViewModel(PhoneNotifier, SwitchToUnlockBoot, SwitchToDumpFFU, SwitchToFlashRom, true, SwitchToInfoViewModel);
|
||||
RootUnlockViewModel.ActivateSubContext(null);
|
||||
|
||||
RootRestoreViewModel = new LumiaUnlockRootViewModel(PhoneNotifier, SwitchToUnlockBoot, SwitchToDumpFFU, SwitchToFlashRom, false, SwitchToInfoViewModel);
|
||||
RootRestoreViewModel.ActivateSubContext(null);
|
||||
|
||||
BackupViewModel = new BackupViewModel(PhoneNotifier, SwitchToUnlockBoot, SwitchToInfoViewModel);
|
||||
BackupViewModel.ActivateSubContext(null);
|
||||
|
||||
RestoreViewModel = new RestoreViewModel(PhoneNotifier, SwitchToDifferentInterface, SwitchToUnlockBoot, SwitchToFlashRom, SwitchToInfoViewModel);
|
||||
RestoreViewModel.ActivateSubContext(null);
|
||||
|
||||
LumiaFlashRomViewModel = new LumiaFlashRomViewModel(PhoneNotifier, SwitchToUnlockBoot, SwitchToUnlockRoot, SwitchToDumpFFU, SwitchToBackup, SwitchToInfoViewModel);
|
||||
LumiaFlashRomViewModel.ActivateSubContext(null);
|
||||
|
||||
DumpRomViewModel = new DumpRomViewModel(SwitchToUnlockBoot, SwitchToUnlockRoot, SwitchToFlashRom);
|
||||
DumpRomViewModel.ActivateSubContext(null);
|
||||
|
||||
DownloadsViewModel = new DownloadsViewModel(PhoneNotifier);
|
||||
App.DownloadManager = DownloadsViewModel;
|
||||
|
||||
PhoneNotifier.Start();
|
||||
}
|
||||
|
||||
internal void SwitchToInfoViewModel()
|
||||
{
|
||||
ContextViewModel = InfoViewModel;
|
||||
}
|
||||
|
||||
internal void SwitchToUnlockBoot()
|
||||
{
|
||||
ContextViewModel = BootUnlockViewModel;
|
||||
}
|
||||
|
||||
internal void SwitchToRestoreBoot()
|
||||
{
|
||||
ContextViewModel = BootRestoreViewModel;
|
||||
}
|
||||
|
||||
internal void SwitchToUnlockRoot()
|
||||
{
|
||||
ContextViewModel = RootUnlockViewModel;
|
||||
}
|
||||
|
||||
internal void SwitchToUndoRoot()
|
||||
{
|
||||
ContextViewModel = RootRestoreViewModel;
|
||||
}
|
||||
|
||||
internal void SwitchToBackup()
|
||||
{
|
||||
ContextViewModel = BackupViewModel;
|
||||
}
|
||||
|
||||
internal void SwitchToFlashRom()
|
||||
{
|
||||
ContextViewModel = LumiaFlashRomViewModel;
|
||||
}
|
||||
|
||||
internal void SwitchToDumpFFU()
|
||||
{
|
||||
ContextViewModel = DumpRomViewModel;
|
||||
}
|
||||
|
||||
internal void SwitchToDownload()
|
||||
{
|
||||
ContextViewModel = DownloadsViewModel;
|
||||
}
|
||||
|
||||
internal void SwitchToDifferentInterface(PhoneInterfaces TargetInterface)
|
||||
{
|
||||
ModeViewModel.OnModeSwitchRequested(TargetInterface);
|
||||
ContextViewModel = ModeViewModel;
|
||||
}
|
||||
|
||||
private void PhoneNotifier_DeviceRemoved()
|
||||
{
|
||||
InfoViewModel.ActivateSubContext(null);
|
||||
}
|
||||
|
||||
private void PhoneNotifier_NewDeviceArrived(ArrivalEventArgs Args)
|
||||
{
|
||||
PhoneInterfaces? PreviousInterface = LastInterface;
|
||||
LastInterface = Args.NewInterface;
|
||||
|
||||
if (App.InterruptBoot && (Args.NewInterface == PhoneInterfaces.Lumia_Bootloader))
|
||||
{
|
||||
App.InterruptBoot = false;
|
||||
LogFile.Log("Found Lumia BootMgr and user forced to interrupt the boot process. Force to Flash-mode.");
|
||||
Task.Run(() => SwitchModeViewModel.SwitchTo(PhoneNotifier, PhoneInterfaces.Lumia_Flash));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Args.NewInterface != PhoneInterfaces.Qualcomm_Download)
|
||||
{
|
||||
App.InterruptBoot = false;
|
||||
}
|
||||
|
||||
if (ContextViewModel == null)
|
||||
{
|
||||
ContextViewModel = InfoViewModel;
|
||||
}
|
||||
else if (ContextViewModel.IsFlashModeOperation)
|
||||
{
|
||||
if ((!ContextViewModel.IsSwitchingInterface) && (Args.NewInterface == PhoneInterfaces.Lumia_Bootloader))
|
||||
{
|
||||
// The current screen is marked as "Flash operation".
|
||||
// When the bootloader is detected at this stage, it means a phone is booting and
|
||||
// it is possible that the phone is in a non-booting stage (not possible to boot past UEFI).
|
||||
// We will try to boot straight to Flash-mode, so that it will be possible to flash a new ROM.
|
||||
LogFile.Log("Found Lumia BootMgr while mode is not being switched. Screen is marked as Flash Operation. Force to Flash-mode.");
|
||||
Task.Run(() => SwitchModeViewModel.SwitchTo(PhoneNotifier, PhoneInterfaces.Lumia_Flash));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((!ContextViewModel.IsSwitchingInterface) && (Args.NewInterface != PhoneInterfaces.Lumia_Bootloader))
|
||||
{
|
||||
ContextViewModel = InfoViewModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _InfoCommand = null;
|
||||
public ICommand InfoCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _InfoCommand ??= new DelegateCommand(() => ContextViewModel = InfoViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _ModeCommand = null;
|
||||
public ICommand ModeCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ModeCommand ??= new DelegateCommand(() => ContextViewModel = ModeViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _BootUnlockCommand = null;
|
||||
public ICommand BootUnlockCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _BootUnlockCommand ??= new DelegateCommand(() => ContextViewModel = BootUnlockViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _BootRestoreCommand = null;
|
||||
public ICommand BootRestoreCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _BootRestoreCommand ??= new DelegateCommand(() => ContextViewModel = BootRestoreViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _RootUnlockCommand = null;
|
||||
public ICommand RootUnlockCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _RootUnlockCommand ??= new DelegateCommand(() => ContextViewModel = RootUnlockViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _RootUndoCommand = null;
|
||||
public ICommand RootUndoCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _RootUndoCommand ??= new DelegateCommand(() => ContextViewModel = RootRestoreViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _BackupCommand = null;
|
||||
public ICommand BackupCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _BackupCommand ??= new DelegateCommand(() => ContextViewModel = BackupViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _RestoreCommand = null;
|
||||
public ICommand RestoreCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _RestoreCommand ??= new DelegateCommand(() => ContextViewModel = RestoreViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _LumiaFlashRomCommand = null;
|
||||
public ICommand LumiaFlashRomCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _LumiaFlashRomCommand ??= new DelegateCommand(() => ContextViewModel = LumiaFlashRomViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _DumpRomCommand = null;
|
||||
public ICommand DumpRomCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _DumpRomCommand ??= new DelegateCommand(() => ContextViewModel = DumpRomViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _AboutCommand = null;
|
||||
public ICommand AboutCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _AboutCommand ??= new DelegateCommand(() => ContextViewModel = new AboutViewModel());
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _DonateCommand = null;
|
||||
public ICommand DonateCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _DonateCommand ??= new DelegateCommand(() =>
|
||||
{
|
||||
Process process = new();
|
||||
process.StartInfo.UseShellExecute = true;
|
||||
process.StartInfo.FileName = "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=VY8N7BCBT9CS4";
|
||||
process.Start();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _GettingStartedCommand = null;
|
||||
public ICommand GettingStartedCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _GettingStartedCommand ??= new DelegateCommand(() => ContextViewModel = _GettingStartedViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _DownloadCommand = null;
|
||||
public ICommand DownloadCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _DownloadCommand ??= new DelegateCommand(() => ContextViewModel = DownloadsViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private bool _IsMenuEnabled = false;
|
||||
public bool IsMenuEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return _IsMenuEnabled;
|
||||
}
|
||||
set
|
||||
{
|
||||
_IsMenuEnabled = value;
|
||||
OnPropertyChanged(nameof(IsMenuEnabled));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +1,75 @@
|
||||
// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class MessageViewModel : ContextViewModel
|
||||
{
|
||||
internal MessageViewModel(string Message, Action OkAction = null, Action CancelAction = null)
|
||||
: base()
|
||||
{
|
||||
LogFile.Log(Message);
|
||||
|
||||
if (OkAction != null)
|
||||
{
|
||||
this.OkCommand = new DelegateCommand(OkAction);
|
||||
}
|
||||
|
||||
if (CancelAction != null)
|
||||
{
|
||||
this.CancelCommand = new DelegateCommand(CancelAction);
|
||||
}
|
||||
|
||||
this.Message = Message;
|
||||
}
|
||||
|
||||
private string _Message = null;
|
||||
public string Message
|
||||
{
|
||||
get
|
||||
{
|
||||
return _Message;
|
||||
}
|
||||
set
|
||||
{
|
||||
_Message = value;
|
||||
OnPropertyChanged(nameof(Message));
|
||||
}
|
||||
}
|
||||
|
||||
private string _SubMessage = null;
|
||||
public string SubMessage
|
||||
{
|
||||
get
|
||||
{
|
||||
return _SubMessage;
|
||||
}
|
||||
set
|
||||
{
|
||||
_SubMessage = value;
|
||||
OnPropertyChanged(nameof(SubMessage));
|
||||
}
|
||||
}
|
||||
public DelegateCommand OkCommand { get; } = null;
|
||||
public DelegateCommand CancelCommand { get; } = 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;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class MessageViewModel : ContextViewModel
|
||||
{
|
||||
internal MessageViewModel(string Message, Action OkAction = null, Action CancelAction = null)
|
||||
: base()
|
||||
{
|
||||
LogFile.Log(Message);
|
||||
|
||||
if (OkAction != null)
|
||||
{
|
||||
this.OkCommand = new DelegateCommand(OkAction);
|
||||
}
|
||||
|
||||
if (CancelAction != null)
|
||||
{
|
||||
this.CancelCommand = new DelegateCommand(CancelAction);
|
||||
}
|
||||
|
||||
this.Message = Message;
|
||||
}
|
||||
|
||||
private string _Message = null;
|
||||
public string Message
|
||||
{
|
||||
get
|
||||
{
|
||||
return _Message;
|
||||
}
|
||||
set
|
||||
{
|
||||
_Message = value;
|
||||
OnPropertyChanged(nameof(Message));
|
||||
}
|
||||
}
|
||||
|
||||
private string _SubMessage = null;
|
||||
public string SubMessage
|
||||
{
|
||||
get
|
||||
{
|
||||
return _SubMessage;
|
||||
}
|
||||
set
|
||||
{
|
||||
_SubMessage = value;
|
||||
OnPropertyChanged(nameof(SubMessage));
|
||||
}
|
||||
}
|
||||
public DelegateCommand OkCommand { get; } = null;
|
||||
public DelegateCommand CancelCommand { get; } = null;
|
||||
}
|
||||
}
|
||||
+762
-762
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user