diff --git a/XCI Explorer.csproj b/XCI Explorer.csproj
index 71c9199..663284c 100644
--- a/XCI Explorer.csproj
+++ b/XCI Explorer.csproj
@@ -15,4 +15,10 @@
+
+
+ Always
+ true
+
+
\ No newline at end of file
diff --git a/XCI_Explorer.Helpers/BetterBinaryReader.cs b/XCI_Explorer.Helpers/BetterBinaryReader.cs
deleted file mode 100644
index 21368b6..0000000
--- a/XCI_Explorer.Helpers/BetterBinaryReader.cs
+++ /dev/null
@@ -1,154 +0,0 @@
-using System;
-using System.IO;
-
-namespace XCI_Explorer.Helpers
-{
- public class BetterBinaryReader : IDisposable
- {
- public string FileName;
- public bool Initiated;
- public Stream Stream;
- private BinaryReader br;
-
- public BetterBinaryReader()
- {
- Initiated = false;
- }
-
- public BetterBinaryReader(string file)
- {
- Initiated = false;
- Load(file);
- }
-
- public BetterBinaryReader(Stream s)
- {
- Initiated = false;
- FileName = "";
- Stream = s;
- br = new BinaryReader(Stream);
- }
-
- public void Dispose()
- {
- Initiated = false;
- br.Close();
- br = null;
- Stream.Close();
- Stream = null;
- }
-
- public void Load(string file)
- {
- FileName = file;
- Stream = new FileStream(file, FileMode.Open);
- br = new BinaryReader(Stream);
- Initiated = true;
- }
-
- public void Seek(long o)
- {
- if (o > -1)
- {
- Stream.Seek(o, SeekOrigin.Begin);
- }
- }
-
- public void Skip(long o)
- {
- Stream.Seek(o, SeekOrigin.Current);
- }
-
- public long Position()
- {
- return Stream.Position;
- }
-
- public int Read()
- {
- return br.ReadBytes(1)[0];
- }
-
- public int Read(byte[] buffer, int index, int count)
- {
- return br.Read(buffer, index, count);
- }
-
- public int Read(char[] buffer, int index, int count)
- {
- return br.Read(buffer, index, count);
- }
-
- public byte[] ReadBytes(int l)
- {
- if (l >= 0 && l <= 2147483647)
- {
- return br.ReadBytes(l);
- }
- return new byte[0];
- }
-
- public Stream ReadBytesButLonger(long l)
- {
- MemoryStream memoryStream = new MemoryStream();
- for (long num = 0L; num < l; num++)
- {
- }
- Console.WriteLine(memoryStream.Length);
- return memoryStream;
- }
-
- public string ReadCharsAsString(int l)
- {
- return new string(br.ReadChars(l));
- }
-
- public short ReadShort()
- {
- return br.ReadInt16();
- }
-
- public short ReadInt16()
- {
- return br.ReadInt16();
- }
-
- public int ReadInt()
- {
- return br.ReadInt32();
- }
-
- public int ReadInt32()
- {
- return br.ReadInt32();
- }
-
- public long ReadLong()
- {
- return br.ReadInt64();
- }
-
- public long ReadInt64()
- {
- return br.ReadInt64();
- }
-
- public string ReadString()
- {
- return br.ReadString();
- }
-
- private long GreatestDivisor(long n)
- {
- long result = 0L;
- for (long num = 1L; num < n / 64; num++)
- {
- if (n % num == 0L && num != n)
- {
- result = num;
- }
- }
- return result;
- }
- }
-}
diff --git a/XCI_Explorer.Helpers/BetterTreeNode.cs b/XCI_Explorer.Helpers/BetterTreeNode.cs
index 89589a5..129fb7b 100644
--- a/XCI_Explorer.Helpers/BetterTreeNode.cs
+++ b/XCI_Explorer.Helpers/BetterTreeNode.cs
@@ -1,18 +1,17 @@
using System.Windows.Forms;
-namespace XCI_Explorer.Helpers
-{
- public class BetterTreeNode : TreeNode
- {
- public long Offset;
- public long Size;
- public string ExpectedHash;
- public string ActualHash;
- public long HashedRegionSize;
+namespace XCI_Explorer.Helpers;
- public BetterTreeNode(string t)
- {
- base.Text = t;
- }
+public class BetterTreeNode : TreeNode
+{
+ public long Offset;
+ public long Size;
+ public string ExpectedHash;
+ public string ActualHash;
+ public long HashedRegionSize;
+
+ public BetterTreeNode(string t)
+ {
+ Text = t;
}
}
diff --git a/XCI_Explorer/CNMT.cs b/XCI_Explorer/CNMT.cs
index c7ab6d5..33d2975 100644
--- a/XCI_Explorer/CNMT.cs
+++ b/XCI_Explorer/CNMT.cs
@@ -1,80 +1,79 @@
using System;
using System.Linq;
-namespace XCI_Explorer
+namespace XCI_Explorer;
+
+internal static class CNMT
{
- internal static class CNMT
+ public class CNMT_Header
{
- public class CNMT_Header
+ public byte[] Data;
+ public long TitleID;
+ public int TitleVersion;
+ public byte Type;
+ public byte Reserved1;
+ public short Offset;
+ public short ContentCount;
+ public short MetaCount;
+ public byte[] Reserved2;
+
+ public enum TitleType
{
- public byte[] Data;
- public long TitleID;
- public int TitleVersion;
- public byte Type;
- public byte Reserved1;
- public short Offset;
- public short ContentCount;
- public short MetaCount;
- public byte[] Reserved2;
-
- public enum TitleType
- {
- SYSTEM_PROGRAMS = 0x01,
- SYSTEM_DATA_ARCHIVES,
- SYSTEM_UPDATE,
- FIRMWARE_PACKAGE_A,
- FIRMWARE_PACKAGE_B,
- REGULAR_APPLICATION = 0x80,
- UPDATE_TITLE,
- ADD_ON_CONTENT,
- DELTA_TITLE
- }
-
- public CNMT_Header(byte[] data)
- {
- Data = data;
- TitleID = BitConverter.ToInt64(data, 0);
- TitleVersion = BitConverter.ToInt32(data, 8);
- Type = Data[12];
- Reserved1 = Data[13];
- Offset = BitConverter.ToInt16(data, 14);
- ContentCount = BitConverter.ToInt16(data, 16);
- MetaCount = BitConverter.ToInt16(data, 16);
- Reserved2 = Data.Skip(20).Take(12).ToArray();
- }
+ SYSTEM_PROGRAMS = 0x01,
+ SYSTEM_DATA_ARCHIVES,
+ SYSTEM_UPDATE,
+ FIRMWARE_PACKAGE_A,
+ FIRMWARE_PACKAGE_B,
+ REGULAR_APPLICATION = 0x80,
+ UPDATE_TITLE,
+ ADD_ON_CONTENT,
+ DELTA_TITLE
}
- public class CNMT_Entry
+ public CNMT_Header(byte[] data)
{
- public byte[] Data;
- public byte[] Hash;
- public byte[] NcaId;
- public long Size;
- public byte Type;
- public byte Reserved;
-
- public enum ContentType
- {
- META,
- PROGRAM,
- DATA,
- CONTROL,
- OFFLINE_MANUAL,
- LEGAL,
- GAME_UPDATE
- }
-
- public CNMT_Entry(byte[] data)
- {
- Data = data;
- Hash = Data.Skip(0).Take(32).ToArray();
- NcaId = Data.Skip(32).Take(16).ToArray();
- Size = BitConverter.ToInt32(data, 48) + BitConverter.ToInt16(data, 52) * 65536;
- Type = Data[54];
- Reserved = Data[55];
- }
+ Data = data;
+ TitleID = BitConverter.ToInt64(data, 0);
+ TitleVersion = BitConverter.ToInt32(data, 8);
+ Type = Data[12];
+ Reserved1 = Data[13];
+ Offset = BitConverter.ToInt16(data, 14);
+ ContentCount = BitConverter.ToInt16(data, 16);
+ MetaCount = BitConverter.ToInt16(data, 16);
+ Reserved2 = Data.Skip(20).Take(12).ToArray();
}
-
- public static CNMT_Header[] CNMT_Headers = new CNMT_Header[1];
}
+
+ public class CNMT_Entry
+ {
+ public byte[] Data;
+ public byte[] Hash;
+ public byte[] NcaId;
+ public long Size;
+ public byte Type;
+ public byte Reserved;
+
+ public enum ContentType
+ {
+ META,
+ PROGRAM,
+ DATA,
+ CONTROL,
+ OFFLINE_MANUAL,
+ LEGAL,
+ GAME_UPDATE
+ }
+
+ public CNMT_Entry(byte[] data)
+ {
+ Data = data;
+ Hash = Data.Skip(0).Take(32).ToArray();
+ NcaId = Data.Skip(32).Take(16).ToArray();
+ Size = BitConverter.ToInt32(data, 48) + BitConverter.ToInt16(data, 52) * 65536;
+ Type = Data[54];
+ Reserved = Data[55];
+ }
+ }
+
+ public static CNMT_Header[] CNMT_Headers = new CNMT_Header[1];
}
diff --git a/XCI_Explorer/CenterWinDialog.cs b/XCI_Explorer/CenterWinDialog.cs
index de53275..0119610 100644
--- a/XCI_Explorer/CenterWinDialog.cs
+++ b/XCI_Explorer/CenterWinDialog.cs
@@ -1,69 +1,77 @@
using System;
-using System.Windows.Forms;
-using System.Text;
using System.Drawing;
using System.Runtime.InteropServices;
+using System.Text;
+using System.Windows.Forms;
-namespace XCI_Explorer
+namespace XCI_Explorer;
+
+public class CenterWinDialog : IDisposable
{
- public class CenterWinDialog : IDisposable
+ private int mTries = 0;
+ private Form mOwner;
+
+ public CenterWinDialog(Form owner)
{
- private int mTries = 0;
- private Form mOwner;
-
- public CenterWinDialog(Form owner)
+ mOwner = owner;
+ if (owner.WindowState != FormWindowState.Minimized)
{
- mOwner = owner;
- if (owner.WindowState != FormWindowState.Minimized)
- {
- owner.BeginInvoke(new MethodInvoker(findDialog));
- }
+ owner.BeginInvoke(new MethodInvoker(findDialog));
}
-
- private void findDialog()
- {
- // Enumerate windows to find the message box
- if (mTries < 0) return;
- EnumThreadWndProc callback = new EnumThreadWndProc(checkWindow);
- if (EnumThreadWindows(GetCurrentThreadId(), callback, IntPtr.Zero))
- {
- if (++mTries < 10) mOwner.BeginInvoke(new MethodInvoker(findDialog));
- }
- }
- private bool checkWindow(IntPtr hWnd, IntPtr lp)
- {
- // Checks if is a dialog
- StringBuilder sb = new StringBuilder(260);
- GetClassName(hWnd, sb, sb.Capacity);
- if (sb.ToString() != "#32770") return true;
- // Got it
- Rectangle frmRect = new Rectangle(mOwner.Location, mOwner.Size);
- RECT dlgRect;
- GetWindowRect(hWnd, out dlgRect);
- MoveWindow(hWnd,
- frmRect.Left + (frmRect.Width - dlgRect.Right + dlgRect.Left) / 2,
- frmRect.Top + (frmRect.Height - dlgRect.Bottom + dlgRect.Top) / 2,
- dlgRect.Right - dlgRect.Left,
- dlgRect.Bottom - dlgRect.Top, true);
- return false;
- }
- public void Dispose()
- {
- mTries = -1;
- }
-
- // P/Invoke declarations
- private delegate bool EnumThreadWndProc(IntPtr hWnd, IntPtr lp);
- [DllImport("user32.dll")]
- private static extern bool EnumThreadWindows(int tid, EnumThreadWndProc callback, IntPtr lp);
- [DllImport("kernel32.dll")]
- private static extern int GetCurrentThreadId();
- [DllImport("user32.dll")]
- private static extern int GetClassName(IntPtr hWnd, StringBuilder buffer, int buflen);
- [DllImport("user32.dll")]
- private static extern bool GetWindowRect(IntPtr hWnd, out RECT rc);
- [DllImport("user32.dll")]
- private static extern bool MoveWindow(IntPtr hWnd, int x, int y, int w, int h, bool repaint);
- private struct RECT { public int Left; public int Top; public int Right; public int Bottom; }
}
+
+ private void findDialog()
+ {
+ // Enumerate windows to find the message box
+ if (mTries < 0)
+ {
+ return;
+ }
+ EnumThreadWndProc callback = new(checkWindow);
+ if (EnumThreadWindows(GetCurrentThreadId(), callback, IntPtr.Zero))
+ {
+ if (++mTries < 10)
+ {
+ mOwner.BeginInvoke(new MethodInvoker(findDialog));
+ }
+ }
+ }
+ private bool checkWindow(IntPtr hWnd, IntPtr lp)
+ {
+ // Checks if is a dialog
+ StringBuilder sb = new(260);
+ GetClassName(hWnd, sb, sb.Capacity);
+ if (sb.ToString() != "#32770")
+ {
+ return true;
+ }
+ // Got it
+ Rectangle frmRect = new Rectangle(mOwner.Location, mOwner.Size);
+ RECT dlgRect;
+ GetWindowRect(hWnd, out dlgRect);
+ MoveWindow(hWnd,
+ frmRect.Left + (frmRect.Width - dlgRect.Right + dlgRect.Left) / 2,
+ frmRect.Top + (frmRect.Height - dlgRect.Bottom + dlgRect.Top) / 2,
+ dlgRect.Right - dlgRect.Left,
+ dlgRect.Bottom - dlgRect.Top, true);
+ return false;
+ }
+ public void Dispose()
+ {
+ mTries = -1;
+ }
+
+ // P/Invoke declarations
+ private delegate bool EnumThreadWndProc(IntPtr hWnd, IntPtr lp);
+ [DllImport("user32.dll")]
+ private static extern bool EnumThreadWindows(int tid, EnumThreadWndProc callback, IntPtr lp);
+ [DllImport("kernel32.dll")]
+ private static extern int GetCurrentThreadId();
+ [DllImport("user32.dll")]
+ private static extern int GetClassName(IntPtr hWnd, StringBuilder buffer, int buflen);
+ [DllImport("user32.dll")]
+ private static extern bool GetWindowRect(IntPtr hWnd, out RECT rc);
+ [DllImport("user32.dll")]
+ private static extern bool MoveWindow(IntPtr hWnd, int x, int y, int w, int h, bool repaint);
+ private struct RECT { public int Left; public int Top; public int Right; public int Bottom; }
}
\ No newline at end of file
diff --git a/XCI_Explorer/CertForm.cs b/XCI_Explorer/CertForm.cs
index 24e353a..40b55a4 100644
--- a/XCI_Explorer/CertForm.cs
+++ b/XCI_Explorer/CertForm.cs
@@ -2,19 +2,18 @@
using System.IO;
using System.Windows.Forms;
-namespace XCI_Explorer
+namespace XCI_Explorer;
+
+public partial class CertForm : Form
{
- public partial class CertForm : Form
+ public CertForm(MainForm mainForm)
{
- public CertForm(MainForm mainForm)
- {
- InitializeComponent();
- FileStream fileStream = new FileStream(mainForm.TB_File.Text, FileMode.Open, FileAccess.Read);
- byte[] array = new byte[512];
- fileStream.Position = 28672L;
- fileStream.Read(array, 0, 512);
- hbxHexView.ByteProvider = new DynamicByteProvider(array);
- fileStream.Close();
- }
+ InitializeComponent();
+ FileStream fileStream = new(mainForm.TB_File.Text, FileMode.Open, FileAccess.Read);
+ byte[] array = new byte[512];
+ fileStream.Position = 28672L;
+ fileStream.Read(array, 0, 512);
+ hbxHexView.ByteProvider = new DynamicByteProvider(array);
+ fileStream.Close();
}
}
diff --git a/XCI_Explorer/HFS0.cs b/XCI_Explorer/HFS0.cs
index 761e350..a98e5e6 100644
--- a/XCI_Explorer/HFS0.cs
+++ b/XCI_Explorer/HFS0.cs
@@ -2,51 +2,50 @@ using System;
using System.Linq;
using System.Text;
-namespace XCI_Explorer
+namespace XCI_Explorer;
+
+internal static class HFS0
{
- internal static class HFS0
+ public class HFS0_Header
{
- public class HFS0_Header
+ public byte[] Data;
+ public string Magic;
+ public int FileCount;
+ public int StringTableSize;
+ public int Reserved;
+
+ public HFS0_Header(byte[] data)
{
- public byte[] Data;
- public string Magic;
- public int FileCount;
- public int StringTableSize;
- public int Reserved;
-
- public HFS0_Header(byte[] data)
- {
- Data = data;
- Magic = Encoding.UTF8.GetString(Data.Take(4).ToArray());
- FileCount = BitConverter.ToInt32(data, 4);
- StringTableSize = BitConverter.ToInt32(data, 8);
- Reserved = BitConverter.ToInt32(data, 12);
- }
+ Data = data;
+ Magic = Encoding.UTF8.GetString(Data.Take(4).ToArray());
+ FileCount = BitConverter.ToInt32(data, 4);
+ StringTableSize = BitConverter.ToInt32(data, 8);
+ Reserved = BitConverter.ToInt32(data, 12);
}
-
- public class HSF0_Entry
- {
- public byte[] Data;
- public long Offset;
- public long Size;
- public int Name_ptr;
- public int HashedRegionSize;
- public long Padding;
- public byte[] Hash;
- public string Name;
-
- public HSF0_Entry(byte[] data)
- {
- Data = data;
- Offset = BitConverter.ToInt64(data, 0);
- Size = BitConverter.ToInt64(data, 8);
- Name_ptr = BitConverter.ToInt32(data, 16);
- HashedRegionSize = BitConverter.ToInt32(data, 20);
- Padding = BitConverter.ToInt64(data, 24);
- Hash = Data.Skip(32).Take(32).ToArray();
- }
- }
-
- public static HFS0_Header[] HFS0_Headers = new HFS0_Header[1];
}
+
+ public class HSF0_Entry
+ {
+ public byte[] Data;
+ public long Offset;
+ public long Size;
+ public int Name_ptr;
+ public int HashedRegionSize;
+ public long Padding;
+ public byte[] Hash;
+ public string Name;
+
+ public HSF0_Entry(byte[] data)
+ {
+ Data = data;
+ Offset = BitConverter.ToInt64(data, 0);
+ Size = BitConverter.ToInt64(data, 8);
+ Name_ptr = BitConverter.ToInt32(data, 16);
+ HashedRegionSize = BitConverter.ToInt32(data, 20);
+ Padding = BitConverter.ToInt64(data, 24);
+ Hash = Data.Skip(32).Take(32).ToArray();
+ }
+ }
+
+ public static HFS0_Header[] HFS0_Headers = new HFS0_Header[1];
}
diff --git a/XCI_Explorer/MainForm.cs b/XCI_Explorer/MainForm.cs
index ee92e1d..de1a9e4 100644
--- a/XCI_Explorer/MainForm.cs
+++ b/XCI_Explorer/MainForm.cs
@@ -15,1373 +15,339 @@ using System.Xml.Linq;
using XCI_Explorer.Helpers;
using XTSSharp;
-namespace XCI_Explorer
+namespace XCI_Explorer;
+
+public partial class MainForm : Form
{
- public partial class MainForm : Form
+ public List chars = new();
+ public byte[] NcaHeaderEncryptionKey1_Prod;
+ public byte[] NcaHeaderEncryptionKey2_Prod;
+ public string Mkey;
+ public double UsedSize;
+ private Image[] Icons = new Image[16];
+ private readonly string[] Language = new string[16] {
+ "American English",
+ "British English",
+ "Japanese",
+ "French",
+ "German",
+ "Latin American Spanish",
+ "Spanish",
+ "Italian",
+ "Dutch",
+ "Canadian French",
+ "Portuguese",
+ "Russian",
+ "Korean",
+ "Traditional Chinese",
+ "Simplified Chinese",
+ "???"
+ };
+
+ public MainForm()
{
- public List chars = new List();
- public byte[] NcaHeaderEncryptionKey1_Prod;
- public byte[] NcaHeaderEncryptionKey2_Prod;
- public string Mkey;
- public double UsedSize;
- private Image[] Icons = new Image[16];
- private string[] Language = new string[16] {
- "American English",
- "British English",
- "Japanese",
- "French",
- "German",
- "Latin American Spanish",
- "Spanish",
- "Italian",
- "Dutch",
- "Canadian French",
- "Portuguese",
- "Russian",
- "Korean",
- "Traditional Chinese",
- "Simplified Chinese",
- "???"
- };
+ InitializeComponent();
- public MainForm()
+ Text = $"XCI Explorer v{getAssemblyVersion()}";
+
+ LB_SelectedData.Text = "";
+ LB_DataOffset.Text = "";
+ LB_DataSize.Text = "";
+ LB_HashedRegionSize.Text = "";
+ LB_ActualHash.Text = "";
+ LB_ExpectedHash.Text = "";
+
+ Show();
+
+ //MAC - Set Current Directory to application directory so it can find the keys
+ String startupPath = Application.StartupPath;
+ Directory.SetCurrentDirectory(startupPath);
+
+ if (!File.Exists("keys.txt"))
{
- InitializeComponent();
-
- this.Text = $"XCI Explorer v{getAssemblyVersion()}";
-
- LB_SelectedData.Text = "";
- LB_DataOffset.Text = "";
- LB_DataSize.Text = "";
- LB_HashedRegionSize.Text = "";
- LB_ActualHash.Text = "";
- LB_ExpectedHash.Text = "";
-
- this.Show();
-
- //MAC - Set Current Directory to application directory so it can find the keys
- String startupPath = Application.StartupPath;
- Directory.SetCurrentDirectory(startupPath);
+ new CenterWinDialog(this);
+ if (MessageBox.Show("keys.txt is missing.\nDo you want to automatically download it now?\n\nBy pressing 'Yes' you agree that you own these keys.\n", "XCI Explorer", MessageBoxButtons.YesNo) == DialogResult.Yes)
+ {
+ using HttpClient client = new();
+ using HttpResponseMessage response = client.Send(new HttpRequestMessage(HttpMethod.Get, Util.Base64Decode("aHR0cHM6Ly9wYXN0ZWJpbi5jb20vcmF3LzVnN3cxN2tF")));
+ using Stream stream = response.Content.ReadAsStream();
+ using FileStream fs = new("keys.txt", FileMode.CreateNew);
+ stream.CopyTo(fs);
+ }
if (!File.Exists("keys.txt"))
{
new CenterWinDialog(this);
- if (MessageBox.Show("keys.txt is missing.\nDo you want to automatically download it now?\n\nBy pressing 'Yes' you agree that you own these keys.\n", "XCI Explorer", MessageBoxButtons.YesNo) == DialogResult.Yes)
- {
- using HttpClient client = new();
- using HttpResponseMessage response = client.Send(new HttpRequestMessage(HttpMethod.Get, Util.Base64Decode("aHR0cHM6Ly9wYXN0ZWJpbi5jb20vcmF3L1d1TXZBaTN2")));
- using Stream stream = response.Content.ReadAsStream();
- using FileStream fs = new("keys.txt", FileMode.CreateNew);
- stream.CopyTo(fs);
- }
-
- if (!File.Exists("keys.txt"))
- {
- new CenterWinDialog(this);
- MessageBox.Show("keys.txt failed to load.\nPlease include keys.txt in the root folder.");
- Environment.Exit(0);
- }
- }
-
- if (!File.Exists(Path.Join("tools", "hactool.exe")))
- {
- Directory.CreateDirectory("tools");
- new CenterWinDialog(this);
- MessageBox.Show("hactool.exe is missing.\nPlease include hactool.exe in the 'tools' folder.");
+ MessageBox.Show("keys.txt failed to load.\nPlease include keys.txt in the root folder.");
Environment.Exit(0);
}
-
- getKey();
-
- //MAC - Set the double clicked file name into the UI and process file
- String[] args = Environment.GetCommandLineArgs();
- if (args.Length > 1)
- {
- TB_File.Text = args[1];
- Application.DoEvents();
- ProcessFile();
- }
-
}
- private string getAssemblyVersion()
+ if (!File.Exists(Path.Join("tools", "hactool.exe")))
{
- string assemblyVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
- string[] versionArray = assemblyVersion.Split('.');
-
- assemblyVersion = string.Join(".", versionArray.Take(3));
-
- return assemblyVersion;
+ Directory.CreateDirectory("tools");
+ new CenterWinDialog(this);
+ MessageBox.Show("hactool.exe is missing.\nPlease include hactool.exe in the 'tools' folder.");
+ Environment.Exit(0);
}
- private void getKey()
+ getKey();
+
+ //MAC - Set the double clicked file name into the UI and process file
+ String[] args = Environment.GetCommandLineArgs();
+ if (args.Length > 1)
{
- string text = (from x in File.ReadAllLines("keys.txt")
- select x.Split('=') into x
- where x.Length > 1
- select x).ToDictionary((string[] x) => x[0].Trim(), (string[] x) => x[1])["header_key"].Replace(" ", "");
- NcaHeaderEncryptionKey1_Prod = Util.StringToByteArray(text.Remove(32, 32));
- NcaHeaderEncryptionKey2_Prod = Util.StringToByteArray(text.Remove(0, 32));
+ TB_File.Text = args[1];
+ Application.DoEvents();
+ ProcessFile();
}
- public bool getMKey()
+ }
+
+ private string getAssemblyVersion()
+ {
+ string assemblyVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
+ string[] versionArray = assemblyVersion.Split('.');
+
+ assemblyVersion = string.Join(".", versionArray.Take(3));
+
+ return assemblyVersion;
+ }
+
+ private void getKey()
+ {
+ string text = (from x in File.ReadAllLines("keys.txt")
+ select x.Split('=') into x
+ where x.Length > 1
+ select x).ToDictionary((string[] x) => x[0].Trim(), (string[] x) => x[1])["header_key"].Replace(" ", "");
+ NcaHeaderEncryptionKey1_Prod = Util.StringToByteArray(text.Remove(32, 32));
+ NcaHeaderEncryptionKey2_Prod = Util.StringToByteArray(text.Remove(0, 32));
+ }
+
+ public bool getMKey()
+ {
+ Dictionary dictionary = (from x in File.ReadAllLines("keys.txt")
+ select x.Split('=') into x
+ where x.Length > 1
+ select x).ToDictionary((string[] x) => x[0].Trim(), (string[] x) => x[1]);
+ Mkey = "master_key_";
+ string MkeyL = "master_key_";
+ if (NCA.NCA_Headers[0].MasterKeyRev == 0 || NCA.NCA_Headers[0].MasterKeyRev == 1)
+ {
+ Mkey += "00";
+ }
+ else if (NCA.NCA_Headers[0].MasterKeyRev < 17)
+ {
+ int num = NCA.NCA_Headers[0].MasterKeyRev - 1;
+ string capchar = num.ToString("X");
+ string lowchar = capchar.ToLower();
+ Mkey += $"0{capchar}";
+ MkeyL += $"0{lowchar}";
+ }
+ else if (NCA.NCA_Headers[0].MasterKeyRev >= 17)
+ {
+ int num2 = NCA.NCA_Headers[0].MasterKeyRev - 1;
+ string capchar = num2.ToString("X");
+ string lowchar = capchar.ToLower();
+ Mkey += num2.ToString();
+ MkeyL += num2.ToString();
+ }
+ try
+ {
+ Mkey = dictionary[Mkey].Replace(" ", "");
+ return true;
+ }
+ catch
{
- Dictionary dictionary = (from x in File.ReadAllLines("keys.txt")
- select x.Split('=') into x
- where x.Length > 1
- select x).ToDictionary((string[] x) => x[0].Trim(), (string[] x) => x[1]);
- Mkey = "master_key_";
- string MkeyL = "master_key_";
- if (NCA.NCA_Headers[0].MasterKeyRev == 0 || NCA.NCA_Headers[0].MasterKeyRev == 1)
- {
- Mkey += "00";
- }
- else if (NCA.NCA_Headers[0].MasterKeyRev < 17)
- {
- int num = NCA.NCA_Headers[0].MasterKeyRev - 1;
- string capchar = num.ToString("X");
- string lowchar = capchar.ToLower();
- Mkey += $"0{capchar}";
- MkeyL += $"0{lowchar}";
- }
- else if (NCA.NCA_Headers[0].MasterKeyRev >= 17)
- {
- int num2 = NCA.NCA_Headers[0].MasterKeyRev - 1;
- string capchar = num2.ToString("X");
- string lowchar = capchar.ToLower();
- Mkey += num2.ToString();
- MkeyL += num2.ToString();
- }
try
{
- Mkey = dictionary[Mkey].Replace(" ", "");
+ MkeyL = dictionary[MkeyL].Replace(" ", "");
return true;
}
catch
{
- try
- {
- MkeyL = dictionary[MkeyL].Replace(" ", "");
- return true;
- }
- catch
- {
- return false;
- }
+ return false;
}
}
+ }
- private void ProcessFile()
+ private void ProcessFile()
+ {
+ // Code needs refactoring
+ LB_SelectedData.Text = "";
+ LB_DataOffset.Text = "";
+ LB_DataSize.Text = "";
+ LB_HashedRegionSize.Text = "";
+ LB_ExpectedHash.Text = "";
+ LB_ActualHash.Text = "";
+ B_Extract.Enabled = false;
+
+ try
{
- // Code needs refactoring
- LB_SelectedData.Text = "";
- LB_DataOffset.Text = "";
- LB_DataSize.Text = "";
- LB_HashedRegionSize.Text = "";
- LB_ExpectedHash.Text = "";
- LB_ActualHash.Text = "";
- B_Extract.Enabled = false;
-
- try
- {
- if (CheckNSP())
- {
- B_TrimXCI.Enabled = false;
- B_ExportCert.Enabled = false;
- B_ImportCert.Enabled = false;
- B_ViewCert.Enabled = false;
- B_ClearCert.Enabled = false;
-
- LoadNSP();
- }
- else if (CheckXCI())
- {
- B_TrimXCI.Enabled = true;
- B_ExportCert.Enabled = true;
- B_ImportCert.Enabled = true;
- B_ViewCert.Enabled = true;
- B_ClearCert.Enabled = true;
-
- LoadXCI();
- }
- else
- {
- TB_File.Text = null;
- new CenterWinDialog(this);
- MessageBox.Show("File is corrupt or unsupported.");
- }
- }
- catch (Exception e)
- {
- new CenterWinDialog(this);
- MessageBox.Show($"Error: {e.ToString()}\nFile is corrupt or unsupported.");
- }
-
- }
-
- private void B_LoadROM_Click(object sender, EventArgs e)
- {
- OpenFileDialog openFileDialog = new OpenFileDialog();
- openFileDialog.Filter = "Switch Game File (*.xci, *.nsp, *.nsz)|*.xci;*.nsp;*.nsz|All Files (*.*)|*.*";
- new CenterWinDialog(this);
- if (openFileDialog.ShowDialog() == DialogResult.OK)
- {
- TB_File.Text = openFileDialog.FileName;
- ProcessFile();
- }
- }
-
- private void LoadXCI()
- {
- string[] array = new string[5]
- {
- "B",
- "KB",
- "MB",
- "GB",
- "TB"
- };
- double num = (double)new FileInfo(TB_File.Text).Length;
- TB_ROMExactSize.Text = $"({num} bytes)";
- int num2 = 0;
- while (num >= 1024.0 && num2 < array.Length - 1)
- {
- num2++;
- num /= 1024.0;
- }
- TB_ROMSize.Text = $"{num:0.##} {array[num2]}";
- double num3 = UsedSize = (double)(XCI.XCI_Headers[0].CardSize2 * 512 + 512);
- TB_ExactUsedSpace.Text = $"({num3} bytes)";
- if (isTrimmed())
+ if (CheckNSP())
{
B_TrimXCI.Enabled = false;
+ B_ExportCert.Enabled = false;
+ B_ImportCert.Enabled = false;
+ B_ViewCert.Enabled = false;
+ B_ClearCert.Enabled = false;
+
+ LoadNSP();
}
-
- num2 = 0;
- while (num3 >= 1024.0 && num2 < array.Length - 1)
+ else if (CheckXCI())
{
- num2++;
- num3 /= 1024.0;
- }
- TB_UsedSpace.Text = $"{num3:0.##} {array[num2]}";
- TB_Capacity.Text = Util.GetCapacity(XCI.XCI_Headers[0].CardSize1);
- LoadPartitions();
- LoadNCAData();
- LoadGameInfos();
- }
+ B_TrimXCI.Enabled = true;
+ B_ExportCert.Enabled = true;
+ B_ImportCert.Enabled = true;
+ B_ViewCert.Enabled = true;
+ B_ClearCert.Enabled = true;
- // Giba's better implementation (more native)
- public void LoadNSP()
- {
- CB_RegionName.Items.Clear();
- CB_RegionName.Enabled = true;
- TB_TID.Text = "";
- TB_Capacity.Text = "";
- TB_MKeyRev.Text = "";
- TB_SDKVer.Text = "";
- TB_GameRev.Text = "";
- TB_ProdCode.Text = "";
- TB_Name.Text = "";
- TB_Dev.Text = "";
-
- int basenum = 0;
- int updnum = 0;
- int dlcnum = 0;
- string pversion = "";
- int patchflag = 0;
- int patchnum = 0;
- string patchver = "";
- int baseflag = 0;
- string[] basetitle = new string[5];
- string[] updtitle = new string[10];
- string[] dlctitle = new string[300];
-
- PB_GameIcon.BackgroundImage = null;
- Array.Clear(Icons, 0, Icons.Length);
- TV_Partitions.Nodes.Clear();
- FileInfo fi = new FileInfo(TB_File.Text);
- string contentType = "";
-
- // Maximum number of files in NSP to read in
- const int MAXFILES = 250;
-
- //Get File Size
- string[] array_fs = new string[5] { "B", "KB", "MB", "GB", "TB" };
- double num_fs = (double)fi.Length;
- int num2_fs = 0;
- TB_ROMExactSize.Text = $"({num_fs} bytes)";
- TB_ExactUsedSpace.Text = TB_ROMExactSize.Text;
-
- while (num_fs >= 1024.0 && num2_fs < array_fs.Length - 1)
- {
- num2_fs++;
- num_fs /= 1024.0;
- }
- TB_ROMSize.Text = $"{num_fs:0.##} {array_fs[num2_fs]}";
- TB_UsedSpace.Text = TB_ROMSize.Text;
-
- LoadNSPPartitions();
-
- Process process = new Process();
- try
- {
- FileStream fileStream = File.OpenRead(TB_File.Text);
- string ncaTarget = "";
- string xmlVersion = "";
-
- List chars = new List();
- byte[] array = new byte[16];
- byte[] array2 = new byte[24];
- fileStream.Read(array, 0, 16);
- PFS0.PFS0_Headers[0] = new PFS0.PFS0_Header(array);
- if (!PFS0.PFS0_Headers[0].Magic.Contains("PFS0"))
- {
- return;
- }
- PFS0.PFS0_Entry[] array3;
- array3 = new PFS0.PFS0_Entry[Math.Max(PFS0.PFS0_Headers[0].FileCount, MAXFILES)]; //Dump of TitleID 01009AA000FAA000 reports more than 10000000 files here, so it breaks the program. Standard is to have only 20 files
-
- for (int m = 0; m < PFS0.PFS0_Headers[0].FileCount; m++)
- {
- fileStream.Position = 16 + 24 * m;
- fileStream.Read(array2, 0, 24);
- array3[m] = new PFS0.PFS0_Entry(array2);
-
- if (m == MAXFILES - 1) //Dump of TitleID 01009AA000FAA000 reports more than 10000000 files here, so it breaks the program. Standard is to have only 20 files
- {
- break;
- }
- }
- for (int n = 0; n < PFS0.PFS0_Headers[0].FileCount; n++)
- {
- fileStream.Position = 16 + 24 * PFS0.PFS0_Headers[0].FileCount + array3[n].Name_ptr;
- int num4;
- while ((num4 = fileStream.ReadByte()) != 0 && num4 != 0)
- {
- chars.Add((char)num4);
- }
- array3[n].Name = new string(chars.ToArray());
- chars.Clear();
-
- if (array3[n].Name.EndsWith(".cnmt.xml"))
- {
- byte[] array4 = new byte[array3[n].Size];
- fileStream.Position = 16 + 24 * PFS0.PFS0_Headers[0].FileCount + PFS0.PFS0_Headers[0].StringTableSize + array3[n].Offset;
- fileStream.Read(array4, 0, (int)array3[n].Size);
-
- XDocument xml = XDocument.Parse(Encoding.UTF8.GetString(array4));
- TB_TID.Text = xml.Element("ContentMeta").Element("Id").Value.Remove(1, 2).ToUpper(); //id
- pversion = xml.Element("ContentMeta").Element("Version").Value; //version
- contentType = xml.Element("ContentMeta").Element("Type").Value; //content
-
- if (contentType == "Patch")
- {
- patchflag = 1;
- if (System.Convert.ToInt32(pversion) > patchnum)
- {
- patchnum = System.Convert.ToInt32(pversion);
- xmlVersion = $"v{xml.Element("ContentMeta").Element("Version").Value}";
- int number = System.Convert.ToInt32(pversion);
- patchver = $"v{System.Convert.ToString((double)number / 65536)}";
- }
-
- updtitle[updnum] = $"[{TB_TID.Text}][v{pversion}]";
- updnum++;
- }
- else if (contentType == "Application")
- {
- baseflag = 1;
- if (patchflag != 1)
- {
- xmlVersion = $"v{xml.Element("ContentMeta").Element("Version").Value}";
- }
-
- basetitle[basenum] = $"[{TB_TID.Text}][v{pversion}]";
- basenum++;
- }
- else
- {
- if (baseflag == 0 && patchflag == 0)
- {
- xmlVersion = $"v{xml.Element("ContentMeta").Element("Version").Value}";
- }
-
- dlctitle[dlcnum] = $"[{TB_TID.Text}][v{pversion}]";
- dlcnum++;
- }
-
- if (contentType != "AddOnContent")
- {
- foreach (XElement xe in xml.Descendants("Content"))
- {
- if (xe.Element("Type").Value != "Control")
- {
- continue;
- }
-
- ncaTarget = $"{xe.Element("Id").Value}.nca";
- break;
- }
- }
- else //This is a DLC
- {
- foreach (XElement xe in xml.Descendants("Content"))
- {
- if (xe.Element("Type").Value != "Meta")
- {
- continue;
- }
-
- ncaTarget = $"{xe.Element("Id").Value}.cnmt.nca";
- break;
- }
- }
- }
-
- if (n == MAXFILES - 1) //Dump of TitleID 01009AA000FAA000 reports more than 10000000 files here, so it breaks the program. Standard is to have only 20 files
- {
- break;
- }
- }
-
- if (String.IsNullOrEmpty(ncaTarget))
- {
- //Missing content metadata xml. Read from content metadata nca instead
- for (int n = 0; n < PFS0.PFS0_Headers[0].FileCount; n++)
- {
- if (array3[n].Name.EndsWith(".cnmt.nca"))
- {
- try
- {
- File.Delete("meta");
- Directory.Delete("data", true);
- }
- catch { }
-
- using (FileStream fileStream2 = File.OpenWrite("meta"))
- {
- fileStream.Position = 16 + 24 * PFS0.PFS0_Headers[0].FileCount + PFS0.PFS0_Headers[0].StringTableSize + array3[n].Offset;
- byte[] buffer = new byte[8192];
- long num = array3[n].Size;
- int num4;
- while ((num4 = fileStream.Read(buffer, 0, 8192)) > 0 && num > 0)
- {
- fileStream2.Write(buffer, 0, num4);
- num -= num4;
- }
- fileStream2.Close();
- }
-
- process = new Process();
- process.StartInfo = new ProcessStartInfo
- {
- WindowStyle = ProcessWindowStyle.Hidden,
- FileName = Path.Join("tools", "hactool.exe"),
- Arguments = "-k keys.txt --section0dir=data meta",
- UseShellExecute = false,
- RedirectStandardOutput = true,
- CreateNoWindow = true
- };
- process.Start();
-
- string masterkey = "";
- while (!process.StandardOutput.EndOfStream)
- {
- string output = process.StandardOutput.ReadLine();
- if (output.StartsWith("Master Key Revision"))
- {
- masterkey = Regex.Replace(output, @"\s+", " ");
- }
- }
- process.WaitForExit();
-
- if (!Directory.Exists("data"))
- {
- new CenterWinDialog(this);
- MessageBox.Show($"{masterkey} is missing!");
- }
- else
- {
- try
- {
- string[] cnmt = Directory.GetFiles("data", "*.cnmt");
- if (cnmt.Length != 0)
- {
- using (FileStream fileStream3 = File.OpenRead(cnmt[0]))
- {
- byte[] buffer = new byte[32];
- byte[] buffer2 = new byte[56];
- CNMT.CNMT_Header[] array7 = new CNMT.CNMT_Header[1];
-
- fileStream3.Read(buffer, 0, 32);
- array7[0] = new CNMT.CNMT_Header(buffer);
-
- byte[] TitleID = BitConverter.GetBytes(array7[0].TitleID);
- Array.Reverse(TitleID);
- TB_TID.Text = BitConverter.ToString(TitleID).Replace("-", "");
-
- if (array7[0].Type == (byte)CNMT.CNMT_Header.TitleType.REGULAR_APPLICATION)
- {
- contentType = "Application";
- baseflag = 1;
- if (patchflag != 1)
- {
- xmlVersion = $"v{array7[0].TitleVersion.ToString()}";
- }
-
- basetitle[basenum] = $"[{TB_TID.Text}][v{array7[0].TitleVersion.ToString()}]";
- basenum++;
- }
- else if (array7[0].Type == (byte)CNMT.CNMT_Header.TitleType.UPDATE_TITLE)
- {
- contentType = "Patch";
-
- patchflag = 1;
- if (array7[0].TitleVersion > patchnum)
- {
- patchnum = array7[0].TitleVersion;
- xmlVersion = $"v{array7[0].TitleVersion.ToString()}";
- int number = System.Convert.ToInt32(array7[0].TitleVersion);
- patchver = $"v{System.Convert.ToString((double)number / 65536)}";
- }
-
- updtitle[updnum] = $"[{TB_TID.Text}][v{array7[0].TitleVersion.ToString()}]";
- updnum++;
- }
- else if (array7[0].Type == (byte)CNMT.CNMT_Header.TitleType.ADD_ON_CONTENT)
- {
- if (baseflag == 0 && patchflag == 0)
- {
- xmlVersion = $"v{array7[0].TitleVersion.ToString()}";
- }
-
- contentType = "AddOnContent";
- dlctitle[dlcnum] = $"[{TB_TID.Text}][v{array7[0].TitleVersion.ToString()}]";
- dlcnum++;
- }
-
- fileStream3.Position = array7[0].Offset + 32;
- CNMT.CNMT_Entry[] array9 = new CNMT.CNMT_Entry[array7[0].ContentCount];
- for (int k = 0; k < array7[0].ContentCount; k++)
- {
- fileStream3.Read(buffer2, 0, 56);
- array9[k] = new CNMT.CNMT_Entry(buffer2);
- if (array9[k].Type == (byte)CNMT.CNMT_Entry.ContentType.CONTROL || array9[k].Type == (byte)CNMT.CNMT_Entry.ContentType.DATA)
- {
- ncaTarget = $"{BitConverter.ToString(array9[k].NcaId).ToLower().Replace("-", "")}.nca";
- break;
- }
- }
-
- fileStream3.Close();
- }
- }
- }
- catch { }
- }
- }
- }
- }
-
- for (int n = 0; n < PFS0.PFS0_Headers[0].FileCount; n++)
- {
- if (array3[n].Name.Equals(ncaTarget))
- {
- Directory.CreateDirectory("tmp");
-
- byte[] array5 = new byte[64 * 1024];
- fileStream.Position = 16 + 24 * PFS0.PFS0_Headers[0].FileCount + PFS0.PFS0_Headers[0].StringTableSize + array3[n].Offset;
-
- using (Stream output = File.Create(Path.Join("tmp", ncaTarget)))
- {
- long Size = array3[n].Size;
- int result = 0;
- while ((result = fileStream.Read(array5, 0, (int)Math.Min(array5.Length, Size))) > 0)
- {
- output.Write(array5, 0, result);
- Size -= result;
- }
- }
-
- break;
- }
-
- if (n == MAXFILES - 1) //Dump of TitleID 01009AA000FAA000 reports more than 10000000 files here, so it breaks the program. Standard is to have only 20 files
- {
- break;
- }
- }
-
- fileStream.Close();
-
- if (contentType != "AddOnContent")
- {
- process = new Process();
- process.StartInfo = new ProcessStartInfo
- {
- WindowStyle = ProcessWindowStyle.Hidden,
- FileName = Path.Join("tools", "hactool.exe"),
- Arguments = $"-k keys.txt --romfsdir=tmp tmp/{ncaTarget}",
- UseShellExecute = false,
- CreateNoWindow = true
- };
-
- process.Start();
- process.WaitForExit();
- process.Close();
- byte[] flux = new byte[200];
-
- try
- {
- byte[] source = File.ReadAllBytes(Path.Join("tmp", "control.nacp"));
- NACP.NACP_Datas[0] = new NACP.NACP_Data(source.Skip(0x3000).Take(0x1000).ToArray());
-
- for (int i = 0; i < NACP.NACP_Strings.Length; i++)
- {
- NACP.NACP_Strings[i] = new NACP.NACP_String(source.Skip(i * 0x300).Take(0x300).ToArray());
-
- if (NACP.NACP_Strings[i].Check != 0)
- {
- CB_RegionName.Items.Add(Language[i]);
- string icon_filename = Path.Join("tmp", $"icon_{Language[i].Replace(" ", "")}.dat");
- if (File.Exists(icon_filename))
- {
- using (Bitmap original = new Bitmap(icon_filename))
- {
- Icons[i] = new Bitmap(original);
- PB_GameIcon.BackgroundImage = Icons[i];
- }
- }
- }
- }
-
- string gameVer = NACP.NACP_Datas[0].GameVer.Replace("\0", "");
- if (xmlVersion.Trim() == "")
- {
- TB_GameRev.Text = $"GENERAL:{Environment.NewLine}({gameVer}){Environment.NewLine}";
- }
- else
- {
- string cache = $"GENERAL:{Environment.NewLine}{gameVer}{((patchflag == 1) ? $" ({patchver})" : "")}{Environment.NewLine}";
-
- if (basenum != 0)
- {
- cache += $"BASE:{Environment.NewLine}";
- for (int i = 0; i < basenum; i++)
- {
- cache += basetitle[i] + Environment.NewLine;
- }
- }
- else
- {
- cache += $"BASE:{System.Environment.NewLine}EMPTY{System.Environment.NewLine}";
- }
- if (updnum != 0)
- {
- cache += $"UPD:{System.Environment.NewLine}";
- for (int i = 0; i < updnum; i++)
- {
- cache += updtitle[i] + System.Environment.NewLine;
- }
- }
- else
- {
- cache += $"UPD:{System.Environment.NewLine}EMPTY{System.Environment.NewLine}";
- }
- if (dlcnum != 0)
- {
- cache += $"DLC:{System.Environment.NewLine}";
- for (int i = 0; i < dlcnum; i++)
- {
- if (i < dlcnum - 1)
- {
- cache += dlctitle[i] + System.Environment.NewLine;
- }
- else
- {
- cache += dlctitle[i];
- }
- }
- }
- else
- {
- cache += $"DLC:{System.Environment.NewLine}EMPTY";
- }
- TB_GameRev.Text = cache;
- label12.Text = $"{basenum.ToString()} BASE, {updnum.ToString()} UPD, {dlcnum.ToString()} DLC";
- }
-
- TB_ProdCode.Text = NACP.NACP_Datas[0].GameProd.Replace("\0", "");
- if (TB_ProdCode.Text == "")
- {
- TB_ProdCode.Text = "No Prod. ID";
- }
-
- for (int z = 0; z < NACP.NACP_Strings.Length; z++)
- {
- if (NACP.NACP_Strings[z].GameName.Replace("\0", "") != "")
- {
- TB_Name.Text = NACP.NACP_Strings[z].GameName.Replace("\0", "");
- break;
- }
- }
- for (int z = 0; z < NACP.NACP_Strings.Length; z++)
- {
- if (NACP.NACP_Strings[z].GameAuthor.Replace("\0", "") != "")
- {
- TB_Dev.Text = NACP.NACP_Strings[z].GameAuthor.Replace("\0", "");
- break;
- }
- }
- }
- catch { }
-
- }
- else
- {
- if (xmlVersion.Trim() == "")
- {
- TB_GameRev.Text = $"GENERAL:{System.Environment.NewLine}{System.Environment.NewLine}";
- }
- else
- {
- string gameVer = NACP.NACP_Datas[0].GameVer.Replace("\0", "");
- string cache = $"GENERAL:{Environment.NewLine}{gameVer}{((patchflag == 1) ? $" ({patchver})" : "")}{Environment.NewLine}";
-
- if (basenum != 0)
- {
- cache += $"BASE:{System.Environment.NewLine}";
- for (int i = 0; i < basenum; i++)
- {
- cache += basetitle[i] + System.Environment.NewLine;
- }
- }
- else
- {
- cache += $"BASE:{System.Environment.NewLine}EMPTY{System.Environment.NewLine}";
- }
- if (updnum != 0)
- {
- cache += $"UPD:{System.Environment.NewLine}";
- for (int i = 0; i < updnum; i++)
- {
- cache += updtitle[i] + System.Environment.NewLine;
- }
- }
- else
- {
- cache += $"UPD:{System.Environment.NewLine}EMPTY{System.Environment.NewLine}";
- }
- if (dlcnum != 0)
- {
- cache += $"DLC:{System.Environment.NewLine}";
- for (int i = 0; i < dlcnum; i++)
- {
- if (i < dlcnum - 1)
- {
- cache += dlctitle[i] + System.Environment.NewLine;
- }
- else
- {
- cache += dlctitle[i];
- }
- }
- }
- else
- {
- cache += $"DLC:{System.Environment.NewLine}EMPTY";
- }
- TB_GameRev.Text = cache;
- label12.Text = $"{basenum.ToString()} BASE, {updnum.ToString()} UPD, {dlcnum.ToString()} DLC";
- }
- TB_ProdCode.Text = "No Prod. ID";
- }
-
- // Lets get SDK Version, Distribution Type and Masterkey revision
- // This is far from the best aproach, but it's what we have for now
- process = new Process();
- process.StartInfo = new ProcessStartInfo
- {
- WindowStyle = ProcessWindowStyle.Hidden,
- FileName = Path.Join("tools", "hactool.exe"),
- Arguments = $"-k keys.txt tmp/{ncaTarget}",
- RedirectStandardOutput = true,
- UseShellExecute = false,
- CreateNoWindow = true
- };
- process.Start();
- StreamReader sr = process.StandardOutput;
-
- while (sr.Peek() >= 0)
- {
- string str;
- string[] strArray;
- str = sr.ReadLine();
- strArray = str.Split(':');
- if (strArray[0] == "SDK Version")
- {
- TB_SDKVer.Text = strArray[1].Trim();
- }
- else if (strArray[0] == "Master Key Revision")
- {
- string MasterKey = strArray[1].Trim();
- int keyblob;
-
- MasterKey = MasterKey.Split(new char[2] { 'x', ' ' })[1];
- keyblob = Convert.ToInt32(MasterKey, 16);
- MasterKey = Util.GetMkey((byte)(keyblob + 1));
- TB_MKeyRev.Text = MasterKey;
- break;
- }
- }
- process.WaitForExit();
- process.Close();
- }
- catch { }
-
- try
- {
- File.Delete("meta");
- Directory.Delete("data", true);
- }
- catch { }
-
- try
- {
- Directory.Delete("tmp", true);
- }
- catch { }
-
- TB_Capacity.Text = "eShop";
-
- if (TB_Name.Text.Trim() != "")
- {
- CB_RegionName.SelectedIndex = 0;
- }
- }
-
- private void LoadGameInfos()
- {
- CB_RegionName.Items.Clear();
- CB_RegionName.Enabled = true;
- TB_Name.Text = "";
- TB_Dev.Text = "";
- PB_GameIcon.BackgroundImage = null;
-
- int basenum = 0;
- int updnum = 0;
- int dlcnum = 0;
- int patchflag = 0;
- int patchnum = 0;
- string patchver = "";
- int baseflag = 0;
- string[] basetitle = new string[5];
- string[] updtitle = new string[10];
- string[] dlctitle = new string[300];
- string xmlVersion = "";
- string saveTID = "";
-
- Array.Clear(Icons, 0, Icons.Length);
- if (getMKey())
- {
- using (FileStream fileStream = File.OpenRead(TB_File.Text))
- {
- List ncaTarget = new List();
- string GameRevision = "";
-
- for (int si = 0; si < SecureSize.Length; si++)
- {
- if (SecureSize[si] > 0x4E20000)
- {
- continue;
- }
-
- if (SecureName[si].EndsWith(".cnmt.nca"))
- {
- try
- {
- File.Delete("meta");
- Directory.Delete("data", true);
- }
- catch { }
-
- using (FileStream fileStream2 = File.OpenWrite("meta"))
- {
- fileStream.Position = SecureOffset[si];
- byte[] buffer = new byte[8192];
- long num = SecureSize[si];
- int num4;
- while ((num4 = fileStream.Read(buffer, 0, 8192)) > 0 && num > 0)
- {
- fileStream2.Write(buffer, 0, num4);
- num -= num4;
- }
- fileStream2.Close();
- }
-
- Process process1 = new Process();
- process1.StartInfo = new ProcessStartInfo
- {
- WindowStyle = ProcessWindowStyle.Hidden,
- FileName = Path.Join("tools", "hactool.exe"),
- Arguments = "-k keys.txt --section0dir=data meta",
- UseShellExecute = false,
- CreateNoWindow = true
- };
- process1.Start();
- process1.WaitForExit();
-
- string[] cnmt = Directory.GetFiles("data", "*.cnmt");
-
- if (cnmt.Length != 0)
- {
- using (FileStream fileStream3 = File.OpenRead(cnmt[0]))
- {
- byte[] buffer = new byte[32];
- byte[] buffer2 = new byte[56];
- CNMT.CNMT_Header[] array7 = new CNMT.CNMT_Header[1];
-
- fileStream3.Read(buffer, 0, 32);
- array7[0] = new CNMT.CNMT_Header(buffer);
-
- byte[] TitleID = BitConverter.GetBytes(array7[0].TitleID);
- Array.Reverse(TitleID);
- saveTID = BitConverter.ToString(TitleID).Replace("-", "");
-
- if (array7[0].Type == (byte)CNMT.CNMT_Header.TitleType.REGULAR_APPLICATION)
- {
- baseflag = 1;
- if (patchflag != 1)
- {
- xmlVersion = $"v{array7[0].TitleVersion.ToString()}";
- }
-
- basetitle[basenum] = $"[{saveTID}][v{array7[0].TitleVersion.ToString()}]";
- basenum++;
- }
- else if (array7[0].Type == (byte)CNMT.CNMT_Header.TitleType.UPDATE_TITLE)
- {
- patchflag = 1;
- if (array7[0].TitleVersion > patchnum)
- {
- patchnum = array7[0].TitleVersion;
- xmlVersion = $"v{array7[0].TitleVersion.ToString()}";
- int number = System.Convert.ToInt32(array7[0].TitleVersion);
- patchver = $"v{System.Convert.ToString((double)number / 65536)}";
- }
-
- updtitle[updnum] = $"[{saveTID}][v{array7[0].TitleVersion.ToString()}]";
- updnum++;
- }
- else if (array7[0].Type == (byte)CNMT.CNMT_Header.TitleType.ADD_ON_CONTENT)
- {
- if (patchflag == 0 && baseflag == 0)
- {
- xmlVersion = $"v{array7[0].TitleVersion.ToString()}";
- }
-
- dlctitle[dlcnum] = $"[{saveTID}][v{array7[0].TitleVersion.ToString()}]";
- dlcnum++;
- }
-
- fileStream3.Position = array7[0].Offset + 32;
- CNMT.CNMT_Entry[] array9 = new CNMT.CNMT_Entry[array7[0].ContentCount];
- for (int k = 0; k < array7[0].ContentCount; k++)
- {
- fileStream3.Read(buffer2, 0, 56);
- array9[k] = new CNMT.CNMT_Entry(buffer2);
- if (array9[k].Type == (byte)CNMT.CNMT_Entry.ContentType.CONTROL || array9[k].Type == (byte)CNMT.CNMT_Entry.ContentType.DATA)
- {
- ncaTarget.Add($"{BitConverter.ToString(array9[k].NcaId).ToLower().Replace("-", "")}.nca");
- break;
- }
- }
- fileStream3.Close();
- }
- }
- }
- }
-
- for (int si = 0; si < SecureSize.Length; si++)
- {
- if (SecureSize[si] > 0x4E20000)
- {
- continue;
- }
-
- if (ncaTarget.Contains(SecureName[si]))
- {
- try
- {
- File.Delete("meta");
- Directory.Delete("data", true);
- }
- catch { }
-
- using (FileStream fileStream2 = File.OpenWrite("meta"))
- {
- fileStream.Position = SecureOffset[si];
- byte[] buffer = new byte[8192];
- long num = SecureSize[si];
- int num2;
- while ((num2 = fileStream.Read(buffer, 0, 8192)) > 0 && num > 0)
- {
- fileStream2.Write(buffer, 0, num2);
- num -= num2;
- }
- fileStream2.Close();
- }
-
-
- Process process = new Process();
- process.StartInfo = new ProcessStartInfo
- {
- WindowStyle = ProcessWindowStyle.Hidden,
- FileName = Path.Join("tools", "hactool.exe"),
- Arguments = "-k keys.txt --romfsdir=data meta",
- UseShellExecute = false,
- CreateNoWindow = true
- };
- process.Start();
- process.WaitForExit();
-
- if (File.Exists(Path.Join("data", "control.nacp")))
- {
- byte[] source = File.ReadAllBytes(Path.Join("data", "control.nacp"));
- NACP.NACP_Datas[0] = new NACP.NACP_Data(source.Skip(0x3000).Take(0x1000).ToArray());
-
- string GameVer = NACP.NACP_Datas[0].GameVer.Replace("\0", "");
- Version version1, version2;
- if (!Version.TryParse(Regex.Replace(GameRevision, @"[^\d.].*$", ""), out version1))
- {
- version1 = new Version();
- }
- if (!Version.TryParse(Regex.Replace(GameVer, @"[^\d.].*$", ""), out version2))
- {
- version2 = new Version();
- }
- if (version2.CompareTo(version1) > 0)
- {
- GameRevision = GameVer;
-
- for (int i = 0; i < NACP.NACP_Strings.Length; i++)
- {
- NACP.NACP_Strings[i] = new NACP.NACP_String(source.Skip(i * 0x300).Take(0x300).ToArray());
- if (NACP.NACP_Strings[i].Check != 0 && !CB_RegionName.Items.Contains(Language[i]))
- {
- CB_RegionName.Items.Add(Language[i]);
- string icon_filename = Path.Join("data", $"icon_{Language[i].Replace(" ", "")}.dat");
- if (File.Exists(icon_filename))
- {
- using (Bitmap original = new Bitmap(icon_filename))
- {
- Icons[i] = new Bitmap(original);
- PB_GameIcon.BackgroundImage = Icons[i];
- }
- }
- }
- }
- TB_ProdCode.Text = NACP.NACP_Datas[0].GameProd;
- if (TB_ProdCode.Text == "")
- {
- TB_ProdCode.Text = "No Prod. ID";
- }
- try
- {
- File.Delete("meta");
- Directory.Delete("data", true);
- }
- catch { }
- }
- }
- }
- }
-
- string gameVer = NACP.NACP_Datas[0].GameVer.Replace("\0", "");
- string cache = $"GENERAL:{Environment.NewLine}{gameVer}{((patchflag == 1) ? $" ({patchver})" : "")}{Environment.NewLine}";
-
- if (basenum != 0)
- {
- cache += $"BASE:{System.Environment.NewLine}";
- for (int i = 0; i < basenum; i++)
- {
- cache += basetitle[i] + System.Environment.NewLine;
- }
- }
- else
- {
- cache += $"BASE:{System.Environment.NewLine}EMPTY{System.Environment.NewLine}";
- }
- if (updnum != 0)
- {
- cache += $"UPD:{System.Environment.NewLine}";
- for (int i = 0; i < updnum; i++)
- {
- cache += updtitle[i] + System.Environment.NewLine;
- }
- }
- else
- {
- cache += $"UPD:{System.Environment.NewLine}EMPTY{System.Environment.NewLine}";
- }
- if (dlcnum != 0)
- {
- cache += $"DLC:{System.Environment.NewLine}";
- for (int i = 0; i < dlcnum; i++)
- {
- if (i < dlcnum - 1)
- {
- cache += dlctitle[i] + System.Environment.NewLine;
- }
- else
- {
- cache += dlctitle[i];
- }
- }
- }
- else
- {
- cache += $"DLC:{System.Environment.NewLine}EMPTY";
- }
- TB_GameRev.Text = cache;
- label12.Text = $"{basenum.ToString()} BASE, {updnum.ToString()} UPD, {dlcnum.ToString()} DLC";
-
- CB_RegionName.SelectedIndex = 0;
-
- fileStream.Close();
- }
+ LoadXCI();
}
else
{
- TB_Dev.Text = $"{Mkey} not found";
- TB_Name.Text = $"{Mkey} not found";
+ TB_File.Text = null;
+ new CenterWinDialog(this);
+ MessageBox.Show("File is corrupt or unsupported.");
}
}
-
- private void LoadNCAData()
+ catch (Exception e)
{
- NCA.NCA_Headers[0] = new NCA.NCA_Header(DecryptNCAHeader(gameNcaOffset));
- TB_TID.Text = $"0{NCA.NCA_Headers[0].TitleID.ToString("X")}";
- TB_SDKVer.Text = $"{NCA.NCA_Headers[0].SDKVersion4}.{NCA.NCA_Headers[0].SDKVersion3}.{NCA.NCA_Headers[0].SDKVersion2}.{NCA.NCA_Headers[0].SDKVersion1}";
- TB_MKeyRev.Text = Util.GetMkey(NCA.NCA_Headers[0].MasterKeyRev);
+ new CenterWinDialog(this);
+ MessageBox.Show($"File is corrupt or unsupported.\nException: {e.Message}");
}
- //https://stackoverflow.com/questions/311165/how-do-you-convert-a-byte-array-to-a-hexadecimal-string-and-vice-versa
- public static string ByteArrayToString(byte[] ba)
- {
- StringBuilder hex = new StringBuilder(ba.Length * 2 + 2);
- hex.Append("0x");
- foreach (byte b in ba)
- {
- hex.AppendFormat("{0:x2}", b);
- }
+ }
- return hex.ToString();
+ private void B_LoadROM_Click(object sender, EventArgs e)
+ {
+ OpenFileDialog openFileDialog = new()
+ {
+ Filter = "Switch Game File (*.xci, *.nsp, *.nsz)|*.xci;*.nsp;*.nsz|All Files (*.*)|*.*"
+ };
+ new CenterWinDialog(this);
+ if (openFileDialog.ShowDialog() == DialogResult.OK)
+ {
+ TB_File.Text = openFileDialog.FileName;
+ ProcessFile();
+ }
+ }
+
+ private void LoadXCI()
+ {
+ string[] array = new string[5]
+ {
+ "B",
+ "KB",
+ "MB",
+ "GB",
+ "TB"
+ };
+ double num = new FileInfo(TB_File.Text).Length;
+ TB_ROMExactSize.Text = $"({num} bytes)";
+ int num2 = 0;
+ while (num >= 1024.0 && num2 < array.Length - 1)
+ {
+ num2++;
+ num /= 1024.0;
+ }
+ TB_ROMSize.Text = $"{num:0.##} {array[num2]}";
+ double num3 = UsedSize = XCI.XCI_Headers[0].CardSize2 * 512 + 512;
+ TB_ExactUsedSpace.Text = $"({num3} bytes)";
+ if (isTrimmed())
+ {
+ B_TrimXCI.Enabled = false;
}
- public static string SHA256Bytes(byte[] ba)
+ num2 = 0;
+ while (num3 >= 1024.0 && num2 < array.Length - 1)
{
- SHA256 mySHA256 = SHA256.Create();
- byte[] hashValue;
- hashValue = mySHA256.ComputeHash(ba);
- return ByteArrayToString(hashValue);
+ num2++;
+ num3 /= 1024.0;
}
+ TB_UsedSpace.Text = $"{num3:0.##} {array[num2]}";
+ TB_Capacity.Text = Util.GetCapacity(XCI.XCI_Headers[0].CardSize1);
+ LoadPartitions();
+ LoadNCAData();
+ LoadGameInfos();
+ }
- public bool isTrimmed()
+ // Giba's better implementation (more native)
+ public void LoadNSP()
+ {
+ CB_RegionName.Items.Clear();
+ CB_RegionName.Enabled = true;
+ TB_TID.Text = "";
+ TB_Capacity.Text = "";
+ TB_MKeyRev.Text = "";
+ TB_SDKVer.Text = "";
+ TB_GameRev.Text = "";
+ TB_ProdCode.Text = "";
+ TB_Name.Text = "";
+ TB_Dev.Text = "";
+
+ int basenum = 0;
+ int updnum = 0;
+ int dlcnum = 0;
+ string pversion = "";
+ int patchflag = 0;
+ int patchnum = 0;
+ string patchver = "";
+ int baseflag = 0;
+ string[] basetitle = new string[5];
+ string[] updtitle = new string[10];
+ string[] dlctitle = new string[300];
+
+ PB_GameIcon.BackgroundImage = null;
+ Array.Clear(Icons, 0, Icons.Length);
+ TV_Partitions.Nodes.Clear();
+ FileInfo fi = new(TB_File.Text);
+ string contentType = "";
+
+ // Maximum number of files in NSP to read in
+ const int MAXFILES = 250;
+
+ //Get File Size
+ string[] array_fs = new string[5] { "B", "KB", "MB", "GB", "TB" };
+ double num_fs = fi.Length;
+ int num2_fs = 0;
+ TB_ROMExactSize.Text = $"({num_fs} bytes)";
+ TB_ExactUsedSpace.Text = TB_ROMExactSize.Text;
+
+ while (num_fs >= 1024.0 && num2_fs < array_fs.Length - 1)
{
- return TB_ROMExactSize.Text == TB_ExactUsedSpace.Text;
+ num2_fs++;
+ num_fs /= 1024.0;
}
+ TB_ROMSize.Text = $"{num_fs:0.##} {array_fs[num2_fs]}";
+ TB_UsedSpace.Text = TB_ROMSize.Text;
- private void LoadPartitions()
+ LoadNSPPartitions();
+
+ Process process = new();
+ try
{
- string actualHash;
- byte[] hashBuffer;
- long offset;
-
- TV_Partitions.Nodes.Clear();
- TV_Parti = new TreeViewFileSystem(TV_Partitions);
- rootNode = new BetterTreeNode("root");
- rootNode.Offset = -1L;
- rootNode.Size = -1L;
- TV_Partitions.Nodes.Add(rootNode);
- bool LogoPartition = false;
- FileStream fileStream = new FileStream(TB_File.Text, FileMode.Open, FileAccess.Read);
- HFS0.HSF0_Entry[] array = new HFS0.HSF0_Entry[HFS0.HFS0_Headers[0].FileCount];
- fileStream.Position = XCI.XCI_Headers[0].HFS0OffsetPartition + 16 + 64 * HFS0.HFS0_Headers[0].FileCount;
- long num = XCI.XCI_Headers[0].HFS0OffsetPartition + XCI.XCI_Headers[0].HFS0SizeParition;
- byte[] array2 = new byte[64];
- byte[] array3 = new byte[16];
- byte[] array4 = new byte[24];
- for (int i = 0; i < HFS0.HFS0_Headers[0].FileCount; i++)
- {
- fileStream.Position = XCI.XCI_Headers[0].HFS0OffsetPartition + 16 + 64 * i;
- fileStream.Read(array2, 0, 64);
- array[i] = new HFS0.HSF0_Entry(array2);
- fileStream.Position = XCI.XCI_Headers[0].HFS0OffsetPartition + 16 + 64 * HFS0.HFS0_Headers[0].FileCount + array[i].Name_ptr;
- int num2;
- while ((num2 = fileStream.ReadByte()) != 0 && num2 != 0)
- {
- chars.Add((char)num2);
- }
- array[i].Name = new string(chars.ToArray());
- chars.Clear();
- offset = num + array[i].Offset;
- hashBuffer = new byte[array[i].HashedRegionSize];
- fileStream.Position = offset;
- fileStream.Read(hashBuffer, 0, array[i].HashedRegionSize);
- actualHash = SHA256Bytes(hashBuffer);
-
- TV_Parti.AddFile($"{array[i].Name}.hfs0", rootNode, offset, array[i].Size, array[i].HashedRegionSize, ByteArrayToString(array[i].Hash), actualHash);
- BetterTreeNode betterTreeNode = TV_Parti.AddDir(array[i].Name, rootNode);
- HFS0.HFS0_Header[] array5 = new HFS0.HFS0_Header[1];
- fileStream.Position = array[i].Offset + num;
- fileStream.Read(array3, 0, 16);
- array5[0] = new HFS0.HFS0_Header(array3);
- if (array[i].Name == "secure")
- {
- SecureSize = new long[array5[0].FileCount];
- SecureOffset = new long[array5[0].FileCount];
- SecureName = new string[array5[0].FileCount];
- }
- if (array[i].Name == "normal")
- {
- NormalSize = new long[array5[0].FileCount];
- NormalOffset = new long[array5[0].FileCount];
- }
- if (array[i].Name == "logo")
- {
- if (array5[0].FileCount > 0)
- {
- LogoPartition = true;
- }
- }
- HFS0.HSF0_Entry[] array6 = new HFS0.HSF0_Entry[array5[0].FileCount];
- for (int j = 0; j < array5[0].FileCount; j++)
- {
- fileStream.Position = array[i].Offset + num + 16 + 64 * j;
- fileStream.Read(array2, 0, 64);
- array6[j] = new HFS0.HSF0_Entry(array2);
- fileStream.Position = array[i].Offset + num + 16 + 64 * array5[0].FileCount + array6[j].Name_ptr;
- while ((num2 = fileStream.ReadByte()) != 0 && num2 != 0)
- {
- chars.Add((char)num2);
- }
- array6[j].Name = new string(chars.ToArray());
- chars.Clear();
- if (array[i].Name == "secure")
- {
- SecureSize[j] = array6[j].Size;
- SecureOffset[j] = array[i].Offset + array6[j].Offset + num + 16 + array5[0].StringTableSize + array5[0].FileCount * 64;
- SecureName[j] = array6[j].Name;
- }
- if (array[i].Name == "normal")
- {
- NormalSize[j] = array6[j].Size;
- NormalOffset[j] = array[i].Offset + array6[j].Offset + num + 16 + array5[0].StringTableSize + array5[0].FileCount * 64;
- }
- offset = array[i].Offset + array6[j].Offset + num + 16 + array5[0].StringTableSize + array5[0].FileCount * 64;
- hashBuffer = new byte[array6[j].HashedRegionSize];
- fileStream.Position = offset;
- fileStream.Read(hashBuffer, 0, array6[j].HashedRegionSize);
- actualHash = SHA256Bytes(hashBuffer);
-
- TV_Parti.AddFile(array6[j].Name, betterTreeNode, offset, array6[j].Size, array6[j].HashedRegionSize, ByteArrayToString(array6[j].Hash), actualHash);
- TreeNode[] array7 = TV_Partitions.Nodes.Find(betterTreeNode.Text, true);
- if (array7.Length != 0)
- {
- TV_Parti.AddFile(array6[j].Name, (BetterTreeNode)array7[0], 0L, 0L);
- }
- }
- }
- long num3 = -9223372036854775808L;
- for (int k = 0; k < SecureSize.Length; k++)
- {
- if (SecureSize[k] > num3)
- {
- gameNcaSize = SecureSize[k];
- gameNcaOffset = SecureOffset[k];
- num3 = SecureSize[k];
- }
- }
- PFS0Offset = gameNcaOffset + 32768;
- fileStream.Position = PFS0Offset;
- fileStream.Read(array3, 0, 16);
- PFS0.PFS0_Headers[0] = new PFS0.PFS0_Header(array3);
- if (PFS0.PFS0_Headers[0].FileCount == 2 || !LogoPartition)
- {
- PFS0.PFS0_Entry[] array8;
- try
- {
- array8 = new PFS0.PFS0_Entry[PFS0.PFS0_Headers[0].FileCount];
- }
- catch (Exception ex)
- {
- array8 = new PFS0.PFS0_Entry[0];
- Debug.WriteLine($"Partitions Error: {ex.Message}");
- }
- for (int m = 0; m < PFS0.PFS0_Headers[0].FileCount; m++)
- {
- fileStream.Position = PFS0Offset + 16 + 24 * m;
- fileStream.Read(array4, 0, 24);
- array8[m] = new PFS0.PFS0_Entry(array4);
- PFS0Size += array8[m].Size;
- }
- TV_Parti.AddFile("boot.psf0", rootNode, PFS0Offset, 16 + 24 * PFS0.PFS0_Headers[0].FileCount + 64 + PFS0Size);
- BetterTreeNode betterTreeNode2 = TV_Parti.AddDir("boot", rootNode);
- for (int n = 0; n < PFS0.PFS0_Headers[0].FileCount; n++)
- {
- fileStream.Position = PFS0Offset + 16 + 24 * PFS0.PFS0_Headers[0].FileCount + array8[n].Name_ptr;
- int num4;
- while ((num4 = fileStream.ReadByte()) != 0 && num4 != 0)
- {
- chars.Add((char)num4);
- }
- array8[n].Name = new string(chars.ToArray());
- chars.Clear();
- TV_Parti.AddFile(array8[n].Name, betterTreeNode2, PFS0Offset + array8[n].Offset + 16 + PFS0.PFS0_Headers[0].StringTableSize + PFS0.PFS0_Headers[0].FileCount * 24, array8[n].Size);
- TreeNode[] array9 = TV_Partitions.Nodes.Find(betterTreeNode2.Text, true);
- if (array9.Length != 0)
- {
- TV_Parti.AddFile(array8[n].Name, (BetterTreeNode)array9[0], 0L, 0L);
- }
- }
- }
- fileStream.Close();
- }
-
-
- private void LoadNSPPartitions()
- {
- long offset;
-
- TV_Partitions.Nodes.Clear();
- TV_Parti = new TreeViewFileSystem(TV_Partitions);
- rootNode = new BetterTreeNode("root");
- rootNode.Offset = -1L;
- rootNode.Size = -1L;
- TV_Partitions.Nodes.Add(rootNode);
-
-
- // Maximum number of files in NSP to read in
- const int MAXFILES = 250;
-
FileStream fileStream = File.OpenRead(TB_File.Text);
- List chars = new List();
+ string ncaTarget = "";
+ string xmlVersion = "";
+
+ List chars = new();
byte[] array = new byte[16];
byte[] array2 = new byte[24];
fileStream.Read(array, 0, 16);
- PFS0.PFS0_Headers[0] = new PFS0.PFS0_Header(array);
+ PFS0.PFS0_Headers[0] = new(array);
if (!PFS0.PFS0_Headers[0].Magic.Contains("PFS0"))
{
return;
}
PFS0.PFS0_Entry[] array3;
array3 = new PFS0.PFS0_Entry[Math.Max(PFS0.PFS0_Headers[0].FileCount, MAXFILES)]; //Dump of TitleID 01009AA000FAA000 reports more than 10000000 files here, so it breaks the program. Standard is to have only 20 files
+
for (int m = 0; m < PFS0.PFS0_Headers[0].FileCount; m++)
{
fileStream.Position = 16 + 24 * m;
fileStream.Read(array2, 0, 24);
- array3[m] = new PFS0.PFS0_Entry(array2);
+ array3[m] = new(array2);
if (m == MAXFILES - 1) //Dump of TitleID 01009AA000FAA000 reports more than 10000000 files here, so it breaks the program. Standard is to have only 20 files
{
@@ -1396,475 +362,1551 @@ namespace XCI_Explorer
{
chars.Add((char)num4);
}
- array3[n].Name = new string(chars.ToArray());
+ array3[n].Name = new(chars.ToArray());
chars.Clear();
- offset = 16 + 24 * PFS0.PFS0_Headers[0].FileCount + PFS0.PFS0_Headers[0].StringTableSize + array3[n].Offset;
- fileStream.Position = offset;
- TV_Parti.AddFile(array3[n].Name, rootNode, offset, array3[n].Size);
- }
+ if (array3[n].Name.EndsWith(".cnmt.xml"))
+ {
+ byte[] array4 = new byte[array3[n].Size];
+ fileStream.Position = 16 + 24 * PFS0.PFS0_Headers[0].FileCount + PFS0.PFS0_Headers[0].StringTableSize + array3[n].Offset;
+ fileStream.Read(array4, 0, (int)array3[n].Size);
- fileStream.Close();
- }
+ XDocument xml = XDocument.Parse(Encoding.UTF8.GetString(array4));
+ TB_TID.Text = xml.Element("ContentMeta").Element("Id").Value.Remove(1, 2).ToUpper(); //id
+ pversion = xml.Element("ContentMeta").Element("Version").Value; //version
+ contentType = xml.Element("ContentMeta").Element("Type").Value; //content
+ var test = NACP.NACP_Datas[0].GameVer.Replace("\0", "");
-
- private void TV_Partitions_AfterSelect(object sender, TreeViewEventArgs e)
- {
- BetterTreeNode betterTreeNode = (BetterTreeNode)TV_Partitions.SelectedNode;
- if (betterTreeNode.Offset != -1)
- {
- selectedOffset = betterTreeNode.Offset;
- selectedSize = betterTreeNode.Size;
- string expectedHash = betterTreeNode.ExpectedHash;
- string actualHash = betterTreeNode.ActualHash;
- long HashedRegionSize = betterTreeNode.HashedRegionSize;
-
- LB_DataOffset.Text = $"Offset: 0x{selectedOffset.ToString("X")}";
- LB_SelectedData.Text = e.Node.Text;
- if (backgroundWorker1.IsBusy != true)
- {
- B_Extract.Enabled = true;
- }
- string[] array = new string[5]
- {
- "B",
- "KB",
- "MB",
- "GB",
- "TB"
- };
- double num = (double)selectedSize;
- int num2 = 0;
- while (num >= 1024.0 && num2 < array.Length - 1)
- {
- num2++;
- num /= 1024.0;
- }
- LB_DataSize.Text = $"Size: 0x{selectedSize.ToString("X")} ({num.ToString()}{array[num2]})";
-
- if (HashedRegionSize != 0)
- {
- LB_HashedRegionSize.Text = $"HashedRegionSize: 0x{HashedRegionSize.ToString("X")}";
- }
- else
- {
- LB_HashedRegionSize.Text = "";
- }
-
- if (!string.IsNullOrEmpty(expectedHash))
- {
- LB_ExpectedHash.Text = $"Header Hash: {expectedHash.Substring(0, 32)}";
- }
- else
- {
- LB_ExpectedHash.Text = "";
- }
-
- if (!string.IsNullOrEmpty(actualHash))
- {
- LB_ActualHash.Text = $"Actual Hash: {actualHash.Substring(0, 32)}";
- if (actualHash == expectedHash)
+ if (contentType == "Patch")
{
- LB_ActualHash.ForeColor = System.Drawing.Color.Green;
+ patchflag = 1;
+ if (Convert.ToInt32(pversion) > patchnum)
+ {
+ patchnum = Convert.ToInt32(pversion);
+ xmlVersion = $"v{xml.Element("ContentMeta").Element("Version").Value}";
+ int number = Convert.ToInt32(pversion);
+ patchver = $"v{Convert.ToString((double)number / 65536)}";
+ }
+
+ updtitle[updnum] = $"[{TB_TID.Text}][v{pversion}]";
+ updnum++;
+ }
+ else if (contentType == "Application")
+ {
+ baseflag = 1;
+ if (patchflag != 1)
+ {
+ xmlVersion = $"v{xml.Element("ContentMeta").Element("Version").Value}";
+ }
+
+ basetitle[basenum] = $"[{TB_TID.Text}][v{pversion}]";
+ basenum++;
}
else
{
- LB_ActualHash.ForeColor = System.Drawing.Color.Red;
+ if (baseflag == 0 && patchflag == 0)
+ {
+ xmlVersion = $"v{xml.Element("ContentMeta").Element("Version").Value}";
+ }
+
+ dlctitle[dlcnum] = $"[{TB_TID.Text}][v{pversion}]";
+ dlcnum++;
}
+
+ if (contentType != "AddOnContent")
+ {
+ foreach (XElement xe in xml.Descendants("Content"))
+ {
+ if (xe.Element("Type").Value != "Control")
+ {
+ continue;
+ }
+
+ ncaTarget = $"{xe.Element("Id").Value}.nca";
+ break;
+ }
+ }
+ else //This is a DLC
+ {
+ foreach (XElement xe in xml.Descendants("Content"))
+ {
+ if (xe.Element("Type").Value != "Meta")
+ {
+ continue;
+ }
+
+ ncaTarget = $"{xe.Element("Id").Value}.cnmt.nca";
+ break;
+ }
+ }
+ }
+
+ if (n == MAXFILES - 1) //Dump of TitleID 01009AA000FAA000 reports more than 10000000 files here, so it breaks the program. Standard is to have only 20 files
+ {
+ break;
+ }
+ }
+
+ if (string.IsNullOrEmpty(ncaTarget))
+ {
+ //Missing content metadata xml. Read from content metadata nca instead
+ for (int n = 0; n < PFS0.PFS0_Headers[0].FileCount; n++)
+ {
+ if (array3[n].Name.EndsWith(".cnmt.nca"))
+ {
+ try
+ {
+ File.Delete("meta");
+ Directory.Delete("data", true);
+ }
+ catch { }
+
+ using (FileStream fileStream2 = File.OpenWrite("meta"))
+ {
+ fileStream.Position = 16 + 24 * PFS0.PFS0_Headers[0].FileCount + PFS0.PFS0_Headers[0].StringTableSize + array3[n].Offset;
+ byte[] buffer = new byte[8192];
+ long num = array3[n].Size;
+ int num4;
+ while ((num4 = fileStream.Read(buffer, 0, 8192)) > 0 && num > 0)
+ {
+ fileStream2.Write(buffer, 0, num4);
+ num -= num4;
+ }
+ fileStream2.Close();
+ }
+
+ process = new()
+ {
+ StartInfo = new ProcessStartInfo
+ {
+ WindowStyle = ProcessWindowStyle.Hidden,
+ FileName = Path.Join("tools", "hactool.exe"),
+ Arguments = "-k keys.txt --section0dir=data meta",
+ UseShellExecute = false,
+ RedirectStandardOutput = true,
+ CreateNoWindow = true
+ }
+ };
+ process.Start();
+
+ string masterkey = "";
+ while (!process.StandardOutput.EndOfStream)
+ {
+ string output = process.StandardOutput.ReadLine();
+ if (output.StartsWith("Master Key Revision"))
+ {
+ masterkey = Regex.Replace(output, @"\s+", " ");
+ }
+ }
+ process.WaitForExit();
+
+ if (!Directory.Exists("data"))
+ {
+ new CenterWinDialog(this);
+ MessageBox.Show($"{masterkey} is missing!");
+ }
+ else
+ {
+ try
+ {
+ string[] cnmt = Directory.GetFiles("data", "*.cnmt");
+ if (cnmt.Length == 0)
+ {
+ return;
+ }
+ using FileStream fileStream3 = File.OpenRead(cnmt[0]);
+ byte[] buffer = new byte[32];
+ byte[] buffer2 = new byte[56];
+ CNMT.CNMT_Header[] array7 = new CNMT.CNMT_Header[1];
+
+ fileStream3.Read(buffer, 0, 32);
+ array7[0] = new CNMT.CNMT_Header(buffer);
+
+ byte[] TitleID = BitConverter.GetBytes(array7[0].TitleID);
+ Array.Reverse(TitleID);
+ TB_TID.Text = BitConverter.ToString(TitleID).Replace("-", "");
+
+ if (array7[0].Type == (byte)CNMT.CNMT_Header.TitleType.REGULAR_APPLICATION)
+ {
+ contentType = "Application";
+ baseflag = 1;
+ if (patchflag != 1)
+ {
+ xmlVersion = $"v{array7[0].TitleVersion}";
+ }
+
+ basetitle[basenum] = $"[{TB_TID.Text}][v{array7[0].TitleVersion}]";
+ basenum++;
+ }
+ else if (array7[0].Type == (byte)CNMT.CNMT_Header.TitleType.UPDATE_TITLE)
+ {
+ contentType = "Patch";
+
+ patchflag = 1;
+ if (array7[0].TitleVersion > patchnum)
+ {
+ patchnum = array7[0].TitleVersion;
+ xmlVersion = $"v{array7[0].TitleVersion}";
+ int number = Convert.ToInt32(array7[0].TitleVersion);
+ patchver = $"v{Convert.ToString((double)number / 65536)}";
+ }
+
+ updtitle[updnum] = $"[{TB_TID.Text}][v{array7[0].TitleVersion}]";
+ updnum++;
+ }
+ else if (array7[0].Type == (byte)CNMT.CNMT_Header.TitleType.ADD_ON_CONTENT)
+ {
+ if (baseflag == 0 && patchflag == 0)
+ {
+ xmlVersion = $"v{array7[0].TitleVersion}";
+ }
+
+ contentType = "AddOnContent";
+ dlctitle[dlcnum] = $"[{TB_TID.Text}][v{array7[0].TitleVersion}]";
+ dlcnum++;
+ }
+
+ fileStream3.Position = array7[0].Offset + 32;
+ CNMT.CNMT_Entry[] array9 = new CNMT.CNMT_Entry[array7[0].ContentCount];
+ for (int k = 0; k < array7[0].ContentCount; k++)
+ {
+ fileStream3.Read(buffer2, 0, 56);
+ array9[k] = new CNMT.CNMT_Entry(buffer2);
+ if (array9[k].Type == (byte)CNMT.CNMT_Entry.ContentType.CONTROL || array9[k].Type == (byte)CNMT.CNMT_Entry.ContentType.DATA)
+ {
+ ncaTarget = $"{BitConverter.ToString(array9[k].NcaId).ToLower().Replace("-", "")}.nca";
+ break;
+ }
+ }
+
+ fileStream3.Close();
+ }
+ catch
+ {
+ }
+ }
+ }
+ }
+ }
+
+ for (int n = 0; n < PFS0.PFS0_Headers[0].FileCount; n++)
+ {
+ if (array3[n].Name.Equals(ncaTarget))
+ {
+ Directory.CreateDirectory("tmp");
+
+ byte[] array5 = new byte[64 * 1024];
+ fileStream.Position = 16 + 24 * PFS0.PFS0_Headers[0].FileCount + PFS0.PFS0_Headers[0].StringTableSize + array3[n].Offset;
+
+ using (Stream output = File.Create(Path.Join("tmp", ncaTarget)))
+ {
+ long Size = array3[n].Size;
+ int result = 0;
+ while ((result = fileStream.Read(array5, 0, (int)Math.Min(array5.Length, Size))) > 0)
+ {
+ output.Write(array5, 0, result);
+ Size -= result;
+ }
+ }
+
+ break;
+ }
+
+ if (n == MAXFILES - 1) //Dump of TitleID 01009AA000FAA000 reports more than 10000000 files here, so it breaks the program. Standard is to have only 20 files
+ {
+ break;
+ }
+ }
+
+ fileStream.Close();
+
+ if (contentType != "AddOnContent")
+ {
+ process = new Process
+ {
+ StartInfo = new ProcessStartInfo
+ {
+ WindowStyle = ProcessWindowStyle.Hidden,
+ FileName = Path.Join("tools", "hactool.exe"),
+ Arguments = $"-k keys.txt --romfsdir=tmp tmp/{ncaTarget}",
+ UseShellExecute = false,
+ CreateNoWindow = true
+ }
+ };
+
+ process.Start();
+ process.WaitForExit();
+ process.Close();
+ byte[] flux = new byte[200];
+
+ try
+ {
+ byte[] source = File.ReadAllBytes(Path.Join("tmp", "control.nacp"));
+ NACP.NACP_Datas[0] = new NACP.NACP_Data(source.Skip(0x3000).Take(0x1000).ToArray());
+
+ for (int i = 0; i < NACP.NACP_Strings.Length; i++)
+ {
+ NACP.NACP_Strings[i] = new NACP.NACP_String(source.Skip(i * 0x300).Take(0x300).ToArray());
+
+ if (NACP.NACP_Strings[i].Check != 0)
+ {
+ CB_RegionName.Items.Add(Language[i]);
+ string icon_filename = Path.Join("tmp", $"icon_{Language[i].Replace(" ", "")}.dat");
+ if (File.Exists(icon_filename))
+ {
+ using Bitmap original = new(icon_filename);
+ Icons[i] = new Bitmap(original);
+ PB_GameIcon.BackgroundImage = Icons[i];
+ }
+ }
+ }
+
+ string gameVer = NACP.NACP_Datas[0].GameVer.Replace("\0", "");
+ if (xmlVersion.Trim() == "")
+ {
+ TB_GameRev.Text = $"GENERAL:{Environment.NewLine}({gameVer}){Environment.NewLine}";
+ }
+ else
+ {
+ string cache = $"GENERAL:{Environment.NewLine}{gameVer}{((patchflag == 1) ? $" ({patchver})" : "")}{Environment.NewLine}";
+
+ if (basenum != 0)
+ {
+ cache += $"BASE:{Environment.NewLine}";
+ for (int i = 0; i < basenum; i++)
+ {
+ cache += basetitle[i] + Environment.NewLine;
+ }
+ }
+ else
+ {
+ cache += $"BASE:{Environment.NewLine}EMPTY{Environment.NewLine}";
+ }
+ if (updnum != 0)
+ {
+ cache += $"UPD:{Environment.NewLine}";
+ for (int i = 0; i < updnum; i++)
+ {
+ cache += updtitle[i] + Environment.NewLine;
+ }
+ }
+ else
+ {
+ cache += $"UPD:{Environment.NewLine}EMPTY{Environment.NewLine}";
+ }
+ if (dlcnum != 0)
+ {
+ cache += $"DLC:{Environment.NewLine}";
+ for (int i = 0; i < dlcnum; i++)
+ {
+ if (i < dlcnum - 1)
+ {
+ cache += dlctitle[i] + Environment.NewLine;
+ }
+ else
+ {
+ cache += dlctitle[i];
+ }
+ }
+ }
+ else
+ {
+ cache += $"DLC:{Environment.NewLine}EMPTY";
+ }
+ TB_GameRev.Text = cache;
+ label12.Text = $"{basenum} BASE, {updnum} UPD, {dlcnum} DLC";
+ }
+
+ TB_ProdCode.Text = NACP.NACP_Datas[0].GameProd.Replace("\0", "");
+ if (TB_ProdCode.Text == "")
+ {
+ TB_ProdCode.Text = "No Prod. ID";
+ }
+
+ for (int z = 0; z < NACP.NACP_Strings.Length; z++)
+ {
+ if (NACP.NACP_Strings[z].GameName.Replace("\0", "") != "")
+ {
+ TB_Name.Text = NACP.NACP_Strings[z].GameName.Replace("\0", "");
+ break;
+ }
+ }
+ for (int z = 0; z < NACP.NACP_Strings.Length; z++)
+ {
+ if (NACP.NACP_Strings[z].GameAuthor.Replace("\0", "") != "")
+ {
+ TB_Dev.Text = NACP.NACP_Strings[z].GameAuthor.Replace("\0", "");
+ break;
+ }
+ }
+ }
+ catch { }
+
+ }
+ else
+ {
+ if (xmlVersion.Trim() == "")
+ {
+ TB_GameRev.Text = $"GENERAL:{Environment.NewLine}{Environment.NewLine}";
}
else
{
- LB_ActualHash.Text = "";
- }
+ string gameVer = NACP.NACP_Datas[0].GameVer.Replace("\0", "");
+ string cache = $"GENERAL:{Environment.NewLine}{gameVer}{((patchflag == 1) ? $" ({patchver})" : "")}{Environment.NewLine}";
- }
- else
- {
- LB_SelectedData.Text = "";
- LB_DataOffset.Text = "";
- LB_DataSize.Text = "";
- LB_HashedRegionSize.Text = "";
- LB_ExpectedHash.Text = "";
- LB_ActualHash.Text = "";
- B_Extract.Enabled = false;
- }
- }
-
- public bool CheckXCI()
- {
- FileStream fileStream = new FileStream(TB_File.Text, FileMode.Open, FileAccess.Read);
- byte[] array = new byte[61440];
- byte[] array2 = new byte[16];
- fileStream.Read(array, 0, 61440);
- XCI.XCI_Headers[0] = new XCI.XCI_Header(array);
- if (!XCI.XCI_Headers[0].Magic.Contains("HEAD"))
- {
- return false;
- }
- fileStream.Position = XCI.XCI_Headers[0].HFS0OffsetPartition;
- fileStream.Read(array2, 0, 16);
- HFS0.HFS0_Headers[0] = new HFS0.HFS0_Header(array2);
- fileStream.Close();
- return true;
- }
-
- public bool CheckNSP()
- {
- FileStream fileStream = File.OpenRead(TB_File.Text);
- byte[] array = new byte[16];
- fileStream.Read(array, 0, 16);
- PFS0.PFS0_Headers[0] = new PFS0.PFS0_Header(array);
- fileStream.Close();
- if (!PFS0.PFS0_Headers[0].Magic.Contains("PFS0"))
- {
- return false;
- }
- return true;
- }
-
- private void B_ExportCert_Click(object sender, EventArgs e)
- {
- new CenterWinDialog(this);
- if (Util.checkFile(TB_File.Text))
- {
- SaveFileDialog saveFileDialog = new SaveFileDialog();
- saveFileDialog.Filter = "gamecard_cert.dat (*.dat)|*.dat";
- saveFileDialog.FileName = Path.GetFileName("gamecard_cert.dat");
- if (saveFileDialog.ShowDialog() == DialogResult.OK)
- {
- FileStream fileStream = new FileStream(TB_File.Text, FileMode.Open, FileAccess.Read);
- byte[] array = new byte[512];
- fileStream.Position = 28672L;
- fileStream.Read(array, 0, 512);
- File.WriteAllBytes(saveFileDialog.FileName, array);
- fileStream.Close();
- MessageBox.Show($"Cert successfully exported to:\n\n{saveFileDialog.FileName}");
- }
- }
- else
- {
- MessageBox.Show("File not found");
- }
- }
-
- private void B_ImportCert_Click(object sender, EventArgs e)
- {
- new CenterWinDialog(this);
- if (Util.checkFile(TB_File.Text))
- {
- OpenFileDialog openFileDialog = new OpenFileDialog();
- openFileDialog.Filter = "gamecard_cert (*.dat)|*.dat|All files (*.*)|*.*";
- if (openFileDialog.ShowDialog() == DialogResult.OK && new FileInfo(openFileDialog.FileName).Length == 512)
- {
- using (Stream stream = File.Open(TB_File.Text, FileMode.Open))
+ if (basenum != 0)
{
- stream.Position = 28672L;
- stream.Write(File.ReadAllBytes(openFileDialog.FileName), 0, 512);
- }
- MessageBox.Show($"Cert successfully imported from:\n\n{openFileDialog.FileName}");
- }
- }
- else
- {
- MessageBox.Show("File not found");
- }
- }
-
- private void B_ViewCert_Click(object sender, EventArgs e)
- {
- new CenterWinDialog(this);
- if (Util.checkFile(TB_File.Text))
- {
- CertForm cert = new CertForm(this);
- cert.Text = $"Cert Data - {TB_File.Text}";
- cert.Show();
- }
- else
- {
- MessageBox.Show("File not found");
- }
- }
-
- private void B_ClearCert_Click(object sender, EventArgs e)
- {
- new CenterWinDialog(this);
- if (Util.checkFile(TB_File.Text))
- {
- if (MessageBox.Show("The cert will be deleted permanently.\nContinue?", "XCI Explorer", MessageBoxButtons.YesNo) == DialogResult.Yes)
- {
- using (Stream stream = File.Open(TB_File.Text, FileMode.Open))
- {
- byte[] array = new byte[512];
- for (int i = 0; i < array.Length; i++)
+ cache += $"BASE:{Environment.NewLine}";
+ for (int i = 0; i < basenum; i++)
{
- array[i] = byte.MaxValue;
+ cache += basetitle[i] + Environment.NewLine;
}
- stream.Position = 28672L;
- stream.Write(array, 0, array.Length);
- new CenterWinDialog(this);
- MessageBox.Show("Cert deleted.");
}
- }
- }
- else
- {
- MessageBox.Show("File not found");
- }
- }
-
- private void B_Extract_Click(object sender, EventArgs e)
- {
- SaveFileDialog saveFileDialog = new SaveFileDialog();
- saveFileDialog.FileName = LB_SelectedData.Text;
- if (saveFileDialog.ShowDialog() == DialogResult.OK)
- {
- if (backgroundWorker1.IsBusy != true)
- {
- B_Extract.Enabled = false;
- B_LoadROM.Enabled = false;
- B_TrimXCI.Enabled = false;
- B_ImportCert.Enabled = false;
- B_ClearCert.Enabled = false;
-
- // Start the asynchronous operation.
- backgroundWorker1.RunWorkerAsync(saveFileDialog.FileName);
- }
- }
- }
-
- public byte[] DecryptNCAHeader(long offset)
- {
- byte[] array = new byte[3072];
- if (File.Exists(TB_File.Text))
- {
- FileStream fileStream = new FileStream(TB_File.Text, FileMode.Open, FileAccess.Read);
- fileStream.Position = offset;
- fileStream.Read(array, 0, 3072);
- File.WriteAllBytes($"{TB_File.Text}.tmp", array);
- Xts xts = XtsAes128.Create(NcaHeaderEncryptionKey1_Prod, NcaHeaderEncryptionKey2_Prod);
- using (BinaryReader binaryReader = new BinaryReader(File.OpenRead($"{TB_File.Text}.tmp")))
- {
- using (XtsStream xtsStream = new XtsStream(binaryReader.BaseStream, xts, 512))
+ else
{
- xtsStream.Read(array, 0, 3072);
+ cache += $"BASE:{Environment.NewLine} EMPTY {Environment.NewLine}";
}
+ if (updnum != 0)
+ {
+ cache += $"UPD:{Environment.NewLine}";
+ for (int i = 0; i < updnum; i++)
+ {
+ cache += updtitle[i] + Environment.NewLine;
+ }
+ }
+ else
+ {
+ cache += $"UPD:{Environment.NewLine} EMPTY {Environment.NewLine}";
+ }
+ if (dlcnum != 0)
+ {
+ cache += $"DLC:{Environment.NewLine}";
+ for (int i = 0; i < dlcnum; i++)
+ {
+ if (i < dlcnum - 1)
+ {
+ cache += dlctitle[i] + Environment.NewLine;
+ }
+ else
+ {
+ cache += dlctitle[i];
+ }
+ }
+ }
+ else
+ {
+ cache += $"DLC:{Environment.NewLine}EMPTY";
+ }
+ TB_GameRev.Text = cache;
+ label12.Text = $"{basenum} BASE, {updnum} UPD, {dlcnum} DLC";
}
- File.Delete($"{TB_File.Text}.tmp");
- fileStream.Close();
+ TB_ProdCode.Text = "No Prod. ID";
}
- return array;
+
+ // Lets get SDK Version, Distribution Type and Masterkey revision
+ // This is far from the best aproach, but it's what we have for now
+ process = new Process
+ {
+ StartInfo = new ProcessStartInfo
+ {
+ WindowStyle = ProcessWindowStyle.Hidden,
+ FileName = Path.Join("tools", "hactool.exe"),
+ Arguments = $"-k keys.txt tmp/{ncaTarget}",
+ RedirectStandardOutput = true,
+ UseShellExecute = false,
+ CreateNoWindow = true
+ }
+ };
+ process.Start();
+ StreamReader sr = process.StandardOutput;
+
+ while (sr.Peek() >= 0)
+ {
+ string str;
+ string[] strArray;
+ str = sr.ReadLine();
+ strArray = str.Split(':');
+ if (strArray[0] == "SDK Version")
+ {
+ TB_SDKVer.Text = strArray[1].Trim();
+ }
+ else if (strArray[0] == "Master Key Revision")
+ {
+ string MasterKey = strArray[1].Trim();
+ int keyblob;
+
+ MasterKey = MasterKey.Split(new char[2] { 'x', ' ' })[1];
+ keyblob = Convert.ToInt32(MasterKey, 16);
+ MasterKey = Util.GetMkey((byte)(keyblob + 1));
+ TB_MKeyRev.Text = MasterKey;
+ break;
+ }
+ }
+ process.WaitForExit();
+ process.Close();
+ }
+ catch { }
+
+ try
+ {
+ File.Delete("meta");
+ Directory.Delete("data", true);
+ }
+ catch
+ {
}
- private void CB_RegionName_SelectedIndexChanged(object sender, EventArgs e)
+ try
{
- int num = Array.FindIndex(Language, (string element) => element.StartsWith(CB_RegionName.Text, StringComparison.Ordinal));
- // Icons for 1-2 Switch in some languages are "missing"
- // This just shows the first real icon instead of a blank
- if (Icons[num] != null)
+ Directory.Delete("tmp", true);
+ }
+ catch
+ {
+ }
+
+ TB_Capacity.Text = "eShop";
+
+ if (TB_Name.Text.Trim() != "")
+ {
+ CB_RegionName.SelectedIndex = 0;
+ }
+ }
+
+ private void LoadGameInfos()
+ {
+ CB_RegionName.Items.Clear();
+ CB_RegionName.Enabled = true;
+ TB_Name.Text = "";
+ TB_Dev.Text = "";
+ PB_GameIcon.BackgroundImage = null;
+
+ int basenum = 0;
+ int updnum = 0;
+ int dlcnum = 0;
+ int patchflag = 0;
+ int patchnum = 0;
+ string patchver = "";
+ int baseflag = 0;
+ string[] basetitle = new string[5];
+ string[] updtitle = new string[10];
+ string[] dlctitle = new string[300];
+ string xmlVersion = "";
+ string saveTID = "";
+
+ Array.Clear(Icons, 0, Icons.Length);
+ if (getMKey())
+ {
+ using FileStream fileStream = File.OpenRead(TB_File.Text);
+ List ncaTarget = new();
+ string GameRevision = "";
+
+ for (int si = 0; si < SecureSize.Length; si++)
{
- PB_GameIcon.BackgroundImage = Icons[num];
- }
- else
- {
- for (int i = 0; i < CB_RegionName.Items.Count; i++)
+ if (SecureSize[si] > 0x4E20000)
{
- if (Icons[i] != null)
+ continue;
+ }
+
+ if (!SecureName[si].EndsWith(".cnmt.nca"))
+ {
+ continue;
+ }
+
+ try
+ {
+ File.Delete("meta");
+ Directory.Delete("data", true);
+ }
+ catch
+ {
+ }
+
+ using (FileStream fileStream2 = File.OpenWrite("meta"))
+ {
+ fileStream.Position = SecureOffset[si];
+ byte[] fsBuffer = new byte[8192];
+ long num = SecureSize[si];
+ int num4;
+ while ((num4 = fileStream.Read(fsBuffer, 0, 8192)) > 0 && num > 0)
{
- PB_GameIcon.BackgroundImage = Icons[i];
+ fileStream2.Write(fsBuffer, 0, num4);
+ num -= num4;
+ }
+ fileStream2.Close();
+ }
+
+ Process process1 = new Process
+ {
+ StartInfo = new ProcessStartInfo
+ {
+ WindowStyle = ProcessWindowStyle.Hidden,
+ FileName = Path.Join("tools", "hactool.exe"),
+ Arguments = "-k keys.txt --section0dir=data meta",
+ UseShellExecute = false,
+ CreateNoWindow = true
+ }
+ };
+ process1.Start();
+ process1.WaitForExit();
+
+ string[] cnmt = Directory.GetFiles("data", "*.cnmt");
+ if (cnmt.Length == 0)
+ {
+ continue;
+ }
+
+ using FileStream fileStream3 = File.OpenRead(cnmt[0]);
+ byte[] buffer = new byte[32];
+ byte[] buffer2 = new byte[56];
+ CNMT.CNMT_Header[] array7 = new CNMT.CNMT_Header[1];
+
+ fileStream3.Read(buffer, 0, 32);
+ array7[0] = new CNMT.CNMT_Header(buffer);
+
+ byte[] TitleID = BitConverter.GetBytes(array7[0].TitleID);
+ Array.Reverse(TitleID);
+ saveTID = BitConverter.ToString(TitleID).Replace("-", "");
+
+ if (array7[0].Type == (byte)CNMT.CNMT_Header.TitleType.REGULAR_APPLICATION)
+ {
+ baseflag = 1;
+ if (patchflag != 1)
+ {
+ xmlVersion = $"v{array7[0].TitleVersion}";
+ }
+
+ basetitle[basenum] = $"[{saveTID}][v{array7[0].TitleVersion}]";
+ basenum++;
+ }
+ else if (array7[0].Type == (byte)CNMT.CNMT_Header.TitleType.UPDATE_TITLE)
+ {
+ patchflag = 1;
+ if (array7[0].TitleVersion > patchnum)
+ {
+ patchnum = array7[0].TitleVersion;
+ xmlVersion = $"v{array7[0].TitleVersion}";
+ int number = Convert.ToInt32(array7[0].TitleVersion);
+ patchver = $"v{Convert.ToString((double)number / 65536)}";
+ }
+
+ updtitle[updnum] = $"[{saveTID}][v{array7[0].TitleVersion}]";
+ updnum++;
+ }
+ else if (array7[0].Type == (byte)CNMT.CNMT_Header.TitleType.ADD_ON_CONTENT)
+ {
+ if (patchflag == 0 && baseflag == 0)
+ {
+ xmlVersion = $"v{array7[0].TitleVersion}";
+ }
+
+ dlctitle[dlcnum] = $"[{saveTID}][v{array7[0].TitleVersion}]";
+ dlcnum++;
+ }
+
+ fileStream3.Position = array7[0].Offset + 32;
+ CNMT.CNMT_Entry[] array9 = new CNMT.CNMT_Entry[array7[0].ContentCount];
+ for (int k = 0; k < array7[0].ContentCount; k++)
+ {
+ fileStream3.Read(buffer2, 0, 56);
+ array9[k] = new CNMT.CNMT_Entry(buffer2);
+ if (array9[k].Type == (byte)CNMT.CNMT_Entry.ContentType.CONTROL || array9[k].Type == (byte)CNMT.CNMT_Entry.ContentType.DATA)
+ {
+ ncaTarget.Add($"{BitConverter.ToString(array9[k].NcaId).ToLower().Replace("-", "")}.nca");
break;
}
}
- }
- TB_Name.Text = NACP.NACP_Strings[num].GameName;
- TB_Dev.Text = NACP.NACP_Strings[num].GameAuthor;
- }
+ fileStream3.Close();
- private void B_TrimXCI_Click(object sender, EventArgs e)
- {
- new CenterWinDialog(this);
- if (Util.checkFile(TB_File.Text))
+ }
+
+ for (int si = 0; si < SecureSize.Length; si++)
{
- if (MessageBox.Show("Trim XCI?", "XCI Explorer", MessageBoxButtons.YesNo) == DialogResult.Yes)
+ if (SecureSize[si] > 0x4E20000)
{
- new CenterWinDialog(this);
- if (!isTrimmed())
+ continue;
+ }
+
+ if (!ncaTarget.Contains(SecureName[si]))
+ {
+ continue;
+ }
+
+ try
+ {
+ File.Delete("meta");
+ Directory.Delete("data", true);
+ }
+ catch
+ {
+ }
+
+ using (FileStream fileStream2 = File.OpenWrite("meta"))
+ {
+ fileStream.Position = SecureOffset[si];
+ byte[] buffer = new byte[8192];
+ long num = SecureSize[si];
+ int num2;
+ while ((num2 = fileStream.Read(buffer, 0, 8192)) > 0 && num > 0)
{
- FileStream fileStream = new FileStream(TB_File.Text, FileMode.Open, FileAccess.Write);
- fileStream.SetLength((long)UsedSize);
- fileStream.Close();
- B_TrimXCI.Enabled = false;
- MessageBox.Show("Done.");
- string[] array = new string[5]
- {
- "B",
- "KB",
- "MB",
- "GB",
- "TB"
- };
- double num = (double)new FileInfo(TB_File.Text).Length;
- TB_ROMExactSize.Text = $"({num.ToString()} bytes)";
- int num2 = 0;
- while (num >= 1024.0 && num2 < array.Length - 1)
- {
- num2++;
- num /= 1024.0;
- }
- TB_ROMSize.Text = $"{num:0.##} {array[num2]}";
- double num3 = UsedSize = (double)(XCI.XCI_Headers[0].CardSize2 * 512 + 512);
- TB_ExactUsedSpace.Text = $"({num3.ToString()} bytes)";
- num2 = 0;
- while (num3 >= 1024.0 && num2 < array.Length - 1)
- {
- num2++;
- num3 /= 1024.0;
- }
- TB_UsedSpace.Text = $"{num3:0.##} {array[num2]}";
+ fileStream2.Write(buffer, 0, num2);
+ num -= num2;
}
+ fileStream2.Close();
+ }
+
+
+ Process process = new();
+ process.StartInfo = new ProcessStartInfo
+ {
+ WindowStyle = ProcessWindowStyle.Hidden,
+ FileName = Path.Join("tools", "hactool.exe"),
+ Arguments = "-k keys.txt --romfsdir=data meta",
+ UseShellExecute = false,
+ CreateNoWindow = true
+ };
+ process.Start();
+ process.WaitForExit();
+
+ if (!File.Exists(Path.Join("data", "control.nacp")))
+ {
+ continue;
+ }
+
+ byte[] source = File.ReadAllBytes(Path.Join("data", "control.nacp"));
+ NACP.NACP_Datas[0] = new NACP.NACP_Data(source.Skip(0x3000).Take(0x1000).ToArray());
+
+ string GameVer = NACP.NACP_Datas[0].GameVer.Replace("\0", "");
+ Version version1, version2;
+ if (!Version.TryParse(Regex.Replace(GameRevision, @"[^\d.].*$", ""), out version1))
+ {
+ version1 = new Version();
+ }
+ if (!Version.TryParse(Regex.Replace(GameVer, @"[^\d.].*$", ""), out version2))
+ {
+ version2 = new Version();
+ }
+ if (version2.CompareTo(version1) > 0)
+ {
+ GameRevision = GameVer;
+
+ for (int i = 0; i < NACP.NACP_Strings.Length; i++)
+ {
+ NACP.NACP_Strings[i] = new NACP.NACP_String(source.Skip(i * 0x300).Take(0x300).ToArray());
+ if (NACP.NACP_Strings[i].Check == 0 || CB_RegionName.Items.Contains(Language[i]))
+ {
+ continue;
+ }
+
+ CB_RegionName.Items.Add(Language[i]);
+ string icon_filename = Path.Join("data", $"icon_{Language[i].Replace(" ", "")}.dat");
+ if (File.Exists(icon_filename))
+ {
+ using Bitmap original = new(icon_filename);
+ Icons[i] = new Bitmap(original);
+ PB_GameIcon.BackgroundImage = Icons[i];
+ }
+ }
+ TB_ProdCode.Text = NACP.NACP_Datas[0].GameProd;
+ if (TB_ProdCode.Text == "")
+ {
+ TB_ProdCode.Text = "No Prod. ID";
+ }
+ try
+ {
+ File.Delete("meta");
+ Directory.Delete("data", true);
+ }
+ catch
+ {
+ }
+ }
+ }
+
+ string gameVer = NACP.NACP_Datas[0].GameVer.Replace("\0", "");
+ string cache = $"GENERAL:{Environment.NewLine}{gameVer}{((patchflag == 1) ? $" ({patchver})" : "")}{Environment.NewLine}";
+
+ if (basenum != 0)
+ {
+ cache += $"BASE:{Environment.NewLine}";
+ for (int i = 0; i < basenum; i++)
+ {
+ cache += basetitle[i] + System.Environment.NewLine;
}
}
else
{
- MessageBox.Show("File not found");
+ cache += $"BASE:{Environment.NewLine}EMPTY{Environment.NewLine}";
}
- }
-
- private void LB_ExpectedHash_DoubleClick(object sender, EventArgs e)
- {
- BetterTreeNode betterTreeNode = (BetterTreeNode)TV_Partitions.SelectedNode;
- if (betterTreeNode.Offset != -1)
+ if (updnum != 0)
{
- Clipboard.SetText(betterTreeNode.ExpectedHash);
- }
- }
-
- private void LB_ActualHash_DoubleClick(object sender, EventArgs e)
- {
- BetterTreeNode betterTreeNode = (BetterTreeNode)TV_Partitions.SelectedNode;
- if (betterTreeNode.Offset != -1)
- {
- Clipboard.SetText(betterTreeNode.ActualHash);
- }
- }
-
- private void TB_File_DragDrop(object sender, DragEventArgs e)
- {
- if (backgroundWorker1.IsBusy != true)
- {
- string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
- TB_File.Text = files[0];
- ProcessFile();
- }
- }
-
- private void TB_File_DragEnter(object sender, DragEventArgs e)
- {
- if (backgroundWorker1.IsBusy != true)
- {
- if (e.Data.GetDataPresent(DataFormats.FileDrop))
+ cache += $"UPD:{Environment.NewLine}";
+ for (int i = 0; i < updnum; i++)
{
- e.Effect = DragDropEffects.Copy;
- }
- else
- {
- e.Effect = DragDropEffects.None;
+ cache += updtitle[i] + Environment.NewLine;
}
}
- }
-
- private void TABP_XCI_DragDrop(object sender, DragEventArgs e)
- {
- if (backgroundWorker1.IsBusy != true)
+ else
{
- string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
- TB_File.Text = files[0];
- ProcessFile();
+ cache += $"UPD:{Environment.NewLine}EMPTY{Environment.NewLine}";
}
- }
-
- private void TABP_XCI_DragEnter(object sender, DragEventArgs e)
- {
- if (backgroundWorker1.IsBusy != true)
+ if (dlcnum != 0)
{
- if (e.Data.GetDataPresent(DataFormats.FileDrop))
+ cache += $"DLC:{Environment.NewLine}";
+ for (int i = 0; i < dlcnum; i++)
{
- e.Effect = DragDropEffects.Copy;
- }
- else
- {
- e.Effect = DragDropEffects.None;
- }
- }
- }
-
- private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
- {
- BackgroundWorker worker = sender as BackgroundWorker;
- string fileName = (string)e.Argument;
-
- using (FileStream fileStream = File.OpenRead(TB_File.Text))
- {
- using (FileStream fileStream2 = File.OpenWrite(fileName))
- {
- new BinaryReader(fileStream);
- new BinaryWriter(fileStream2);
- fileStream.Position = selectedOffset;
- long num = selectedSize;
-
- if (selectedSize < 10000)
+ if (i < dlcnum - 1)
{
- byte[] buffer = new byte[1];
- int num2;
- while ((num2 = fileStream.Read(buffer, 0, 1)) > 0 && num > 0)
- {
- fileStream2.Write(buffer, 0, num2);
- num -= num2;
- }
+ cache += dlctitle[i] + Environment.NewLine;
}
else
{
- byte[] buffer = new byte[8192];
- int num2;
- while ((num2 = fileStream.Read(buffer, 0, 8192)) > 0 && num > 0)
- {
- fileStream2.Write(buffer, 0, num2);
- num -= num2;
- }
+ cache += dlctitle[i];
}
-
- fileStream.Close();
}
}
- }
-
- private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
- {
- new CenterWinDialog(this);
- B_Extract.Enabled = true;
- B_LoadROM.Enabled = true;
- B_TrimXCI.Enabled = true;
- B_ImportCert.Enabled = true;
- B_ClearCert.Enabled = true;
-
- if (e.Error != null)
- {
- MessageBox.Show($"Error: {e.Error.Message}");
- }
else
{
- MessageBox.Show("Done extracting NCA!");
+ cache += $"DLC:{Environment.NewLine}EMPTY";
+ }
+ TB_GameRev.Text = cache;
+ label12.Text = $"{basenum} BASE, {updnum} UPD, {dlcnum} DLC";
+
+ CB_RegionName.SelectedIndex = 0;
+
+ fileStream.Close();
+ }
+ else
+ {
+ TB_Dev.Text = $"{Mkey} not found";
+ TB_Name.Text = $"{Mkey} not found";
+ }
+ }
+
+ private void LoadNCAData()
+ {
+ NCA.NCA_Headers[0] = new NCA.NCA_Header(DecryptNCAHeader(gameNcaOffset));
+ TB_TID.Text = $"0{NCA.NCA_Headers[0].TitleID.ToString("X")}";
+ TB_SDKVer.Text = $"{NCA.NCA_Headers[0].SDKVersion4}.{NCA.NCA_Headers[0].SDKVersion3}.{NCA.NCA_Headers[0].SDKVersion2}.{NCA.NCA_Headers[0].SDKVersion1}";
+ TB_MKeyRev.Text = Util.GetMkey(NCA.NCA_Headers[0].MasterKeyRev);
+ }
+
+ //https://stackoverflow.com/questions/311165/how-do-you-convert-a-byte-array-to-a-hexadecimal-string-and-vice-versa
+ public static string ByteArrayToString(byte[] ba)
+ {
+ StringBuilder hex = new(ba.Length * 2 + 2);
+ hex.Append("0x");
+ foreach (byte b in ba)
+ {
+ hex.AppendFormat("{0:x2}", b);
+ }
+
+ return hex.ToString();
+ }
+
+ public static string SHA256Bytes(byte[] ba)
+ {
+ SHA256 mySHA256 = SHA256.Create();
+ byte[] hashValue;
+ hashValue = mySHA256.ComputeHash(ba);
+ return ByteArrayToString(hashValue);
+ }
+
+ public bool isTrimmed() => TB_ROMExactSize.Text == TB_ExactUsedSpace.Text;
+
+ private void LoadPartitions()
+ {
+ string actualHash;
+ byte[] hashBuffer;
+ long offset;
+
+ TV_Partitions.Nodes.Clear();
+ TV_Parti = new TreeViewFileSystem(TV_Partitions);
+ rootNode = new BetterTreeNode("root")
+ {
+ Offset = -1L,
+ Size = -1L
+ };
+ TV_Partitions.Nodes.Add(rootNode);
+ bool LogoPartition = false;
+ FileStream fileStream = new(TB_File.Text, FileMode.Open, FileAccess.Read);
+ HFS0.HSF0_Entry[] array = new HFS0.HSF0_Entry[HFS0.HFS0_Headers[0].FileCount];
+ fileStream.Position = XCI.XCI_Headers[0].HFS0OffsetPartition + 16 + 64 * HFS0.HFS0_Headers[0].FileCount;
+ long num = XCI.XCI_Headers[0].HFS0OffsetPartition + XCI.XCI_Headers[0].HFS0SizeParition;
+ byte[] array2 = new byte[64];
+ byte[] array3 = new byte[16];
+ byte[] array4 = new byte[24];
+ for (int i = 0; i < HFS0.HFS0_Headers[0].FileCount; i++)
+ {
+ fileStream.Position = XCI.XCI_Headers[0].HFS0OffsetPartition + 16 + 64 * i;
+ fileStream.Read(array2, 0, 64);
+ array[i] = new HFS0.HSF0_Entry(array2);
+ fileStream.Position = XCI.XCI_Headers[0].HFS0OffsetPartition + 16 + 64 * HFS0.HFS0_Headers[0].FileCount + array[i].Name_ptr;
+ int num2;
+ while ((num2 = fileStream.ReadByte()) != 0 && num2 != 0)
+ {
+ chars.Add((char)num2);
+ }
+ array[i].Name = new string(chars.ToArray());
+ chars.Clear();
+ offset = num + array[i].Offset;
+ hashBuffer = new byte[array[i].HashedRegionSize];
+ fileStream.Position = offset;
+ fileStream.Read(hashBuffer, 0, array[i].HashedRegionSize);
+ actualHash = SHA256Bytes(hashBuffer);
+
+ TV_Parti.AddFile($"{array[i].Name}.hfs0", rootNode, offset, array[i].Size, array[i].HashedRegionSize, ByteArrayToString(array[i].Hash), actualHash);
+ BetterTreeNode betterTreeNode = TV_Parti.AddDir(array[i].Name, rootNode);
+ HFS0.HFS0_Header[] array5 = new HFS0.HFS0_Header[1];
+ fileStream.Position = array[i].Offset + num;
+ fileStream.Read(array3, 0, 16);
+ array5[0] = new HFS0.HFS0_Header(array3);
+ if (array[i].Name == "secure")
+ {
+ SecureSize = new long[array5[0].FileCount];
+ SecureOffset = new long[array5[0].FileCount];
+ SecureName = new string[array5[0].FileCount];
+ }
+ if (array[i].Name == "normal")
+ {
+ NormalSize = new long[array5[0].FileCount];
+ NormalOffset = new long[array5[0].FileCount];
+ }
+ if (array[i].Name == "logo")
+ {
+ if (array5[0].FileCount > 0)
+ {
+ LogoPartition = true;
+ }
+ }
+ HFS0.HSF0_Entry[] array6 = new HFS0.HSF0_Entry[array5[0].FileCount];
+ for (int j = 0; j < array5[0].FileCount; j++)
+ {
+ fileStream.Position = array[i].Offset + num + 16 + 64 * j;
+ fileStream.Read(array2, 0, 64);
+ array6[j] = new HFS0.HSF0_Entry(array2);
+ fileStream.Position = array[i].Offset + num + 16 + 64 * array5[0].FileCount + array6[j].Name_ptr;
+ while ((num2 = fileStream.ReadByte()) != 0 && num2 != 0)
+ {
+ chars.Add((char)num2);
+ }
+ array6[j].Name = new string(chars.ToArray());
+ chars.Clear();
+ if (array[i].Name == "secure")
+ {
+ SecureSize[j] = array6[j].Size;
+ SecureOffset[j] = array[i].Offset + array6[j].Offset + num + 16 + array5[0].StringTableSize + array5[0].FileCount * 64;
+ SecureName[j] = array6[j].Name;
+ }
+ if (array[i].Name == "normal")
+ {
+ NormalSize[j] = array6[j].Size;
+ NormalOffset[j] = array[i].Offset + array6[j].Offset + num + 16 + array5[0].StringTableSize + array5[0].FileCount * 64;
+ }
+ offset = array[i].Offset + array6[j].Offset + num + 16 + array5[0].StringTableSize + array5[0].FileCount * 64;
+ hashBuffer = new byte[array6[j].HashedRegionSize];
+ fileStream.Position = offset;
+ fileStream.Read(hashBuffer, 0, array6[j].HashedRegionSize);
+ actualHash = SHA256Bytes(hashBuffer);
+
+ TV_Parti.AddFile(array6[j].Name, betterTreeNode, offset, array6[j].Size, array6[j].HashedRegionSize, ByteArrayToString(array6[j].Hash), actualHash);
+ TreeNode[] array7 = TV_Partitions.Nodes.Find(betterTreeNode.Text, true);
+ if (array7.Length != 0)
+ {
+ TV_Parti.AddFile(array6[j].Name, (BetterTreeNode)array7[0], 0L, 0L);
+ }
+ }
+ }
+ long num3 = -9223372036854775808L;
+ for (int k = 0; k < SecureSize.Length; k++)
+ {
+ if (SecureSize[k] > num3)
+ {
+ gameNcaSize = SecureSize[k];
+ gameNcaOffset = SecureOffset[k];
+ num3 = SecureSize[k];
+ }
+ }
+ PFS0Offset = gameNcaOffset + 32768;
+ fileStream.Position = PFS0Offset;
+ fileStream.Read(array3, 0, 16);
+ PFS0.PFS0_Headers[0] = new(array3);
+ if (PFS0.PFS0_Headers[0].FileCount == 2 || !LogoPartition)
+ {
+ PFS0.PFS0_Entry[] array8;
+ try
+ {
+ array8 = new PFS0.PFS0_Entry[PFS0.PFS0_Headers[0].FileCount];
+ }
+ catch (Exception ex)
+ {
+ array8 = new PFS0.PFS0_Entry[0];
+ Debug.WriteLine($"Partitions Error: {ex.Message}");
+ }
+ for (int m = 0; m < PFS0.PFS0_Headers[0].FileCount; m++)
+ {
+ fileStream.Position = PFS0Offset + 16 + 24 * m;
+ fileStream.Read(array4, 0, 24);
+ array8[m] = new(array4);
+ PFS0Size += array8[m].Size;
+ }
+ TV_Parti.AddFile("boot.psf0", rootNode, PFS0Offset, 16 + 24 * PFS0.PFS0_Headers[0].FileCount + 64 + PFS0Size);
+ BetterTreeNode betterTreeNode2 = TV_Parti.AddDir("boot", rootNode);
+ for (int n = 0; n < PFS0.PFS0_Headers[0].FileCount; n++)
+ {
+ fileStream.Position = PFS0Offset + 16 + 24 * PFS0.PFS0_Headers[0].FileCount + array8[n].Name_ptr;
+ int num4;
+ while ((num4 = fileStream.ReadByte()) != 0 && num4 != 0)
+ {
+ chars.Add((char)num4);
+ }
+ array8[n].Name = new string(chars.ToArray());
+ chars.Clear();
+ TV_Parti.AddFile(array8[n].Name, betterTreeNode2, PFS0Offset + array8[n].Offset + 16 + PFS0.PFS0_Headers[0].StringTableSize + PFS0.PFS0_Headers[0].FileCount * 24, array8[n].Size);
+ TreeNode[] array9 = TV_Partitions.Nodes.Find(betterTreeNode2.Text, true);
+ if (array9.Length != 0)
+ {
+ TV_Parti.AddFile(array8[n].Name, (BetterTreeNode)array9[0], 0L, 0L);
+ }
+ }
+ }
+ fileStream.Close();
+ }
+
+
+ private void LoadNSPPartitions()
+ {
+ long offset;
+
+ TV_Partitions.Nodes.Clear();
+ TV_Parti = new TreeViewFileSystem(TV_Partitions);
+ rootNode = new BetterTreeNode("root")
+ {
+ Offset = -1L,
+ Size = -1L
+ };
+ TV_Partitions.Nodes.Add(rootNode);
+
+
+ // Maximum number of files in NSP to read in
+ const int MAXFILES = 250;
+
+ FileStream fileStream = File.OpenRead(TB_File.Text);
+ List chars = new();
+ byte[] array = new byte[16];
+ byte[] array2 = new byte[24];
+ fileStream.Read(array, 0, 16);
+ PFS0.PFS0_Headers[0] = new(array);
+ if (!PFS0.PFS0_Headers[0].Magic.Contains("PFS0"))
+ {
+ return;
+ }
+ PFS0.PFS0_Entry[] array3;
+ array3 = new PFS0.PFS0_Entry[Math.Max(PFS0.PFS0_Headers[0].FileCount, MAXFILES)]; //Dump of TitleID 01009AA000FAA000 reports more than 10000000 files here, so it breaks the program. Standard is to have only 20 files
+ for (int m = 0; m < PFS0.PFS0_Headers[0].FileCount; m++)
+ {
+ fileStream.Position = 16 + 24 * m;
+ fileStream.Read(array2, 0, 24);
+ array3[m] = new(array2);
+
+ if (m == MAXFILES - 1) //Dump of TitleID 01009AA000FAA000 reports more than 10000000 files here, so it breaks the program. Standard is to have only 20 files
+ {
+ break;
+ }
+ }
+ for (int n = 0; n < PFS0.PFS0_Headers[0].FileCount; n++)
+ {
+ fileStream.Position = 16 + 24 * PFS0.PFS0_Headers[0].FileCount + array3[n].Name_ptr;
+ int num4;
+ while ((num4 = fileStream.ReadByte()) != 0 && num4 != 0)
+ {
+ chars.Add((char)num4);
+ }
+ array3[n].Name = new(chars.ToArray());
+ chars.Clear();
+ offset = 16 + 24 * PFS0.PFS0_Headers[0].FileCount + PFS0.PFS0_Headers[0].StringTableSize + array3[n].Offset;
+ fileStream.Position = offset;
+
+ TV_Parti.AddFile(array3[n].Name, rootNode, offset, array3[n].Size);
+ }
+
+ fileStream.Close();
+ }
+
+
+ private void TV_Partitions_AfterSelect(object sender, TreeViewEventArgs e)
+ {
+ BetterTreeNode betterTreeNode = (BetterTreeNode)TV_Partitions.SelectedNode;
+ if (betterTreeNode.Offset == -1)
+ {
+ LB_SelectedData.Text = "";
+ LB_DataOffset.Text = "";
+ LB_DataSize.Text = "";
+ LB_HashedRegionSize.Text = "";
+ LB_ExpectedHash.Text = "";
+ LB_ActualHash.Text = "";
+ B_Extract.Enabled = false;
+ return;
+ }
+
+ selectedOffset = betterTreeNode.Offset;
+ selectedSize = betterTreeNode.Size;
+ string expectedHash = betterTreeNode.ExpectedHash;
+ string actualHash = betterTreeNode.ActualHash;
+ long HashedRegionSize = betterTreeNode.HashedRegionSize;
+
+ LB_DataOffset.Text = $"Offset: 0x{selectedOffset:X}";
+ LB_SelectedData.Text = e.Node.Text;
+ if (backgroundWorker1.IsBusy != true)
+ {
+ B_Extract.Enabled = true;
+ }
+ string[] array = new string[5]
+ {
+ "B",
+ "KB",
+ "MB",
+ "GB",
+ "TB"
+ };
+ double num = selectedSize;
+ int num2 = 0;
+ while (num >= 1024.0 && num2 < array.Length - 1)
+ {
+ num2++;
+ num /= 1024.0;
+ }
+ LB_DataSize.Text = $"Size: 0x{selectedSize.ToString("X")} ({num}{array[num2]})";
+
+ if (HashedRegionSize != 0)
+ {
+ LB_HashedRegionSize.Text = $"HashedRegionSize: 0x{HashedRegionSize:X}";
+ }
+ else
+ {
+ LB_HashedRegionSize.Text = "";
+ }
+
+ if (!string.IsNullOrEmpty(expectedHash))
+ {
+ LB_ExpectedHash.Text = $"Header Hash: {expectedHash[..32]}";
+ }
+ else
+ {
+ LB_ExpectedHash.Text = "";
+ }
+
+ if (!string.IsNullOrEmpty(actualHash))
+ {
+ LB_ActualHash.Text = $"Actual Hash: {actualHash[..32]}";
+ if (actualHash == expectedHash)
+ {
+ LB_ActualHash.ForeColor = Color.Green;
+ }
+ else
+ {
+ LB_ActualHash.ForeColor = Color.Red;
+ }
+ }
+ else
+ {
+ LB_ActualHash.Text = "";
+ }
+ }
+
+ public bool CheckXCI()
+ {
+ FileStream fileStream = new(TB_File.Text, FileMode.Open, FileAccess.Read);
+ byte[] array = new byte[61440];
+ byte[] array2 = new byte[16];
+ fileStream.Read(array, 0, 61440);
+ XCI.XCI_Headers[0] = new XCI.XCI_Header(array);
+ if (!XCI.XCI_Headers[0].Magic.Contains("HEAD"))
+ {
+ return false;
+ }
+ fileStream.Position = XCI.XCI_Headers[0].HFS0OffsetPartition;
+ fileStream.Read(array2, 0, 16);
+ HFS0.HFS0_Headers[0] = new HFS0.HFS0_Header(array2);
+ fileStream.Close();
+ return true;
+ }
+
+ public bool CheckNSP()
+ {
+ FileStream fileStream = File.OpenRead(TB_File.Text);
+ byte[] array = new byte[16];
+ fileStream.Read(array, 0, 16);
+ PFS0.PFS0_Headers[0] = new(array);
+ fileStream.Close();
+ if (!PFS0.PFS0_Headers[0].Magic.Contains("PFS0"))
+ {
+ return false;
+ }
+ return true;
+ }
+
+ private void B_ExportCert_Click(object sender, EventArgs e)
+ {
+ new CenterWinDialog(this);
+ if (!File.Exists(TB_File.Text))
+ {
+ MessageBox.Show("File not found");
+ return;
+ }
+
+ SaveFileDialog saveFileDialog = new SaveFileDialog();
+ saveFileDialog.Filter = "gamecard_cert.dat (*.dat)|*.dat";
+ saveFileDialog.FileName = Path.GetFileName("gamecard_cert.dat");
+ if (saveFileDialog.ShowDialog() != DialogResult.OK)
+ {
+ return;
+ }
+
+ FileStream fileStream = new(TB_File.Text, FileMode.Open, FileAccess.Read);
+ byte[] array = new byte[512];
+ fileStream.Position = 28672L;
+ fileStream.Read(array, 0, 512);
+ File.WriteAllBytes(saveFileDialog.FileName, array);
+ fileStream.Close();
+ MessageBox.Show($"Cert successfully exported to:\n\n{saveFileDialog.FileName}");
+ }
+
+ private void B_ImportCert_Click(object sender, EventArgs e)
+ {
+ new CenterWinDialog(this);
+ if (!File.Exists(TB_File.Text))
+ {
+ MessageBox.Show("File not found");
+ return;
+ }
+ OpenFileDialog openFileDialog = new OpenFileDialog();
+ openFileDialog.Filter = "gamecard_cert (*.dat)|*.dat|All files (*.*)|*.*";
+ if (openFileDialog.ShowDialog() == DialogResult.OK && new FileInfo(openFileDialog.FileName).Length == 512)
+ {
+ using (Stream stream = File.Open(TB_File.Text, FileMode.Open))
+ {
+ stream.Position = 28672L;
+ stream.Write(File.ReadAllBytes(openFileDialog.FileName), 0, 512);
+ }
+ MessageBox.Show($"Cert successfully imported from:\n\n{openFileDialog.FileName}");
+ }
+ }
+
+ private void B_ViewCert_Click(object sender, EventArgs e)
+ {
+ new CenterWinDialog(this);
+ if (!File.Exists(TB_File.Text))
+ {
+ MessageBox.Show("File not found");
+ return;
+ }
+ CertForm cert = new(this)
+ {
+ Text = $"Cert Data - {TB_File.Text}"
+ };
+ cert.Show();
+ }
+
+ private void B_ClearCert_Click(object sender, EventArgs e)
+ {
+ new CenterWinDialog(this);
+
+ if (!File.Exists(TB_File.Text))
+ {
+ MessageBox.Show("File not found");
+ return;
+ }
+
+ if (MessageBox.Show("The cert will be deleted permanently.\nContinue?", "XCI Explorer", MessageBoxButtons.YesNo) != DialogResult.Yes)
+ {
+ return;
+ }
+
+ using Stream stream = File.Open(TB_File.Text, FileMode.Open);
+ byte[] array = new byte[512];
+ for (int i = 0; i < array.Length; i++)
+ {
+ array[i] = byte.MaxValue;
+ }
+ stream.Position = 28672L;
+ stream.Write(array, 0, array.Length);
+
+ new CenterWinDialog(this);
+ MessageBox.Show("Cert deleted.");
+
+ }
+
+ private void B_Extract_Click(object sender, EventArgs e)
+ {
+ SaveFileDialog saveFileDialog = new SaveFileDialog
+ {
+ FileName = LB_SelectedData.Text
+ };
+
+ if (saveFileDialog.ShowDialog() != DialogResult.OK)
+ {
+ return;
+ }
+
+ if (backgroundWorker1.IsBusy)
+ {
+ return;
+ }
+
+ B_Extract.Enabled = false;
+ B_LoadROM.Enabled = false;
+ B_TrimXCI.Enabled = false;
+ B_ImportCert.Enabled = false;
+ B_ClearCert.Enabled = false;
+
+ // Start the asynchronous operation.
+ backgroundWorker1.RunWorkerAsync(saveFileDialog.FileName);
+ }
+
+ public byte[] DecryptNCAHeader(long offset)
+ {
+ byte[] array = new byte[3072];
+
+ if (!File.Exists(TB_File.Text))
+ {
+ return array;
+ }
+
+ FileStream fileStream = new(TB_File.Text, FileMode.Open, FileAccess.Read)
+ {
+ Position = offset
+ };
+ fileStream.Read(array, 0, 3072);
+ File.WriteAllBytes($"{TB_File.Text}.tmp", array);
+ Xts xts = XtsAes128.Create(NcaHeaderEncryptionKey1_Prod, NcaHeaderEncryptionKey2_Prod);
+ using (BinaryReader binaryReader = new(File.OpenRead($"{TB_File.Text}.tmp")))
+ {
+ using XtsStream xtsStream = new(binaryReader.BaseStream, xts, 512);
+ xtsStream.Read(array, 0, 3072);
+ }
+ File.Delete($"{TB_File.Text}.tmp");
+ fileStream.Close();
+ return array;
+ }
+
+ private void CB_RegionName_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ int num = Array.FindIndex(Language, (string element) => element.StartsWith(CB_RegionName.Text, StringComparison.Ordinal));
+ // Icons for 1-2 Switch in some languages are "missing"
+ // This just shows the first real icon instead of a blank
+ if (Icons[num] != null)
+ {
+ PB_GameIcon.BackgroundImage = Icons[num];
+ }
+ else
+ {
+ for (int i = 0; i < CB_RegionName.Items.Count; i++)
+ {
+ if (Icons[i] == null)
+ {
+ continue;
+ }
+
+ PB_GameIcon.BackgroundImage = Icons[i];
+ break;
+ }
+ }
+ TB_Name.Text = NACP.NACP_Strings[num].GameName;
+ TB_Dev.Text = NACP.NACP_Strings[num].GameAuthor;
+ }
+
+ private void B_TrimXCI_Click(object sender, EventArgs e)
+ {
+ new CenterWinDialog(this);
+
+ if (!File.Exists(TB_File.Text))
+ {
+ MessageBox.Show("File not found");
+ return;
+ }
+
+ if (MessageBox.Show("Trim XCI?", "XCI Explorer", MessageBoxButtons.YesNo) != DialogResult.Yes)
+ {
+ return;
+ }
+
+ new CenterWinDialog(this);
+
+ if (isTrimmed())
+ {
+ return;
+ }
+
+ FileStream fileStream = new(TB_File.Text, FileMode.Open, FileAccess.Write);
+ fileStream.SetLength((long)UsedSize);
+ fileStream.Close();
+ B_TrimXCI.Enabled = false;
+ MessageBox.Show("Done.");
+ string[] array = new string[5]
+ {
+ "B",
+ "KB",
+ "MB",
+ "GB",
+ "TB"
+ };
+ double num = new FileInfo(TB_File.Text).Length;
+ TB_ROMExactSize.Text = $"({num} bytes)";
+ int num2 = 0;
+ while (num >= 1024.0 && num2 < array.Length - 1)
+ {
+ num2++;
+ num /= 1024.0;
+ }
+ TB_ROMSize.Text = $"{num:0.##} {array[num2]}";
+ double num3 = UsedSize = XCI.XCI_Headers[0].CardSize2 * 512 + 512;
+ TB_ExactUsedSpace.Text = $"({num3} bytes)";
+ num2 = 0;
+ while (num3 >= 1024.0 && num2 < array.Length - 1)
+ {
+ num2++;
+ num3 /= 1024.0;
+ }
+ TB_UsedSpace.Text = $"{num3:0.##} {array[num2]}";
+ }
+
+ private void LB_ExpectedHash_DoubleClick(object sender, EventArgs e)
+ {
+ BetterTreeNode betterTreeNode = (BetterTreeNode)TV_Partitions.SelectedNode;
+ if (betterTreeNode.Offset != -1)
+ {
+ Clipboard.SetText(betterTreeNode.ExpectedHash);
+ }
+ }
+
+ private void LB_ActualHash_DoubleClick(object sender, EventArgs e)
+ {
+ BetterTreeNode betterTreeNode = (BetterTreeNode)TV_Partitions.SelectedNode;
+ if (betterTreeNode.Offset != -1)
+ {
+ Clipboard.SetText(betterTreeNode.ActualHash);
+ }
+ }
+
+ private void TB_File_DragDrop(object sender, DragEventArgs e)
+ {
+ if (backgroundWorker1.IsBusy != true)
+ {
+ string[] files = e.Data.GetData(DataFormats.FileDrop) as string[];
+ TB_File.Text = files[0];
+ ProcessFile();
+ }
+ }
+
+ private void TB_File_DragEnter(object sender, DragEventArgs e)
+ {
+ if (backgroundWorker1.IsBusy)
+ {
+ return;
+ }
+
+ if (e.Data.GetDataPresent(DataFormats.FileDrop))
+ {
+ e.Effect = DragDropEffects.Copy;
+ }
+ else
+ {
+ e.Effect = DragDropEffects.None;
+ }
+ }
+
+ private void TABP_XCI_DragDrop(object sender, DragEventArgs e)
+ {
+ if (backgroundWorker1.IsBusy)
+ {
+ return;
+ }
+
+ string[] files = e.Data.GetData(DataFormats.FileDrop) as string[];
+ TB_File.Text = files[0];
+ ProcessFile();
+ }
+
+ private void TABP_XCI_DragEnter(object sender, DragEventArgs e)
+ {
+ if (backgroundWorker1.IsBusy)
+ {
+ return;
+ }
+
+ if (e.Data.GetDataPresent(DataFormats.FileDrop))
+ {
+ e.Effect = DragDropEffects.Copy;
+ }
+ else
+ {
+ e.Effect = DragDropEffects.None;
+ }
+ }
+
+ private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
+ {
+ BackgroundWorker worker = sender as BackgroundWorker;
+ string fileName = (string)e.Argument;
+
+ using FileStream fileStream = File.OpenRead(TB_File.Text);
+ using FileStream fileStream2 = File.OpenWrite(fileName);
+ new BinaryReader(fileStream);
+ new BinaryWriter(fileStream2);
+ fileStream.Position = selectedOffset;
+ long num = selectedSize;
+
+ if (selectedSize < 10000)
+ {
+ byte[] buffer = new byte[1];
+ int num2;
+ while ((num2 = fileStream.Read(buffer, 0, 1)) > 0 && num > 0)
+ {
+ fileStream2.Write(buffer, 0, num2);
+ num -= num2;
+ }
+ }
+ else
+ {
+ byte[] buffer = new byte[8192];
+ int num2;
+ while ((num2 = fileStream.Read(buffer, 0, 8192)) > 0 && num > 0)
+ {
+ fileStream2.Write(buffer, 0, num2);
+ num -= num2;
}
}
- private void TABP_XCI_Click(object sender, EventArgs e)
+ fileStream.Close();
+ }
+
+ private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
+ {
+ new CenterWinDialog(this);
+ B_Extract.Enabled = true;
+ B_LoadROM.Enabled = true;
+ B_TrimXCI.Enabled = true;
+ B_ImportCert.Enabled = true;
+ B_ClearCert.Enabled = true;
+
+ if (e.Error != null)
{
-
+ MessageBox.Show($"Error: {e.Error.Message}");
}
-
- private void label11_Click(object sender, EventArgs e)
+ else
{
-
+ MessageBox.Show("Done extracting NCA!");
}
+ }
+
+ private void TABP_XCI_Click(object sender, EventArgs e)
+ {
}
+
+ private void label11_Click(object sender, EventArgs e)
+ {
+
+ }
+
}
\ No newline at end of file
diff --git a/XCI_Explorer/NACP.cs b/XCI_Explorer/NACP.cs
index cb9c647..a46d9db 100644
--- a/XCI_Explorer/NACP.cs
+++ b/XCI_Explorer/NACP.cs
@@ -1,42 +1,41 @@
using System.Linq;
using System.Text;
-namespace XCI_Explorer
+namespace XCI_Explorer;
+
+public static class NACP
{
- public static class NACP
+ public class NACP_String
{
- public class NACP_String
+ public byte[] Data;
+ public byte Check;
+ public string GameName;
+ public string GameAuthor;
+
+ public NACP_String(byte[] data)
{
- public byte[] Data;
- public byte Check;
- public string GameName;
- public string GameAuthor;
-
- public NACP_String(byte[] data)
- {
- Data = data;
- Check = Data[0];
- GameName = Encoding.UTF8.GetString(Data.Take(512).ToArray());
- GameAuthor = Encoding.UTF8.GetString(Data.Skip(512).Take(256).ToArray());
- }
+ Data = data;
+ Check = Data[0];
+ GameName = Encoding.UTF8.GetString(Data.Take(512).ToArray());
+ GameAuthor = Encoding.UTF8.GetString(Data.Skip(512).Take(256).ToArray());
}
-
- public class NACP_Data
- {
- public byte[] Data;
- public string GameVer;
- public string GameProd;
-
- public NACP_Data(byte[] data)
- {
- Data = data;
- GameVer = Encoding.UTF8.GetString(Data.Skip(0x60).Take(16).ToArray());
- GameProd = Encoding.UTF8.GetString(Data.Skip(0xA8).Take(8).ToArray());
- }
- }
-
- public static NACP_String[] NACP_Strings = new NACP_String[16];
-
- public static NACP_Data[] NACP_Datas = new NACP_Data[1];
}
+
+ public class NACP_Data
+ {
+ public byte[] Data;
+ public string GameVer;
+ public string GameProd;
+
+ public NACP_Data(byte[] data)
+ {
+ Data = data;
+ GameVer = Encoding.UTF8.GetString(Data.Skip(0x60).Take(16).ToArray());
+ GameProd = Encoding.UTF8.GetString(Data.Skip(0xA8).Take(8).ToArray());
+ }
+ }
+
+ public static NACP_String[] NACP_Strings = new NACP_String[16];
+
+ public static NACP_Data[] NACP_Datas = new NACP_Data[1];
}
diff --git a/XCI_Explorer/NCA.cs b/XCI_Explorer/NCA.cs
index f23ba9b..a789be6 100644
--- a/XCI_Explorer/NCA.cs
+++ b/XCI_Explorer/NCA.cs
@@ -2,34 +2,33 @@ using System;
using System.Linq;
using System.Text;
-namespace XCI_Explorer
+namespace XCI_Explorer;
+
+internal static class NCA
{
- internal static class NCA
+ public class NCA_Header
{
- public class NCA_Header
+ public byte[] Data;
+ public string Magic;
+ public long TitleID;
+ public byte SDKVersion1;
+ public byte SDKVersion2;
+ public byte SDKVersion3;
+ public byte SDKVersion4;
+ public byte MasterKeyRev;
+
+ public NCA_Header(byte[] data)
{
- public byte[] Data;
- public string Magic;
- public long TitleID;
- public byte SDKVersion1;
- public byte SDKVersion2;
- public byte SDKVersion3;
- public byte SDKVersion4;
- public byte MasterKeyRev;
-
- public NCA_Header(byte[] data)
- {
- Data = data;
- Magic = Encoding.UTF8.GetString(Data.Skip(512).Take(4).ToArray());
- TitleID = BitConverter.ToInt64(data, 528);
- SDKVersion1 = Data[540];
- SDKVersion2 = Data[541];
- SDKVersion3 = Data[542];
- SDKVersion4 = Data[543];
- MasterKeyRev = Data[544];
- }
+ Data = data;
+ Magic = Encoding.UTF8.GetString(Data.Skip(512).Take(4).ToArray());
+ TitleID = BitConverter.ToInt64(data, 528);
+ SDKVersion1 = Data[540];
+ SDKVersion2 = Data[541];
+ SDKVersion3 = Data[542];
+ SDKVersion4 = Data[543];
+ MasterKeyRev = Data[544];
}
-
- public static NCA_Header[] NCA_Headers = new NCA_Header[1];
}
+
+ public static NCA_Header[] NCA_Headers = new NCA_Header[1];
}
diff --git a/XCI_Explorer/PFS0.cs b/XCI_Explorer/PFS0.cs
index b36158f..303e935 100644
--- a/XCI_Explorer/PFS0.cs
+++ b/XCI_Explorer/PFS0.cs
@@ -2,47 +2,46 @@ using System;
using System.Linq;
using System.Text;
-namespace XCI_Explorer
+namespace XCI_Explorer;
+
+internal static class PFS0
{
- internal static class PFS0
+ public class PFS0_Header
{
- public class PFS0_Header
+ public byte[] Data;
+ public string Magic;
+ public int FileCount;
+ public int StringTableSize;
+ public int Reserved;
+
+ public PFS0_Header(byte[] data)
{
- public byte[] Data;
- public string Magic;
- public int FileCount;
- public int StringTableSize;
- public int Reserved;
-
- public PFS0_Header(byte[] data)
- {
- Data = data;
- Magic = Encoding.UTF8.GetString(Data.Take(4).ToArray());
- FileCount = BitConverter.ToInt32(data, 4);
- StringTableSize = BitConverter.ToInt32(data, 8);
- Reserved = BitConverter.ToInt32(data, 12);
- }
+ Data = data;
+ Magic = Encoding.UTF8.GetString(Data.Take(4).ToArray());
+ FileCount = BitConverter.ToInt32(data, 4);
+ StringTableSize = BitConverter.ToInt32(data, 8);
+ Reserved = BitConverter.ToInt32(data, 12);
}
-
- public class PFS0_Entry
- {
- public byte[] Data;
- public long Offset;
- public long Size;
- public int Name_ptr;
- public int Reserved;
- public string Name;
-
- public PFS0_Entry(byte[] data)
- {
- Data = data;
- Offset = BitConverter.ToInt64(data, 0);
- Size = BitConverter.ToInt64(data, 8);
- Name_ptr = BitConverter.ToInt32(data, 16);
- Reserved = BitConverter.ToInt32(data, 20);
- }
- }
-
- public static PFS0_Header[] PFS0_Headers = new PFS0_Header[1];
}
+
+ public class PFS0_Entry
+ {
+ public byte[] Data;
+ public long Offset;
+ public long Size;
+ public int Name_ptr;
+ public int Reserved;
+ public string Name;
+
+ public PFS0_Entry(byte[] data)
+ {
+ Data = data;
+ Offset = BitConverter.ToInt64(data, 0);
+ Size = BitConverter.ToInt64(data, 8);
+ Name_ptr = BitConverter.ToInt32(data, 16);
+ Reserved = BitConverter.ToInt32(data, 20);
+ }
+ }
+
+ public static PFS0_Header[] PFS0_Headers = new PFS0_Header[1];
}
diff --git a/XCI_Explorer/Program.cs b/XCI_Explorer/Program.cs
index 2c9f687..0094802 100644
--- a/XCI_Explorer/Program.cs
+++ b/XCI_Explorer/Program.cs
@@ -1,28 +1,26 @@
using System;
+using System.IO;
using System.Windows.Forms;
-namespace XCI_Explorer
-{
- internal static class Program
- {
- [STAThread]
- private static void Main()
- {
- AppDomain.CurrentDomain.AssemblyResolve += (Object sender, ResolveEventArgs args) =>
- {
- System.Reflection.AssemblyName embeddedAssembly = new System.Reflection.AssemblyName(args.Name);
- String resourceName = "XCI_Explorer" + "." + embeddedAssembly.Name + ".dll";
+namespace XCI_Explorer;
- using (var stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
- {
- Byte[] assemblyData = new Byte[stream.Length];
- stream.Read(assemblyData, 0, assemblyData.Length);
- return System.Reflection.Assembly.Load(assemblyData);
- }
- };
- Application.EnableVisualStyles();
- Application.SetCompatibleTextRenderingDefault(false);
- Application.Run(new MainForm());
- }
+internal static class Program
+{
+ [STAThread]
+ private static void Main()
+ {
+ AppDomain.CurrentDomain.AssemblyResolve += (object sender, ResolveEventArgs args) =>
+ {
+ System.Reflection.AssemblyName embeddedAssembly = new System.Reflection.AssemblyName(args.Name);
+ string resourceName = "XCI_Explorer" + "." + embeddedAssembly.Name + ".dll";
+
+ using Stream stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
+ byte[] assemblyData = new byte[stream.Length];
+ stream.Read(assemblyData, 0, assemblyData.Length);
+ return System.Reflection.Assembly.Load(assemblyData);
+ };
+ Application.EnableVisualStyles();
+ Application.SetCompatibleTextRenderingDefault(false);
+ Application.Run(new MainForm());
}
}
diff --git a/XCI_Explorer/TreeViewFileSystem.cs b/XCI_Explorer/TreeViewFileSystem.cs
index 1a54ce3..8cda4f9 100644
--- a/XCI_Explorer/TreeViewFileSystem.cs
+++ b/XCI_Explorer/TreeViewFileSystem.cs
@@ -1,40 +1,40 @@
using System.Windows.Forms;
using XCI_Explorer.Helpers;
-namespace XCI_Explorer
+namespace XCI_Explorer;
+
+public class TreeViewFileSystem
{
- public class TreeViewFileSystem
+ public TreeView treeView;
+
+ public TreeViewFileSystem(TreeView tv)
{
- public TreeView treeView;
+ }
- public TreeViewFileSystem(TreeView tv)
+ public BetterTreeNode AddDir(string name, BetterTreeNode parent = null)
+ {
+ BetterTreeNode betterTreeNode = new(name)
{
- }
+ Offset = -1L,
+ Size = -1L
+ };
+ parent.Nodes.Add(betterTreeNode);
+ return betterTreeNode;
+ }
- public BetterTreeNode AddDir(string name, BetterTreeNode parent = null)
- {
- BetterTreeNode betterTreeNode = new BetterTreeNode(name);
- betterTreeNode.Offset = -1L;
- betterTreeNode.Size = -1L;
- parent.Nodes.Add(betterTreeNode);
- return betterTreeNode;
- }
+ public BetterTreeNode AddFile(string name, BetterTreeNode parent, long offset, long size) => AddFile(name, parent, offset, size, 0, "", "");
- public BetterTreeNode AddFile(string name, BetterTreeNode parent, long offset, long size)
+ public BetterTreeNode AddFile(string name, BetterTreeNode parent, long offset, long size, long HashedRegionSize, string ExpectedHash, string ActualHash)
+ {
+ BetterTreeNode betterTreeNode = new(name)
{
- return AddFile(name, parent, offset, size, 0, "", "");
- }
-
- public BetterTreeNode AddFile(string name, BetterTreeNode parent, long offset, long size, long HashedRegionSize, string ExpectedHash, string ActualHash)
- {
- BetterTreeNode betterTreeNode = new BetterTreeNode(name);
- betterTreeNode.Offset = offset;
- betterTreeNode.Size = size;
- betterTreeNode.ExpectedHash = ExpectedHash;
- betterTreeNode.ActualHash = ActualHash;
- betterTreeNode.HashedRegionSize = HashedRegionSize;
- parent.Nodes.Add(betterTreeNode);
- return betterTreeNode;
- }
+ Offset = offset,
+ Size = size,
+ ExpectedHash = ExpectedHash,
+ ActualHash = ActualHash,
+ HashedRegionSize = HashedRegionSize
+ };
+ parent.Nodes.Add(betterTreeNode);
+ return betterTreeNode;
}
}
diff --git a/XCI_Explorer/Util.cs b/XCI_Explorer/Util.cs
index a7ce235..0527d14 100644
--- a/XCI_Explorer/Util.cs
+++ b/XCI_Explorer/Util.cs
@@ -1,130 +1,73 @@
using System;
-using System.IO;
using System.Linq;
+using System.Text;
-namespace XCI_Explorer
+namespace XCI_Explorer;
+
+internal static class Util
{
- internal static class Util
+ public static string GetCapacity(int id)
{
- public static string GetCapacity(int id)
+ return id switch
{
- switch (id)
- {
- case 250:
- return "1GB";
- case 248:
- return "2GB";
- case 240:
- return "4GB";
- case 224:
- return "8GB";
- case 225:
- return "16GB";
- case 226:
- return "32GB";
- default:
- return "?";
- }
- }
-
- public static string GetMkey(byte id)
- {
- switch (id)
- {
- case 0:
- case 1:
- return "MasterKey0 (1.0.0-2.3.0)";
- case 2:
- return "MasterKey1 (3.0.0)";
- case 3:
- return "MasterKey2 (3.0.1-3.0.2)";
- case 4:
- return "MasterKey3 (4.0.0-4.1.0)";
- case 5:
- return "MasterKey4 (5.0.0-5.1.0)";
- case 6:
- return "MasterKey5 (6.0.0-6.1.0)";
- case 7:
- return "MasterKey6 (6.2.0)";
- case 8:
- return "MasterKey7 (7.0.0-8.0.1)";
- case 9:
- return "MasterKey8 (8.1.0-8.1.1)";
- case 10:
- return "MasterKey9 (9.0.0-9.0.1)";
- case 11:
- return "MasterKey10 (9.1.0-12.0.3)";
- case 12:
- return "MasterKey11 (12.1.0)";
- case 13:
- return "MasterKey12 (13.0.0-?)";
- case 14:
- return "MasterKey13";
- case 15:
- return "MasterKey14";
- case 16:
- return "MasterKey15";
- case 17:
- return "MasterKey16";
- case 18:
- return "MasterKey17";
- case 19:
- return "MasterKey18";
- case 20:
- return "MasterKey19";
- case 21:
- return "MasterKey20";
- case 22:
- return "MasterKey21";
- case 23:
- return "MasterKey22";
- case 24:
- return "MasterKey23";
- case 25:
- return "MasterKey24";
- case 26:
- return "MasterKey25";
- case 27:
- return "MasterKey26";
- case 28:
- return "MasterKey27";
- case 29:
- return "MasterKey28";
- case 30:
- return "MasterKey29";
- case 31:
- return "MasterKey30";
- case 32:
- return "MasterKey31";
- case 33:
- return "MasterKey32";
- default:
- return "?";
- }
- }
-
- public static bool checkFile(string filepath)
- {
- return File.Exists(filepath);
- }
-
- public static byte[] StringToByteArray(string hex)
- {
- return (from x in Enumerable.Range(0, hex.Length)
- where x % 2 == 0
- select Convert.ToByte(hex.Substring(x, 2), 16)).ToArray();
- }
-
- public static string Base64Encode(string plainText)
- {
- var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
- return System.Convert.ToBase64String(plainTextBytes);
- }
-
- public static string Base64Decode(string base64EncodedData)
- {
- var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
- return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
- }
+ 250 => "1GB",
+ 248 => "2GB",
+ 240 => "4GB",
+ 224 => "8GB",
+ 225 => "16GB",
+ 226 => "32GB",
+ _ => "?",
+ };
}
+
+ public static string GetMkey(byte id)
+ {
+ return id switch
+ {
+ 0 or 1 => "MasterKey0 (1.0.0-2.3.0)",
+ 2 => "MasterKey1 (3.0.0)",
+ 3 => "MasterKey2 (3.0.1-3.0.2)",
+ 4 => "MasterKey3 (4.0.0-4.1.0)",
+ 5 => "MasterKey4 (5.0.0-5.1.0)",
+ 6 => "MasterKey5 (6.0.0-6.1.0)",
+ 7 => "MasterKey6 (6.2.0)",
+ 8 => "MasterKey7 (7.0.0-8.0.1)",
+ 9 => "MasterKey8 (8.1.0-8.1.1)",
+ 10 => "MasterKey9 (9.0.0-9.0.1)",
+ 11 => "MasterKey10 (9.1.0-12.0.3)",
+ 12 => "MasterKey11 (12.1.0)",
+ 13 => "MasterKey12 (13.0.0-?)",
+ 14 => "MasterKey13",
+ 15 => "MasterKey14",
+ 16 => "MasterKey15",
+ 17 => "MasterKey16",
+ 18 => "MasterKey17",
+ 19 => "MasterKey18",
+ 20 => "MasterKey19",
+ 21 => "MasterKey20",
+ 22 => "MasterKey21",
+ 23 => "MasterKey22",
+ 24 => "MasterKey23",
+ 25 => "MasterKey24",
+ 26 => "MasterKey25",
+ 27 => "MasterKey26",
+ 28 => "MasterKey27",
+ 29 => "MasterKey28",
+ 30 => "MasterKey29",
+ 31 => "MasterKey30",
+ 32 => "MasterKey31",
+ 33 => "MasterKey32",
+ _ => "?",
+ };
+ }
+
+ public static byte[] StringToByteArray(string hex) => (from x in Enumerable.Range(0, hex.Length)
+ where x % 2 == 0
+ select Convert.ToByte(hex.Substring(x, 2), 16)).ToArray();
+
+ public static string Base64Encode(string plainText)
+ => Convert.ToBase64String(Encoding.UTF8.GetBytes(plainText));
+
+ public static string Base64Decode(string base64EncodedData)
+ => Encoding.UTF8.GetString(Convert.FromBase64String(base64EncodedData));
}
diff --git a/XCI_Explorer/XCI.cs b/XCI_Explorer/XCI.cs
index 6a22152..613597b 100644
--- a/XCI_Explorer/XCI.cs
+++ b/XCI_Explorer/XCI.cs
@@ -2,30 +2,29 @@ using System;
using System.Linq;
using System.Text;
-namespace XCI_Explorer
+namespace XCI_Explorer;
+
+public static class XCI
{
- public static class XCI
+ public class XCI_Header
{
- public class XCI_Header
+ public byte[] Data;
+ public string Magic;
+ public byte CardSize1;
+ public long CardSize2;
+ public long HFS0OffsetPartition;
+ public long HFS0SizeParition;
+
+ public XCI_Header(byte[] data)
{
- public byte[] Data;
- public string Magic;
- public byte CardSize1;
- public long CardSize2;
- public long HFS0OffsetPartition;
- public long HFS0SizeParition;
-
- public XCI_Header(byte[] data)
- {
- Data = data;
- Magic = Encoding.UTF8.GetString(Data.Skip(256).Take(4).ToArray());
- CardSize1 = Data[269];
- CardSize2 = BitConverter.ToInt64(data, 280);
- HFS0OffsetPartition = BitConverter.ToInt64(data, 304);
- HFS0SizeParition = BitConverter.ToInt64(data, 312);
- }
+ Data = data;
+ Magic = Encoding.UTF8.GetString(Data.Skip(256).Take(4).ToArray());
+ CardSize1 = Data[269];
+ CardSize2 = BitConverter.ToInt64(data, 280);
+ HFS0OffsetPartition = BitConverter.ToInt64(data, 304);
+ HFS0SizeParition = BitConverter.ToInt64(data, 312);
}
-
- public static XCI_Header[] XCI_Headers = new XCI_Header[1];
}
+
+ public static XCI_Header[] XCI_Headers = new XCI_Header[1];
}
diff --git a/XTSSharp/RandomAccessSectorStream.cs b/XTSSharp/RandomAccessSectorStream.cs
index 4ed6ed2..6361b40 100644
--- a/XTSSharp/RandomAccessSectorStream.cs
+++ b/XTSSharp/RandomAccessSectorStream.cs
@@ -1,195 +1,190 @@
using System;
using System.IO;
-namespace XTSSharp
+namespace XTSSharp;
+
+public class RandomAccessSectorStream : Stream
{
- public class RandomAccessSectorStream : Stream
+ private readonly byte[] _buffer;
+ private readonly int _bufferSize;
+ private readonly SectorStream _s;
+ private readonly bool _isStreamOwned;
+ private bool _bufferDirty;
+ private bool _bufferLoaded;
+ private int _bufferPos;
+ public override bool CanRead => _s.CanRead;
+ public override bool CanSeek => _s.CanSeek;
+ public override bool CanWrite => _s.CanWrite;
+ public override long Length => _s.Length + _bufferPos;
+
+ public override long Position
{
- private readonly byte[] _buffer;
- private readonly int _bufferSize;
- private readonly SectorStream _s;
- private readonly bool _isStreamOwned;
- private bool _bufferDirty;
- private bool _bufferLoaded;
- private int _bufferPos;
- public override bool CanRead => _s.CanRead;
- public override bool CanSeek => _s.CanSeek;
- public override bool CanWrite => _s.CanWrite;
- public override long Length => _s.Length + _bufferPos;
-
- public override long Position {
- get {
- if (!_bufferLoaded)
- {
- return _s.Position + _bufferPos;
- }
- return _s.Position - _bufferSize + _bufferPos;
- }
- set {
- if (value < 0)
- {
- throw new ArgumentOutOfRangeException("value");
- }
- long num = value % _bufferSize;
- long position = value - num;
- if (_bufferLoaded)
- {
- long num2 = _s.Position - _bufferSize;
- if (value > num2 && value < num2 + _bufferSize)
- {
- _bufferPos = (int)num;
- return;
- }
- }
- if (_bufferDirty)
- {
- WriteSector();
- }
- _s.Position = position;
- ReadSector();
- _bufferPos = (int)num;
- }
- }
-
- public RandomAccessSectorStream(SectorStream s)
- : this(s, false)
+ get
{
- }
-
- public RandomAccessSectorStream(SectorStream s, bool isStreamOwned)
- {
- _s = s;
- _isStreamOwned = isStreamOwned;
- _buffer = new byte[s.SectorSize];
- _bufferSize = s.SectorSize;
- }
-
- protected override void Dispose(bool disposing)
- {
- Flush();
- base.Dispose(disposing);
- if (_isStreamOwned)
+ if (!_bufferLoaded)
{
- _s.Dispose();
+ return _s.Position + _bufferPos;
}
+ return _s.Position - _bufferSize + _bufferPos;
}
-
- public override void Flush()
+ set
{
+ if (value < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+ long num = value % _bufferSize;
+ long position = value - num;
+ if (_bufferLoaded)
+ {
+ long num2 = _s.Position - _bufferSize;
+ if (value > num2 && value < num2 + _bufferSize)
+ {
+ _bufferPos = (int)num;
+ return;
+ }
+ }
if (_bufferDirty)
{
WriteSector();
}
+ _s.Position = position;
+ ReadSector();
+ _bufferPos = (int)num;
}
+ }
- public override long Seek(long offset, SeekOrigin origin)
+ public RandomAccessSectorStream(SectorStream s)
+ : this(s, false)
+ {
+ }
+
+ public RandomAccessSectorStream(SectorStream s, bool isStreamOwned)
+ {
+ _s = s;
+ _isStreamOwned = isStreamOwned;
+ _buffer = new byte[s.SectorSize];
+ _bufferSize = s.SectorSize;
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ Flush();
+ base.Dispose(disposing);
+ if (_isStreamOwned)
{
- long num;
- switch (origin)
- {
- case SeekOrigin.Begin:
- num = offset;
- break;
- case SeekOrigin.End:
- num = Length - offset;
- break;
- default:
- num = Position + offset;
- break;
- }
- Position = num;
- return num;
+ _s.Dispose();
}
+ }
- public override void SetLength(long value)
+ public override void Flush()
+ {
+ if (_bufferDirty)
{
- long num = value % _s.SectorSize;
- if (num > 0)
- {
- value = value - num + _bufferSize;
- }
- _s.SetLength(value);
+ WriteSector();
}
+ }
- public override int Read(byte[] buffer, int offset, int count)
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ long num = origin switch
{
- long position = Position;
- if (position + count > _s.Length)
+ SeekOrigin.Begin => offset,
+ SeekOrigin.End => Length - offset,
+ _ => Position + offset,
+ };
+ Position = num;
+ return num;
+ }
+
+ public override void SetLength(long value)
+ {
+ long num = value % _s.SectorSize;
+ if (num > 0)
+ {
+ value = value - num + _bufferSize;
+ }
+ _s.SetLength(value);
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ long position = Position;
+ if (position + count > _s.Length)
+ {
+ count = (int)(_s.Length - position);
+ }
+ if (!_bufferLoaded)
+ {
+ ReadSector();
+ }
+ int num = 0;
+ while (count > 0)
+ {
+ int num2 = Math.Min(count, _bufferSize - _bufferPos);
+ Buffer.BlockCopy(_buffer, _bufferPos, buffer, offset, num2);
+ offset += num2;
+ _bufferPos += num2;
+ count -= num2;
+ num += num2;
+ if (_bufferPos == _bufferSize)
{
- count = (int)(_s.Length - position);
+ ReadSector();
}
+ }
+ return num;
+ }
+
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ while (count > 0)
+ {
if (!_bufferLoaded)
{
ReadSector();
}
- int num = 0;
- while (count > 0)
- {
- int num2 = Math.Min(count, _bufferSize - _bufferPos);
- Buffer.BlockCopy(_buffer, _bufferPos, buffer, offset, num2);
- offset += num2;
- _bufferPos += num2;
- count -= num2;
- num += num2;
- if (_bufferPos == _bufferSize)
- {
- ReadSector();
- }
- }
- return num;
- }
-
- public override void Write(byte[] buffer, int offset, int count)
- {
- while (count > 0)
- {
- if (!_bufferLoaded)
- {
- ReadSector();
- }
- int num = Math.Min(count, _bufferSize - _bufferPos);
- Buffer.BlockCopy(buffer, offset, _buffer, _bufferPos, num);
- offset += num;
- _bufferPos += num;
- count -= num;
- _bufferDirty = true;
- if (_bufferPos == _bufferSize)
- {
- WriteSector();
- }
- }
- }
-
- private void ReadSector()
- {
- if (_bufferLoaded && _bufferDirty)
+ int num = Math.Min(count, _bufferSize - _bufferPos);
+ Buffer.BlockCopy(buffer, offset, _buffer, _bufferPos, num);
+ offset += num;
+ _bufferPos += num;
+ count -= num;
+ _bufferDirty = true;
+ if (_bufferPos == _bufferSize)
{
WriteSector();
}
- if (_s.Position != _s.Length)
- {
- int num = _s.Read(_buffer, 0, _buffer.Length);
- if (num != _bufferSize)
- {
- Array.Clear(_buffer, num, _buffer.Length - num);
- }
- _bufferLoaded = true;
- _bufferPos = 0;
- _bufferDirty = false;
- }
- }
-
- private void WriteSector()
- {
- if (_bufferLoaded)
- {
- _s.Seek(-_bufferSize, SeekOrigin.Current);
- }
- _s.Write(_buffer, 0, _bufferSize);
- _bufferDirty = false;
- _bufferLoaded = false;
- _bufferPos = 0;
- Array.Clear(_buffer, 0, _bufferSize);
}
}
+
+ private void ReadSector()
+ {
+ if (_bufferLoaded && _bufferDirty)
+ {
+ WriteSector();
+ }
+ if (_s.Position != _s.Length)
+ {
+ int num = _s.Read(_buffer, 0, _buffer.Length);
+ if (num != _bufferSize)
+ {
+ Array.Clear(_buffer, num, _buffer.Length - num);
+ }
+ _bufferLoaded = true;
+ _bufferPos = 0;
+ _bufferDirty = false;
+ }
+ }
+
+ private void WriteSector()
+ {
+ if (_bufferLoaded)
+ {
+ _s.Seek(-_bufferSize, SeekOrigin.Current);
+ }
+ _s.Write(_buffer, 0, _bufferSize);
+ _bufferDirty = false;
+ _bufferLoaded = false;
+ _bufferPos = 0;
+ Array.Clear(_buffer, 0, _bufferSize);
+ }
}
diff --git a/XTSSharp/SectorStream.cs b/XTSSharp/SectorStream.cs
index c6a5bb9..70506fc 100644
--- a/XTSSharp/SectorStream.cs
+++ b/XTSSharp/SectorStream.cs
@@ -1,119 +1,115 @@
using System;
using System.IO;
-namespace XTSSharp
+namespace XTSSharp;
+
+public class SectorStream : Stream
{
- public class SectorStream : Stream
+ private readonly Stream _baseStream;
+ private readonly long _offset;
+ private ulong _currentSector;
+
+ public int SectorSize
{
- private readonly Stream _baseStream;
- private readonly long _offset;
- private ulong _currentSector;
+ get;
+ private set;
+ }
- public int SectorSize {
- get;
- private set;
- }
+ public override bool CanRead => _baseStream.CanRead;
+ public override bool CanSeek => _baseStream.CanSeek;
+ public override bool CanWrite => _baseStream.CanWrite;
+ public override long Length => _baseStream.Length - _offset;
- public override bool CanRead => _baseStream.CanRead;
- public override bool CanSeek => _baseStream.CanSeek;
- public override bool CanWrite => _baseStream.CanWrite;
- public override long Length => _baseStream.Length - _offset;
-
- public override long Position {
- get {
- return _baseStream.Position - _offset;
- }
- set {
- ValidateSizeMultiple(value);
- _baseStream.Position = value + _offset;
- _currentSector = (ulong)(value / SectorSize);
- }
- }
-
- protected ulong CurrentSector => _currentSector;
-
- public SectorStream(Stream baseStream, int sectorSize)
- : this(baseStream, sectorSize, 0L)
+ public override long Position
+ {
+ get
{
+ return _baseStream.Position - _offset;
}
-
- public SectorStream(Stream baseStream, int sectorSize, long offset)
- {
- SectorSize = sectorSize;
- _baseStream = baseStream;
- _offset = offset;
- }
-
- private void ValidateSizeMultiple(long value)
- {
- if (value % SectorSize == 0L)
- {
- return;
- }
- throw new ArgumentException($"Value needs to be a multiple of {SectorSize}");
- }
-
- protected void ValidateSize(long value)
- {
- if (value == SectorSize)
- {
- return;
- }
- throw new ArgumentException($"Value needs to be {SectorSize}");
- }
-
- protected void ValidateSize(int value)
- {
- if (value == SectorSize)
- {
- return;
- }
- throw new ArgumentException($"Value needs to be {SectorSize}");
- }
-
- public override void Flush()
- {
- _baseStream.Flush();
- }
-
- public override long Seek(long offset, SeekOrigin origin)
- {
- long num;
- switch (origin)
- {
- case SeekOrigin.Begin:
- num = offset;
- break;
- case SeekOrigin.End:
- num = Length - offset;
- break;
- default:
- num = Position + offset;
- break;
- }
- Position = num;
- return num;
- }
-
- public override void SetLength(long value)
+ set
{
ValidateSizeMultiple(value);
- _baseStream.SetLength(value);
- }
-
- public override int Read(byte[] buffer, int offset, int count)
- {
- ValidateSize(count);
- int result = _baseStream.Read(buffer, offset, count);
- _currentSector++;
- return result;
- }
-
- public override void Write(byte[] buffer, int offset, int count)
- {
- ValidateSize(count);
- _baseStream.Write(buffer, offset, count);
- _currentSector++;
+ _baseStream.Position = value + _offset;
+ _currentSector = (ulong)(value / SectorSize);
}
}
+
+ protected ulong CurrentSector => _currentSector;
+
+ public SectorStream(Stream baseStream, int sectorSize)
+ : this(baseStream, sectorSize, 0L)
+ {
+ }
+
+ public SectorStream(Stream baseStream, int sectorSize, long offset)
+ {
+ SectorSize = sectorSize;
+ _baseStream = baseStream;
+ _offset = offset;
+ }
+
+ private void ValidateSizeMultiple(long value)
+ {
+ if (value % SectorSize == 0L)
+ {
+ return;
+ }
+ throw new ArgumentException($"Value needs to be a multiple of {SectorSize}");
+ }
+
+ protected void ValidateSize(long value)
+ {
+ if (value == SectorSize)
+ {
+ return;
+ }
+ throw new ArgumentException($"Value needs to be {SectorSize}");
+ }
+
+ protected void ValidateSize(int value)
+ {
+ if (value == SectorSize)
+ {
+ return;
+ }
+ throw new ArgumentException($"Value needs to be {SectorSize}");
+ }
+
+ public override void Flush()
+ {
+ _baseStream.Flush();
+ }
+
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ long num = origin switch
+ {
+ SeekOrigin.Begin => offset,
+ SeekOrigin.End => Length - offset,
+ _ => Position + offset,
+ };
+ Position = num;
+ return num;
+ }
+
+ public override void SetLength(long value)
+ {
+ ValidateSizeMultiple(value);
+ _baseStream.SetLength(value);
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ ValidateSize(count);
+ int result = _baseStream.Read(buffer, offset, count);
+ _currentSector++;
+ return result;
+ }
+
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ ValidateSize(count);
+ _baseStream.Write(buffer, offset, count);
+ _currentSector++;
+ }
}
diff --git a/XTSSharp/Xts.cs b/XTSSharp/Xts.cs
index 7a1fa13..04391b8 100644
--- a/XTSSharp/Xts.cs
+++ b/XTSSharp/Xts.cs
@@ -1,66 +1,65 @@
using System;
using System.Security.Cryptography;
-namespace XTSSharp
+namespace XTSSharp;
+
+public class Xts
{
- public class Xts
+ private readonly SymmetricAlgorithm _key1;
+ private readonly SymmetricAlgorithm _key2;
+
+ protected Xts(Func create, byte[] key1, byte[] key2)
{
- private readonly SymmetricAlgorithm _key1;
- private readonly SymmetricAlgorithm _key2;
-
- protected Xts(Func create, byte[] key1, byte[] key2)
+ if (create == null)
{
- if (create == null)
- {
- throw new ArgumentNullException("create");
- }
- if (key1 == null)
- {
- throw new ArgumentNullException("key1");
- }
- if (key2 == null)
- {
- throw new ArgumentNullException("key2");
- }
- _key1 = create();
- _key2 = create();
- if (key1.Length != key2.Length)
- {
- throw new ArgumentException("Key lengths don't match");
- }
- _key1.KeySize = key1.Length * 8;
- _key2.KeySize = key2.Length * 8;
- _key1.Key = key1;
- _key2.Key = key2;
- _key1.Mode = CipherMode.ECB;
- _key2.Mode = CipherMode.ECB;
- _key1.Padding = PaddingMode.None;
- _key2.Padding = PaddingMode.None;
- _key1.BlockSize = 128;
- _key2.BlockSize = 128;
+ throw new ArgumentNullException(nameof(create));
}
-
- public XtsCryptoTransform CreateEncryptor()
+ if (key1 == null)
{
- return new XtsCryptoTransform(_key1.CreateEncryptor(), _key2.CreateEncryptor(), false);
+ throw new ArgumentNullException(nameof(key1));
}
-
- public XtsCryptoTransform CreateDecryptor()
+ if (key2 == null)
{
- return new XtsCryptoTransform(_key1.CreateDecryptor(), _key2.CreateEncryptor(), true);
+ throw new ArgumentNullException(nameof(key2));
}
-
- protected static byte[] VerifyKey(int expectedSize, byte[] key)
+ _key1 = create();
+ _key2 = create();
+ if (key1.Length != key2.Length)
{
- if (key == null)
- {
- throw new ArgumentNullException("key");
- }
- if (key.Length * 8 != expectedSize)
- {
- throw new ArgumentException($"Expected key length of {expectedSize} bits, got {key.Length * 8}");
- }
- return key;
+ throw new ArgumentException("Key lengths don't match");
}
+ _key1.KeySize = key1.Length * 8;
+ _key2.KeySize = key2.Length * 8;
+ _key1.Key = key1;
+ _key2.Key = key2;
+ _key1.Mode = CipherMode.ECB;
+ _key2.Mode = CipherMode.ECB;
+ _key1.Padding = PaddingMode.None;
+ _key2.Padding = PaddingMode.None;
+ _key1.BlockSize = 128;
+ _key2.BlockSize = 128;
+ }
+
+ public XtsCryptoTransform CreateEncryptor()
+ {
+ return new XtsCryptoTransform(_key1.CreateEncryptor(), _key2.CreateEncryptor(), false);
+ }
+
+ public XtsCryptoTransform CreateDecryptor()
+ {
+ return new XtsCryptoTransform(_key1.CreateDecryptor(), _key2.CreateEncryptor(), true);
+ }
+
+ protected static byte[] VerifyKey(int expectedSize, byte[] key)
+ {
+ if (key == null)
+ {
+ throw new ArgumentNullException(nameof(key));
+ }
+ if (key.Length * 8 != expectedSize)
+ {
+ throw new ArgumentException($"Expected key length of {expectedSize} bits, got {key.Length * 8}");
+ }
+ return key;
}
}
diff --git a/XTSSharp/XtsAes128.cs b/XTSSharp/XtsAes128.cs
index 5b1df9d..a8b242b 100644
--- a/XTSSharp/XtsAes128.cs
+++ b/XTSSharp/XtsAes128.cs
@@ -1,33 +1,32 @@
using System;
using System.Security.Cryptography;
-namespace XTSSharp
+namespace XTSSharp;
+
+public class XtsAes128 : Xts
{
- public class XtsAes128 : Xts
+ private const int KEY_LENGTH = 128;
+ private const int KEY_BYTE_LENGTH = 16;
+
+ protected XtsAes128(Func create, byte[] key1, byte[] key2)
+ : base(create, VerifyKey(128, key1), VerifyKey(128, key2))
{
- private const int KEY_LENGTH = 128;
- private const int KEY_BYTE_LENGTH = 16;
+ }
- protected XtsAes128(Func create, byte[] key1, byte[] key2)
- : base(create, Xts.VerifyKey(128, key1), Xts.VerifyKey(128, key2))
- {
- }
+ public static Xts Create(byte[] key1, byte[] key2)
+ {
+ VerifyKey(128, key1);
+ VerifyKey(128, key2);
+ return new XtsAes128(Aes.Create, key1, key2);
+ }
- public static Xts Create(byte[] key1, byte[] key2)
- {
- Xts.VerifyKey(128, key1);
- Xts.VerifyKey(128, key2);
- return new XtsAes128(Aes.Create, key1, key2);
- }
-
- public static Xts Create(byte[] key)
- {
- Xts.VerifyKey(256, key);
- byte[] array = new byte[16];
- byte[] array2 = new byte[16];
- Buffer.BlockCopy(key, 0, array, 0, 16);
- Buffer.BlockCopy(key, 16, array2, 0, 16);
- return new XtsAes128(Aes.Create, array, array2);
- }
+ public static Xts Create(byte[] key)
+ {
+ VerifyKey(256, key);
+ byte[] array = new byte[16];
+ byte[] array2 = new byte[16];
+ Buffer.BlockCopy(key, 0, array, 0, 16);
+ Buffer.BlockCopy(key, 16, array2, 0, 16);
+ return new XtsAes128(Aes.Create, array, array2);
}
}
diff --git a/XTSSharp/XtsAes256.cs b/XTSSharp/XtsAes256.cs
index fd789c0..98f3eae 100644
--- a/XTSSharp/XtsAes256.cs
+++ b/XTSSharp/XtsAes256.cs
@@ -1,33 +1,32 @@
using System;
using System.Security.Cryptography;
-namespace XTSSharp
+namespace XTSSharp;
+
+public class XtsAes256 : Xts
{
- public class XtsAes256 : Xts
+ private const int KEY_LENGTH = 256;
+ private const int KEY_BYTE_LENGTH = 32;
+
+ protected XtsAes256(Func create, byte[] key1, byte[] key2)
+ : base(create, VerifyKey(256, key1), VerifyKey(256, key2))
{
- private const int KEY_LENGTH = 256;
- private const int KEY_BYTE_LENGTH = 32;
+ }
- protected XtsAes256(Func create, byte[] key1, byte[] key2)
- : base(create, Xts.VerifyKey(256, key1), Xts.VerifyKey(256, key2))
- {
- }
+ public static Xts Create(byte[] key1, byte[] key2)
+ {
+ VerifyKey(256, key1);
+ VerifyKey(256, key2);
+ return new XtsAes256(Aes.Create, key1, key2);
+ }
- public static Xts Create(byte[] key1, byte[] key2)
- {
- Xts.VerifyKey(256, key1);
- Xts.VerifyKey(256, key2);
- return new XtsAes256(Aes.Create, key1, key2);
- }
-
- public static Xts Create(byte[] key)
- {
- Xts.VerifyKey(512, key);
- byte[] array = new byte[32];
- byte[] array2 = new byte[32];
- Buffer.BlockCopy(key, 0, array, 0, 32);
- Buffer.BlockCopy(key, 32, array2, 0, 32);
- return new XtsAes256(Aes.Create, array, array2);
- }
+ public static Xts Create(byte[] key)
+ {
+ VerifyKey(512, key);
+ byte[] array = new byte[32];
+ byte[] array2 = new byte[32];
+ Buffer.BlockCopy(key, 0, array, 0, 32);
+ Buffer.BlockCopy(key, 32, array2, 0, 32);
+ return new XtsAes256(Aes.Create, array, array2);
}
}
diff --git a/XTSSharp/XtsCryptoTransform.cs b/XTSSharp/XtsCryptoTransform.cs
index 64a2daf..e9b76b5 100644
--- a/XTSSharp/XtsCryptoTransform.cs
+++ b/XTSSharp/XtsCryptoTransform.cs
@@ -1,142 +1,141 @@
using System;
using System.Security.Cryptography;
-namespace XTSSharp
+namespace XTSSharp;
+
+public class XtsCryptoTransform : IDisposable
{
- public class XtsCryptoTransform : IDisposable
+ private readonly byte[] _cc = new byte[16];
+ private readonly bool _decrypting;
+ private readonly ICryptoTransform _key1;
+ private readonly ICryptoTransform _key2;
+ private readonly byte[] _pp = new byte[16];
+ private readonly byte[] _t = new byte[16];
+ private readonly byte[] _tweak = new byte[16];
+
+ public XtsCryptoTransform(ICryptoTransform key1, ICryptoTransform key2, bool decrypting)
{
- private readonly byte[] _cc = new byte[16];
- private readonly bool _decrypting;
- private readonly ICryptoTransform _key1;
- private readonly ICryptoTransform _key2;
- private readonly byte[] _pp = new byte[16];
- private readonly byte[] _t = new byte[16];
- private readonly byte[] _tweak = new byte[16];
-
- public XtsCryptoTransform(ICryptoTransform key1, ICryptoTransform key2, bool decrypting)
+ if (key1 == null)
{
- if (key1 == null)
- {
- throw new ArgumentNullException("key1");
- }
- if (key2 == null)
- {
- throw new ArgumentNullException("key2");
- }
- _key1 = key1;
- _key2 = key2;
- _decrypting = decrypting;
+ throw new ArgumentNullException(nameof(key1));
}
-
- public void Dispose()
+ if (key2 == null)
{
- _key1.Dispose();
- _key2.Dispose();
+ throw new ArgumentNullException(nameof(key2));
}
+ _key1 = key1;
+ _key2 = key2;
+ _decrypting = decrypting;
+ }
- public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset, ulong sector)
+ public void Dispose()
+ {
+ _key1.Dispose();
+ _key2.Dispose();
+ }
+
+ public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset, ulong sector)
+ {
+ FillArrayFromSectorLittleEndian(_tweak, sector);
+ int num = inputCount >> 4;
+ int num2 = inputCount & 0xF;
+ _key2.TransformBlock(_tweak, 0, _tweak.Length, _t, 0);
+ int num3 = (num2 != 0) ? (num - 1) : num;
+ for (int i = 0; i < num3; i++)
{
- FillArrayFromSectorLittleEndian(_tweak, sector);
- int num = inputCount >> 4;
- int num2 = inputCount & 0xF;
- _key2.TransformBlock(_tweak, 0, _tweak.Length, _t, 0);
- int num3 = (num2 != 0) ? (num - 1) : num;
- for (int i = 0; i < num3; i++)
+ TweakCrypt(inputBuffer, inputOffset, outputBuffer, outputOffset, _t);
+ inputOffset += 16;
+ outputOffset += 16;
+ }
+ if (num2 > 0)
+ {
+ if (_decrypting)
{
- TweakCrypt(inputBuffer, inputOffset, outputBuffer, outputOffset, _t);
- inputOffset += 16;
- outputOffset += 16;
- }
- if (num2 > 0)
- {
- if (_decrypting)
+ Buffer.BlockCopy(_t, 0, _cc, 0, 16);
+ MultiplyByX(_cc);
+ TweakCrypt(inputBuffer, inputOffset, _pp, 0, _cc);
+ int j;
+ for (j = 0; j < num2; j++)
{
- Buffer.BlockCopy(_t, 0, _cc, 0, 16);
- MultiplyByX(_cc);
- TweakCrypt(inputBuffer, inputOffset, _pp, 0, _cc);
- int j;
- for (j = 0; j < num2; j++)
- {
- _cc[j] = inputBuffer[16 + j + inputOffset];
- outputBuffer[16 + j + outputOffset] = _pp[j];
- }
- for (; j < 16; j++)
- {
- _cc[j] = _pp[j];
- }
- TweakCrypt(_cc, 0, outputBuffer, outputOffset, _t);
+ _cc[j] = inputBuffer[16 + j + inputOffset];
+ outputBuffer[16 + j + outputOffset] = _pp[j];
}
- else
+ for (; j < 16; j++)
{
- TweakCrypt(inputBuffer, inputOffset, _cc, 0, _t);
- int k;
- for (k = 0; k < num2; k++)
- {
- _pp[k] = inputBuffer[16 + k + inputOffset];
- outputBuffer[16 + k + outputOffset] = _cc[k];
- }
- for (; k < 16; k++)
- {
- _pp[k] = _cc[k];
- }
- TweakCrypt(_pp, 0, outputBuffer, outputOffset, _t);
+ _cc[j] = _pp[j];
}
+ TweakCrypt(_cc, 0, outputBuffer, outputOffset, _t);
}
- return inputCount;
- }
-
- private static void FillArrayFromSectorBigEndian(byte[] value, ulong sector)
- {
- value[7] = (byte)((sector >> 56) & 0xFF);
- value[6] = (byte)((sector >> 48) & 0xFF);
- value[5] = (byte)((sector >> 40) & 0xFF);
- value[4] = (byte)((sector >> 32) & 0xFF);
- value[3] = (byte)((sector >> 24) & 0xFF);
- value[2] = (byte)((sector >> 16) & 0xFF);
- value[1] = (byte)((sector >> 8) & 0xFF);
- value[0] = (byte)(sector & 0xFF);
- }
-
- private static void FillArrayFromSectorLittleEndian(byte[] value, ulong sector)
- {
- value[8] = (byte)((sector >> 56) & 0xFF);
- value[9] = (byte)((sector >> 48) & 0xFF);
- value[10] = (byte)((sector >> 40) & 0xFF);
- value[11] = (byte)((sector >> 32) & 0xFF);
- value[12] = (byte)((sector >> 24) & 0xFF);
- value[13] = (byte)((sector >> 16) & 0xFF);
- value[14] = (byte)((sector >> 8) & 0xFF);
- value[15] = (byte)(sector & 0xFF);
- }
-
- private void TweakCrypt(byte[] inputBuffer, int inputOffset, byte[] outputBuffer, int outputOffset, byte[] t)
- {
- for (int i = 0; i < 16; i++)
+ else
{
- outputBuffer[i + outputOffset] = (byte)(inputBuffer[i + inputOffset] ^ t[i]);
+ TweakCrypt(inputBuffer, inputOffset, _cc, 0, _t);
+ int k;
+ for (k = 0; k < num2; k++)
+ {
+ _pp[k] = inputBuffer[16 + k + inputOffset];
+ outputBuffer[16 + k + outputOffset] = _cc[k];
+ }
+ for (; k < 16; k++)
+ {
+ _pp[k] = _cc[k];
+ }
+ TweakCrypt(_pp, 0, outputBuffer, outputOffset, _t);
}
- _key1.TransformBlock(outputBuffer, outputOffset, 16, outputBuffer, outputOffset);
- for (int j = 0; j < 16; j++)
- {
- outputBuffer[j + outputOffset] = (byte)(outputBuffer[j + outputOffset] ^ t[j]);
- }
- MultiplyByX(t);
}
+ return inputCount;
+ }
- private static void MultiplyByX(byte[] i)
+ private static void FillArrayFromSectorBigEndian(byte[] value, ulong sector)
+ {
+ value[7] = (byte)((sector >> 56) & 0xFF);
+ value[6] = (byte)((sector >> 48) & 0xFF);
+ value[5] = (byte)((sector >> 40) & 0xFF);
+ value[4] = (byte)((sector >> 32) & 0xFF);
+ value[3] = (byte)((sector >> 24) & 0xFF);
+ value[2] = (byte)((sector >> 16) & 0xFF);
+ value[1] = (byte)((sector >> 8) & 0xFF);
+ value[0] = (byte)(sector & 0xFF);
+ }
+
+ private static void FillArrayFromSectorLittleEndian(byte[] value, ulong sector)
+ {
+ value[8] = (byte)((sector >> 56) & 0xFF);
+ value[9] = (byte)((sector >> 48) & 0xFF);
+ value[10] = (byte)((sector >> 40) & 0xFF);
+ value[11] = (byte)((sector >> 32) & 0xFF);
+ value[12] = (byte)((sector >> 24) & 0xFF);
+ value[13] = (byte)((sector >> 16) & 0xFF);
+ value[14] = (byte)((sector >> 8) & 0xFF);
+ value[15] = (byte)(sector & 0xFF);
+ }
+
+ private void TweakCrypt(byte[] inputBuffer, int inputOffset, byte[] outputBuffer, int outputOffset, byte[] t)
+ {
+ for (int i = 0; i < 16; i++)
{
- byte b = 0;
- byte b2 = 0;
- for (int j = 0; j < 16; j++)
- {
- b2 = (byte)(i[j] >> 7);
- i[j] = (byte)(((i[j] << 1) | b) & 0xFF);
- b = b2;
- }
- if (b2 > 0)
- {
- i[0] ^= 135;
- }
+ outputBuffer[i + outputOffset] = (byte)(inputBuffer[i + inputOffset] ^ t[i]);
+ }
+ _key1.TransformBlock(outputBuffer, outputOffset, 16, outputBuffer, outputOffset);
+ for (int j = 0; j < 16; j++)
+ {
+ outputBuffer[j + outputOffset] = (byte)(outputBuffer[j + outputOffset] ^ t[j]);
+ }
+ MultiplyByX(t);
+ }
+
+ private static void MultiplyByX(byte[] i)
+ {
+ byte b = 0;
+ byte b2 = 0;
+ for (int j = 0; j < 16; j++)
+ {
+ b2 = (byte)(i[j] >> 7);
+ i[j] = (byte)(((i[j] << 1) | b) & 0xFF);
+ b = b2;
+ }
+ if (b2 > 0)
+ {
+ i[0] ^= 135;
}
}
}
diff --git a/XTSSharp/XtsSectorStream.cs b/XTSSharp/XtsSectorStream.cs
index 3ec039b..2e85eba 100644
--- a/XTSSharp/XtsSectorStream.cs
+++ b/XTSSharp/XtsSectorStream.cs
@@ -1,74 +1,73 @@
using System.IO;
-namespace XTSSharp
+namespace XTSSharp;
+
+public class XtsSectorStream : SectorStream
{
- public class XtsSectorStream : SectorStream
+ public const int DEFAULT_SECTOR_SIZE = 512;
+ private readonly byte[] _tempBuffer;
+ private readonly Xts _xts;
+ private XtsCryptoTransform _decryptor;
+ private XtsCryptoTransform _encryptor;
+
+ public XtsSectorStream(Stream baseStream, Xts xts)
+ : this(baseStream, xts, 512)
{
- public const int DEFAULT_SECTOR_SIZE = 512;
- private readonly byte[] _tempBuffer;
- private readonly Xts _xts;
- private XtsCryptoTransform _decryptor;
- private XtsCryptoTransform _encryptor;
+ }
- public XtsSectorStream(Stream baseStream, Xts xts)
- : this(baseStream, xts, 512)
+ public XtsSectorStream(Stream baseStream, Xts xts, int sectorSize)
+ : this(baseStream, xts, sectorSize, 0L)
+ {
+ }
+
+ public XtsSectorStream(Stream baseStream, Xts xts, int sectorSize, long offset)
+ : base(baseStream, sectorSize, offset)
+ {
+ _xts = xts;
+ _tempBuffer = new byte[sectorSize];
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+ if (_encryptor != null)
{
+ _encryptor.Dispose();
}
-
- public XtsSectorStream(Stream baseStream, Xts xts, int sectorSize)
- : this(baseStream, xts, sectorSize, 0L)
+ if (_decryptor != null)
{
- }
-
- public XtsSectorStream(Stream baseStream, Xts xts, int sectorSize, long offset)
- : base(baseStream, sectorSize, offset)
- {
- _xts = xts;
- _tempBuffer = new byte[sectorSize];
- }
-
- protected override void Dispose(bool disposing)
- {
- base.Dispose(disposing);
- if (_encryptor != null)
- {
- _encryptor.Dispose();
- }
- if (_decryptor != null)
- {
- _decryptor.Dispose();
- }
- }
-
- public override void Write(byte[] buffer, int offset, int count)
- {
- ValidateSize(count);
- if (count != 0)
- {
- ulong currentSector = base.CurrentSector;
- if (_encryptor == null)
- {
- _encryptor = _xts.CreateEncryptor();
- }
- int count2 = _encryptor.TransformBlock(buffer, offset, count, _tempBuffer, 0, currentSector);
- base.Write(_tempBuffer, 0, count2);
- }
- }
-
- public override int Read(byte[] buffer, int offset, int count)
- {
- ValidateSize(count);
- ulong currentSector = base.CurrentSector;
- int num = base.Read(_tempBuffer, 0, count);
- if (num == 0)
- {
- return 0;
- }
- if (_decryptor == null)
- {
- _decryptor = _xts.CreateDecryptor();
- }
- return _decryptor.TransformBlock(_tempBuffer, 0, num, buffer, offset, currentSector);
+ _decryptor.Dispose();
}
}
+
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ ValidateSize(count);
+ if (count != 0)
+ {
+ ulong currentSector = base.CurrentSector;
+ if (_encryptor == null)
+ {
+ _encryptor = _xts.CreateEncryptor();
+ }
+ int count2 = _encryptor.TransformBlock(buffer, offset, count, _tempBuffer, 0, currentSector);
+ base.Write(_tempBuffer, 0, count2);
+ }
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ ValidateSize(count);
+ ulong currentSector = base.CurrentSector;
+ int num = base.Read(_tempBuffer, 0, count);
+ if (num == 0)
+ {
+ return 0;
+ }
+ if (_decryptor == null)
+ {
+ _decryptor = _xts.CreateDecryptor();
+ }
+ return _decryptor.TransformBlock(_tempBuffer, 0, num, buffer, offset, currentSector);
+ }
}
diff --git a/XTSSharp/XtsStream.cs b/XTSSharp/XtsStream.cs
index f17bd1a..58d248c 100644
--- a/XTSSharp/XtsStream.cs
+++ b/XTSSharp/XtsStream.cs
@@ -1,22 +1,21 @@
using System.IO;
-namespace XTSSharp
+namespace XTSSharp;
+
+public class XtsStream : RandomAccessSectorStream
{
- public class XtsStream : RandomAccessSectorStream
+ public XtsStream(Stream baseStream, Xts xts)
+ : this(baseStream, xts, 512)
{
- public XtsStream(Stream baseStream, Xts xts)
- : this(baseStream, xts, 512)
- {
- }
+ }
- public XtsStream(Stream baseStream, Xts xts, int sectorSize)
- : base(new XtsSectorStream(baseStream, xts, sectorSize), true)
- {
- }
+ public XtsStream(Stream baseStream, Xts xts, int sectorSize)
+ : base(new XtsSectorStream(baseStream, xts, sectorSize), true)
+ {
+ }
- public XtsStream(Stream baseStream, Xts xts, int sectorSize, long offset)
- : base(new XtsSectorStream(baseStream, xts, sectorSize, offset), true)
- {
- }
+ public XtsStream(Stream baseStream, Xts xts, int sectorSize, long offset)
+ : base(new XtsSectorStream(baseStream, xts, sectorSize, offset), true)
+ {
}
}