diff --git a/.gitignore b/.gitignore index 976661b..6a54c30 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## -## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore # User-specific files *.rsuser @@ -184,7 +184,7 @@ publish/ *.azurePubxml # Note: Comment the next line if you want to checkin your web deploy settings, # but database connection strings (with potential passwords) will be unencrypted -*.pubxml +#*.pubxml *.publishproj # Microsoft Azure Web App publish settings. Comment the next line if you want to @@ -206,9 +206,6 @@ PublishScripts/ *.nuget.props *.nuget.targets -# Nuget personal access tokens and Credentials -# nuget.config - # Microsoft Azure Build Output csx/ *.build.csdef @@ -297,6 +294,17 @@ node_modules/ # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) *.vbw +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts @@ -353,6 +361,9 @@ ASALocalRun/ # Local History for Visual Studio .localhistory/ +# Visual Studio History (VSHistory) files +.vshistory/ + # BeatPulse healthcheck temp database healthchecksdb @@ -384,5 +395,4 @@ FodyWeavers.xsd *.msp # JetBrains Rider -.idea/ *.sln.iml \ No newline at end of file diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index 6be3437..bf1135c 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -15,5 +15,5 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("206c6c47-87b1-477f-b6e6-f7e7c1a92f8f")] -[assembly: AssemblyFileVersion("1.6.0")] -[assembly: AssemblyVersion("1.6.0")] +[assembly: AssemblyFileVersion("2.0.0")] +[assembly: AssemblyVersion("2.0.0")] diff --git a/Properties/PublishProfiles/Dependent.pubxml b/Properties/PublishProfiles/Dependent.pubxml new file mode 100644 index 0000000..e534582 --- /dev/null +++ b/Properties/PublishProfiles/Dependent.pubxml @@ -0,0 +1,18 @@ + + + + + Release + Any CPU + bin\Release\Dependent + FileSystem + <_TargetId>Folder + net6.0-windows + win-x64 + false + true + false + + \ No newline at end of file diff --git a/Properties/PublishProfiles/Portable.pubxml b/Properties/PublishProfiles/Portable.pubxml new file mode 100644 index 0000000..73c0484 --- /dev/null +++ b/Properties/PublishProfiles/Portable.pubxml @@ -0,0 +1,20 @@ + + + + + Release + Any CPU + bin\Release\Portable + FileSystem + <_TargetId>Folder + net6.0-windows + win-x64 + true + true + false + true + true + + \ No newline at end of file diff --git a/XCI Explorer.csproj b/XCI Explorer.csproj index 71c9199..3a90001 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.Designer.cs b/XCI_Explorer/MainForm.Designer.cs index e2ce910..aefd75a 100644 --- a/XCI_Explorer/MainForm.Designer.cs +++ b/XCI_Explorer/MainForm.Designer.cs @@ -36,17 +36,19 @@ namespace XCI_Explorer this.TB_File = new System.Windows.Forms.TextBox(); this.TABC_Main = new System.Windows.Forms.TabControl(); this.TABP_XCI = new System.Windows.Forms.TabPage(); + this.TB_GameRev = new System.Windows.Forms.RichTextBox(); + this.label12 = new System.Windows.Forms.Label(); this.B_TrimXCI = new System.Windows.Forms.Button(); this.TB_ProdCode = new System.Windows.Forms.TextBox(); this.label8 = new System.Windows.Forms.Label(); this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.label11 = new System.Windows.Forms.Label(); this.TB_Dev = new System.Windows.Forms.TextBox(); this.label10 = new System.Windows.Forms.Label(); this.TB_Name = new System.Windows.Forms.TextBox(); this.label9 = new System.Windows.Forms.Label(); this.PB_GameIcon = new System.Windows.Forms.PictureBox(); this.CB_RegionName = new System.Windows.Forms.ComboBox(); - this.TB_GameRev = new System.Windows.Forms.TextBox(); this.label7 = new System.Windows.Forms.Label(); this.groupBox1 = new System.Windows.Forms.GroupBox(); this.B_ViewCert = new System.Windows.Forms.Button(); @@ -87,9 +89,9 @@ namespace XCI_Explorer // // B_LoadROM // - this.B_LoadROM.Location = new System.Drawing.Point(4, 12); + this.B_LoadROM.Location = new System.Drawing.Point(4, 11); this.B_LoadROM.Name = "B_LoadROM"; - this.B_LoadROM.Size = new System.Drawing.Size(75, 23); + this.B_LoadROM.Size = new System.Drawing.Size(75, 21); this.B_LoadROM.TabIndex = 0; this.B_LoadROM.Text = "Load Game"; this.B_LoadROM.UseVisualStyleBackColor = true; @@ -98,31 +100,31 @@ namespace XCI_Explorer // TB_File // this.TB_File.AllowDrop = true; - this.TB_File.Location = new System.Drawing.Point(85, 13); + this.TB_File.Location = new System.Drawing.Point(85, 12); this.TB_File.Name = "TB_File"; this.TB_File.ReadOnly = true; - this.TB_File.Size = new System.Drawing.Size(258, 20); + this.TB_File.Size = new System.Drawing.Size(268, 21); this.TB_File.TabIndex = 1; - this.TB_File.DragDrop += new System.Windows.Forms.DragEventHandler(this.TB_File_DragDrop); - this.TB_File.DragEnter += new System.Windows.Forms.DragEventHandler(this.TB_File_DragEnter); // // TABC_Main // this.TABC_Main.Controls.Add(this.TABP_XCI); this.TABC_Main.Controls.Add(this.tabPage2); - this.TABC_Main.Location = new System.Drawing.Point(4, 41); + this.TABC_Main.Location = new System.Drawing.Point(4, 38); this.TABC_Main.Name = "TABC_Main"; this.TABC_Main.SelectedIndex = 0; - this.TABC_Main.Size = new System.Drawing.Size(355, 485); + this.TABC_Main.Size = new System.Drawing.Size(364, 511); this.TABC_Main.TabIndex = 2; // // TABP_XCI // + this.TABP_XCI.AllowDrop = true; + this.TABP_XCI.Controls.Add(this.TB_GameRev); + this.TABP_XCI.Controls.Add(this.label12); this.TABP_XCI.Controls.Add(this.B_TrimXCI); this.TABP_XCI.Controls.Add(this.TB_ProdCode); this.TABP_XCI.Controls.Add(this.label8); this.TABP_XCI.Controls.Add(this.groupBox2); - this.TABP_XCI.Controls.Add(this.TB_GameRev); this.TABP_XCI.Controls.Add(this.label7); this.TABP_XCI.Controls.Add(this.groupBox1); this.TABP_XCI.Controls.Add(this.TB_ExactUsedSpace); @@ -142,16 +144,37 @@ namespace XCI_Explorer this.TABP_XCI.Location = new System.Drawing.Point(4, 22); this.TABP_XCI.Name = "TABP_XCI"; this.TABP_XCI.Padding = new System.Windows.Forms.Padding(3); - this.TABP_XCI.Size = new System.Drawing.Size(347, 459); + this.TABP_XCI.Size = new System.Drawing.Size(356, 485); this.TABP_XCI.TabIndex = 0; this.TABP_XCI.Text = "Main"; this.TABP_XCI.UseVisualStyleBackColor = true; + this.TABP_XCI.Click += new System.EventHandler(this.TABP_XCI_Click); + this.TABP_XCI.DragDrop += new System.Windows.Forms.DragEventHandler(this.TB_File_DragDrop); + this.TABP_XCI.DragEnter += new System.Windows.Forms.DragEventHandler(this.TB_File_DragEnter); + // + // TB_GameRev + // + this.TB_GameRev.Location = new System.Drawing.Point(15, 63); + this.TB_GameRev.Name = "TB_GameRev"; + this.TB_GameRev.ReadOnly = true; + this.TB_GameRev.Size = new System.Drawing.Size(237, 99); + this.TB_GameRev.TabIndex = 23; + this.TB_GameRev.Text = ""; + // + // label12 + // + this.label12.AutoSize = true; + this.label12.Location = new System.Drawing.Point(75, 48); + this.label12.Name = "label12"; + this.label12.Size = new System.Drawing.Size(125, 12); + this.label12.TabIndex = 22; + this.label12.Text = "0 BASE, 0 UPD, 0 DLC"; // // B_TrimXCI // - this.B_TrimXCI.Location = new System.Drawing.Point(90, 207); + this.B_TrimXCI.Location = new System.Drawing.Point(307, 178); this.B_TrimXCI.Name = "B_TrimXCI"; - this.B_TrimXCI.Size = new System.Drawing.Size(70, 23); + this.B_TrimXCI.Size = new System.Drawing.Size(38, 46); this.B_TrimXCI.TabIndex = 21; this.B_TrimXCI.Text = "Trim XCI"; this.B_TrimXCI.UseVisualStyleBackColor = true; @@ -159,76 +182,87 @@ namespace XCI_Explorer // // TB_ProdCode // - this.TB_ProdCode.Location = new System.Drawing.Point(238, 115); + this.TB_ProdCode.Location = new System.Drawing.Point(258, 141); this.TB_ProdCode.Name = "TB_ProdCode"; this.TB_ProdCode.ReadOnly = true; - this.TB_ProdCode.Size = new System.Drawing.Size(69, 20); + this.TB_ProdCode.Size = new System.Drawing.Size(87, 21); this.TB_ProdCode.TabIndex = 20; // // label8 // this.label8.AutoSize = true; - this.label8.Location = new System.Drawing.Point(235, 99); + this.label8.Location = new System.Drawing.Point(258, 126); this.label8.Name = "label8"; - this.label8.Size = new System.Drawing.Size(75, 13); + this.label8.Size = new System.Drawing.Size(83, 12); this.label8.TabIndex = 19; this.label8.Text = "Product Code:"; // // groupBox2 // + this.groupBox2.Controls.Add(this.label11); this.groupBox2.Controls.Add(this.TB_Dev); this.groupBox2.Controls.Add(this.label10); this.groupBox2.Controls.Add(this.TB_Name); this.groupBox2.Controls.Add(this.label9); this.groupBox2.Controls.Add(this.PB_GameIcon); this.groupBox2.Controls.Add(this.CB_RegionName); - this.groupBox2.Location = new System.Drawing.Point(22, 296); + this.groupBox2.Location = new System.Drawing.Point(15, 285); this.groupBox2.Name = "groupBox2"; - this.groupBox2.Size = new System.Drawing.Size(301, 154); + this.groupBox2.Size = new System.Drawing.Size(330, 178); this.groupBox2.TabIndex = 18; this.groupBox2.TabStop = false; this.groupBox2.Text = "Game Infos"; // + // label11 + // + this.label11.AutoSize = true; + this.label11.Location = new System.Drawing.Point(6, 69); + this.label11.Name = "label11"; + this.label11.Size = new System.Drawing.Size(59, 12); + this.label11.TabIndex = 25; + this.label11.Text = "Language:"; + this.label11.Click += new System.EventHandler(this.label11_Click); + // // TB_Dev // - this.TB_Dev.Location = new System.Drawing.Point(6, 117); + this.TB_Dev.Location = new System.Drawing.Point(6, 138); this.TB_Dev.Name = "TB_Dev"; this.TB_Dev.ReadOnly = true; - this.TB_Dev.Size = new System.Drawing.Size(145, 20); + this.TB_Dev.Size = new System.Drawing.Size(154, 21); this.TB_Dev.TabIndex = 24; // // label10 // this.label10.AutoSize = true; - this.label10.Location = new System.Drawing.Point(3, 101); + this.label10.Location = new System.Drawing.Point(6, 123); this.label10.Name = "label10"; - this.label10.Size = new System.Drawing.Size(59, 13); + this.label10.Size = new System.Drawing.Size(65, 12); this.label10.TabIndex = 23; this.label10.Text = "Developer:"; // // TB_Name // - this.TB_Name.Location = new System.Drawing.Point(6, 66); + this.TB_Name.Location = new System.Drawing.Point(6, 35); this.TB_Name.Name = "TB_Name"; this.TB_Name.ReadOnly = true; - this.TB_Name.Size = new System.Drawing.Size(145, 20); + this.TB_Name.Size = new System.Drawing.Size(154, 21); this.TB_Name.TabIndex = 22; // // label9 // this.label9.AutoSize = true; - this.label9.Location = new System.Drawing.Point(3, 50); + this.label9.Location = new System.Drawing.Point(6, 20); this.label9.Name = "label9"; - this.label9.Size = new System.Drawing.Size(38, 13); + this.label9.Size = new System.Drawing.Size(35, 12); this.label9.TabIndex = 21; this.label9.Text = "Name:"; // // PB_GameIcon // this.PB_GameIcon.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; - this.PB_GameIcon.Location = new System.Drawing.Point(190, 43); + this.PB_GameIcon.Location = new System.Drawing.Point(172, 20); this.PB_GameIcon.Name = "PB_GameIcon"; - this.PB_GameIcon.Size = new System.Drawing.Size(105, 105); + this.PB_GameIcon.Size = new System.Drawing.Size(152, 147); this.PB_GameIcon.TabIndex = 18; this.PB_GameIcon.TabStop = false; // @@ -236,28 +270,20 @@ namespace XCI_Explorer // this.CB_RegionName.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.CB_RegionName.FormattingEnabled = true; - this.CB_RegionName.Location = new System.Drawing.Point(77, 14); + this.CB_RegionName.Location = new System.Drawing.Point(6, 84); this.CB_RegionName.Name = "CB_RegionName"; - this.CB_RegionName.Size = new System.Drawing.Size(138, 21); + this.CB_RegionName.Size = new System.Drawing.Size(154, 20); this.CB_RegionName.TabIndex = 17; this.CB_RegionName.SelectedIndexChanged += new System.EventHandler(this.CB_RegionName_SelectedIndexChanged); // - // TB_GameRev - // - this.TB_GameRev.Location = new System.Drawing.Point(24, 115); - this.TB_GameRev.Name = "TB_GameRev"; - this.TB_GameRev.ReadOnly = true; - this.TB_GameRev.Size = new System.Drawing.Size(124, 20); - this.TB_GameRev.TabIndex = 16; - // // label7 // this.label7.AutoSize = true; - this.label7.Location = new System.Drawing.Point(21, 99); + this.label7.Location = new System.Drawing.Point(11, 48); this.label7.Name = "label7"; - this.label7.Size = new System.Drawing.Size(82, 13); + this.label7.Size = new System.Drawing.Size(59, 12); this.label7.TabIndex = 15; - this.label7.Text = "Game Revision:"; + this.label7.Text = "Contents:"; // // groupBox1 // @@ -265,18 +291,18 @@ namespace XCI_Explorer this.groupBox1.Controls.Add(this.B_ClearCert); this.groupBox1.Controls.Add(this.B_ImportCert); this.groupBox1.Controls.Add(this.B_ExportCert); - this.groupBox1.Location = new System.Drawing.Point(22, 234); + this.groupBox1.Location = new System.Drawing.Point(15, 230); this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(301, 52); + this.groupBox1.Size = new System.Drawing.Size(330, 49); this.groupBox1.TabIndex = 14; this.groupBox1.TabStop = false; this.groupBox1.Text = "Cert"; // // B_ViewCert // - this.B_ViewCert.Location = new System.Drawing.Point(156, 19); + this.B_ViewCert.Location = new System.Drawing.Point(168, 18); this.B_ViewCert.Name = "B_ViewCert"; - this.B_ViewCert.Size = new System.Drawing.Size(66, 23); + this.B_ViewCert.Size = new System.Drawing.Size(74, 21); this.B_ViewCert.TabIndex = 3; this.B_ViewCert.Text = "View Cert"; this.B_ViewCert.UseVisualStyleBackColor = true; @@ -284,9 +310,9 @@ namespace XCI_Explorer // // B_ClearCert // - this.B_ClearCert.Location = new System.Drawing.Point(229, 19); + this.B_ClearCert.Location = new System.Drawing.Point(250, 18); this.B_ClearCert.Name = "B_ClearCert"; - this.B_ClearCert.Size = new System.Drawing.Size(66, 23); + this.B_ClearCert.Size = new System.Drawing.Size(74, 21); this.B_ClearCert.TabIndex = 2; this.B_ClearCert.Text = "Clear Cert"; this.B_ClearCert.UseVisualStyleBackColor = true; @@ -294,9 +320,9 @@ namespace XCI_Explorer // // B_ImportCert // - this.B_ImportCert.Location = new System.Drawing.Point(83, 19); + this.B_ImportCert.Location = new System.Drawing.Point(86, 18); this.B_ImportCert.Name = "B_ImportCert"; - this.B_ImportCert.Size = new System.Drawing.Size(67, 23); + this.B_ImportCert.Size = new System.Drawing.Size(74, 21); this.B_ImportCert.TabIndex = 1; this.B_ImportCert.Text = "Import Cert"; this.B_ImportCert.UseVisualStyleBackColor = true; @@ -304,9 +330,9 @@ namespace XCI_Explorer // // B_ExportCert // - this.B_ExportCert.Location = new System.Drawing.Point(7, 19); + this.B_ExportCert.Location = new System.Drawing.Point(6, 18); this.B_ExportCert.Name = "B_ExportCert"; - this.B_ExportCert.Size = new System.Drawing.Size(70, 23); + this.B_ExportCert.Size = new System.Drawing.Size(74, 21); this.B_ExportCert.TabIndex = 0; this.B_ExportCert.Text = "Export Cert"; this.B_ExportCert.UseVisualStyleBackColor = true; @@ -314,120 +340,120 @@ namespace XCI_Explorer // // TB_ExactUsedSpace // - this.TB_ExactUsedSpace.Location = new System.Drawing.Point(166, 181); + this.TB_ExactUsedSpace.Location = new System.Drawing.Point(152, 203); this.TB_ExactUsedSpace.Name = "TB_ExactUsedSpace"; this.TB_ExactUsedSpace.ReadOnly = true; - this.TB_ExactUsedSpace.Size = new System.Drawing.Size(157, 20); + this.TB_ExactUsedSpace.Size = new System.Drawing.Size(152, 21); this.TB_ExactUsedSpace.TabIndex = 13; // // TB_ROMExactSize // - this.TB_ROMExactSize.Location = new System.Drawing.Point(166, 154); + this.TB_ROMExactSize.Location = new System.Drawing.Point(152, 178); this.TB_ROMExactSize.Name = "TB_ROMExactSize"; this.TB_ROMExactSize.ReadOnly = true; - this.TB_ROMExactSize.Size = new System.Drawing.Size(157, 20); + this.TB_ROMExactSize.Size = new System.Drawing.Size(152, 21); this.TB_ROMExactSize.TabIndex = 12; // // TB_UsedSpace // - this.TB_UsedSpace.Location = new System.Drawing.Point(91, 181); + this.TB_UsedSpace.Location = new System.Drawing.Point(77, 203); this.TB_UsedSpace.Name = "TB_UsedSpace"; this.TB_UsedSpace.ReadOnly = true; - this.TB_UsedSpace.Size = new System.Drawing.Size(69, 20); + this.TB_UsedSpace.Size = new System.Drawing.Size(69, 21); this.TB_UsedSpace.TabIndex = 11; // // TB_ROMSize // - this.TB_ROMSize.Location = new System.Drawing.Point(91, 154); + this.TB_ROMSize.Location = new System.Drawing.Point(77, 178); this.TB_ROMSize.Name = "TB_ROMSize"; this.TB_ROMSize.ReadOnly = true; - this.TB_ROMSize.Size = new System.Drawing.Size(69, 20); + this.TB_ROMSize.Size = new System.Drawing.Size(69, 21); this.TB_ROMSize.TabIndex = 10; // // label6 // this.label6.AutoSize = true; - this.label6.Location = new System.Drawing.Point(18, 181); + this.label6.Location = new System.Drawing.Point(4, 203); this.label6.Name = "label6"; - this.label6.Size = new System.Drawing.Size(67, 13); + this.label6.Size = new System.Drawing.Size(71, 12); this.label6.TabIndex = 9; this.label6.Text = "Used space:"; // // label5 // this.label5.AutoSize = true; - this.label5.Location = new System.Drawing.Point(27, 157); + this.label5.Location = new System.Drawing.Point(13, 181); this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(58, 13); + this.label5.Size = new System.Drawing.Size(59, 12); this.label5.TabIndex = 8; this.label5.Text = "ROM Size:"; // // TB_MKeyRev // - this.TB_MKeyRev.Location = new System.Drawing.Point(24, 68); + this.TB_MKeyRev.Location = new System.Drawing.Point(191, 21); this.TB_MKeyRev.Name = "TB_MKeyRev"; this.TB_MKeyRev.ReadOnly = true; - this.TB_MKeyRev.Size = new System.Drawing.Size(124, 20); + this.TB_MKeyRev.Size = new System.Drawing.Size(154, 21); this.TB_MKeyRev.TabIndex = 7; // // label4 // this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(21, 52); + this.label4.Location = new System.Drawing.Point(189, 6); this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(104, 13); + this.label4.Size = new System.Drawing.Size(119, 12); this.label4.TabIndex = 6; this.label4.Text = "MasterKey Revision:"; // // TB_SDKVer // - this.TB_SDKVer.Location = new System.Drawing.Point(238, 68); + this.TB_SDKVer.Location = new System.Drawing.Point(258, 102); this.TB_SDKVer.Name = "TB_SDKVer"; this.TB_SDKVer.ReadOnly = true; - this.TB_SDKVer.Size = new System.Drawing.Size(69, 20); + this.TB_SDKVer.Size = new System.Drawing.Size(87, 21); this.TB_SDKVer.TabIndex = 5; // // label3 // this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(235, 52); + this.label3.Location = new System.Drawing.Point(258, 87); this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(70, 13); + this.label3.Size = new System.Drawing.Size(77, 12); this.label3.TabIndex = 4; this.label3.Text = "SDK Version:"; // // TB_Capacity // - this.TB_Capacity.Location = new System.Drawing.Point(238, 23); + this.TB_Capacity.Location = new System.Drawing.Point(258, 63); this.TB_Capacity.Name = "TB_Capacity"; this.TB_Capacity.ReadOnly = true; - this.TB_Capacity.Size = new System.Drawing.Size(69, 20); + this.TB_Capacity.Size = new System.Drawing.Size(87, 21); this.TB_Capacity.TabIndex = 3; // // label2 // this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(235, 7); + this.label2.Location = new System.Drawing.Point(258, 48); this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(51, 13); + this.label2.Size = new System.Drawing.Size(59, 12); this.label2.TabIndex = 2; this.label2.Text = "Capacity:"; // // label1 // this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(21, 7); + this.label1.Location = new System.Drawing.Point(12, 6); this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(44, 13); + this.label1.Size = new System.Drawing.Size(59, 12); this.label1.TabIndex = 1; this.label1.Text = "Title ID:"; // // TB_TID // - this.TB_TID.Location = new System.Drawing.Point(24, 23); + this.TB_TID.Location = new System.Drawing.Point(15, 21); this.TB_TID.Name = "TB_TID"; this.TB_TID.ReadOnly = true; - this.TB_TID.Size = new System.Drawing.Size(124, 20); + this.TB_TID.Size = new System.Drawing.Size(170, 21); this.TB_TID.TabIndex = 0; // // tabPage2 @@ -443,7 +469,7 @@ namespace XCI_Explorer this.tabPage2.Location = new System.Drawing.Point(4, 22); this.tabPage2.Name = "tabPage2"; this.tabPage2.Padding = new System.Windows.Forms.Padding(3); - this.tabPage2.Size = new System.Drawing.Size(347, 459); + this.tabPage2.Size = new System.Drawing.Size(356, 485); this.tabPage2.TabIndex = 1; this.tabPage2.Text = "Partitions"; this.tabPage2.UseVisualStyleBackColor = true; @@ -451,18 +477,18 @@ namespace XCI_Explorer // LB_HashedRegionSize // this.LB_HashedRegionSize.AutoSize = true; - this.LB_HashedRegionSize.Location = new System.Drawing.Point(6, 416); + this.LB_HashedRegionSize.Location = new System.Drawing.Point(6, 439); this.LB_HashedRegionSize.Name = "LB_HashedRegionSize"; - this.LB_HashedRegionSize.Size = new System.Drawing.Size(101, 13); + this.LB_HashedRegionSize.Size = new System.Drawing.Size(107, 12); this.LB_HashedRegionSize.TabIndex = 7; this.LB_HashedRegionSize.Text = "HashedRegionSize:"; // // LB_ActualHash // this.LB_ActualHash.AutoSize = true; - this.LB_ActualHash.Location = new System.Drawing.Point(6, 443); + this.LB_ActualHash.Location = new System.Drawing.Point(6, 464); this.LB_ActualHash.Name = "LB_ActualHash"; - this.LB_ActualHash.Size = new System.Drawing.Size(68, 13); + this.LB_ActualHash.Size = new System.Drawing.Size(77, 12); this.LB_ActualHash.TabIndex = 6; this.LB_ActualHash.Text = "Actual Hash:"; this.LB_ActualHash.DoubleClick += new System.EventHandler(this.LB_ActualHash_DoubleClick); @@ -470,9 +496,9 @@ namespace XCI_Explorer // LB_ExpectedHash // this.LB_ExpectedHash.AutoSize = true; - this.LB_ExpectedHash.Location = new System.Drawing.Point(6, 430); + this.LB_ExpectedHash.Location = new System.Drawing.Point(6, 452); this.LB_ExpectedHash.Name = "LB_ExpectedHash"; - this.LB_ExpectedHash.Size = new System.Drawing.Size(73, 13); + this.LB_ExpectedHash.Size = new System.Drawing.Size(77, 12); this.LB_ExpectedHash.TabIndex = 5; this.LB_ExpectedHash.Text = "Header Hash:"; this.LB_ExpectedHash.DoubleClick += new System.EventHandler(this.LB_ExpectedHash_DoubleClick); @@ -480,9 +506,9 @@ namespace XCI_Explorer // B_Extract // this.B_Extract.Enabled = false; - this.B_Extract.Location = new System.Drawing.Point(296, 367); + this.B_Extract.Location = new System.Drawing.Point(296, 394); this.B_Extract.Name = "B_Extract"; - this.B_Extract.Size = new System.Drawing.Size(48, 23); + this.B_Extract.Size = new System.Drawing.Size(48, 21); this.B_Extract.TabIndex = 4; this.B_Extract.Text = "Extract"; this.B_Extract.UseVisualStyleBackColor = true; @@ -491,27 +517,27 @@ namespace XCI_Explorer // LB_DataSize // this.LB_DataSize.AutoSize = true; - this.LB_DataSize.Location = new System.Drawing.Point(6, 403); + this.LB_DataSize.Location = new System.Drawing.Point(6, 427); this.LB_DataSize.Name = "LB_DataSize"; - this.LB_DataSize.Size = new System.Drawing.Size(30, 13); + this.LB_DataSize.Size = new System.Drawing.Size(35, 12); this.LB_DataSize.TabIndex = 3; this.LB_DataSize.Text = "Size:"; // // LB_DataOffset // this.LB_DataOffset.AutoSize = true; - this.LB_DataOffset.Location = new System.Drawing.Point(6, 390); + this.LB_DataOffset.Location = new System.Drawing.Point(6, 415); this.LB_DataOffset.Name = "LB_DataOffset"; - this.LB_DataOffset.Size = new System.Drawing.Size(38, 13); + this.LB_DataOffset.Size = new System.Drawing.Size(47, 12); this.LB_DataOffset.TabIndex = 2; this.LB_DataOffset.Text = "Offset:"; // // LB_SelectedData // this.LB_SelectedData.AutoSize = true; - this.LB_SelectedData.Location = new System.Drawing.Point(6, 367); + this.LB_SelectedData.Location = new System.Drawing.Point(6, 394); this.LB_SelectedData.Name = "LB_SelectedData"; - this.LB_SelectedData.Size = new System.Drawing.Size(51, 13); + this.LB_SelectedData.Size = new System.Drawing.Size(53, 12); this.LB_SelectedData.TabIndex = 1; this.LB_SelectedData.Text = "FileName"; // @@ -521,7 +547,7 @@ namespace XCI_Explorer this.TV_Partitions.HideSelection = false; this.TV_Partitions.Location = new System.Drawing.Point(3, 3); this.TV_Partitions.Name = "TV_Partitions"; - this.TV_Partitions.Size = new System.Drawing.Size(341, 361); + this.TV_Partitions.Size = new System.Drawing.Size(350, 385); this.TV_Partitions.TabIndex = 0; this.TV_Partitions.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.TV_Partitions_AfterSelect); // @@ -533,9 +559,9 @@ namespace XCI_Explorer // MainForm // this.AllowDrop = true; - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(362, 529); + this.ClientSize = new System.Drawing.Size(370, 553); this.Controls.Add(this.TABC_Main); this.Controls.Add(this.TB_File); this.Controls.Add(this.B_LoadROM); @@ -555,6 +581,7 @@ namespace XCI_Explorer this.tabPage2.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); + } #endregion @@ -591,7 +618,6 @@ namespace XCI_Explorer private TextBox TB_ROMSize; private Label label6; private Label label5; - private TextBox TB_GameRev; private Label label7; private GroupBox groupBox1; private Button B_ClearCert; @@ -617,5 +643,8 @@ namespace XCI_Explorer private Label LB_HashedRegionSize; private BackgroundWorker backgroundWorker1; private Button B_TrimXCI; + private Label label11; + private Label label12; + private RichTextBox TB_GameRev; } } \ No newline at end of file diff --git a/XCI_Explorer/MainForm.cs b/XCI_Explorer/MainForm.cs index aa9b14a..ca76fda 100644 --- a/XCI_Explorer/MainForm.cs +++ b/XCI_Explorer/MainForm.cs @@ -15,162 +15,1429 @@ 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 = ""; - - //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("aHR0cHM6Ly9wYXN0ZWJpbi5jb20vcmF3L0Z2M25GRzJR"))); + using Stream stream = response.Content.ReadAsStream(); + using FileStream fs = new("keys.txt", FileMode.CreateNew); + stream.CopyTo(fs); + } if (!File.Exists("keys.txt")) { - - 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")) - { - MessageBox.Show("keys.txt failed to load.\nPlease include keys.txt in the root folder."); - Environment.Exit(0); - } - } - - if (!File.Exists($"tools{Path.DirectorySeparatorChar}hactool.exe")) - { - Directory.CreateDirectory("tools"); - MessageBox.Show("hactool.exe is missing.\nPlease include hactool.exe in the 'tools' folder."); + new CenterWinDialog(this); + 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 = Mkey + "0" + capchar; - MkeyL = 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 { + return false; + } + } + } + + 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 + { + 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($"File is corrupt or unsupported.\nException: {e.Message}"); + } + + } + + 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; + } + + num2 = 0; + while (num3 >= 1024.0 && num2 < array.Length - 1) + { + num2++; + num3 /= 1024.0; + } + TB_UsedSpace.Text = $"{num3:0.##} {array[num2]}"; + TB_Capacity.Text = Util.GetCapacity(XCI.XCI_Headers[0].CardSize1); + LoadPartitions(); + LoadNCAData(); + LoadGameInfos(); + } + + // 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) + { + 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(); + try + { + FileStream fileStream = File.OpenRead(TB_File.Text); + 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(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(); + + 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 + var test = NACP.NACP_Datas[0].GameVer.Replace("\0", ""); + + if (contentType == "Patch") + { + 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 + { + 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 { - MkeyL = dictionary[MkeyL].Replace(" ", ""); - return true; + 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 + { + 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] + 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 = "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 + { + 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(); + string GameRevision = ""; + + for (int si = 0; si < SecureSize.Length; si++) + { + if (SecureSize[si] > 0x4E20000) + { + continue; + } + + if (!SecureName[si].EndsWith(".cnmt.nca")) + { + continue; + } + + try + { + File.Delete("meta"); + Directory.Delete("data", true); } catch { - return false; + } + + 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) + { + 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; + } + } + fileStream3.Close(); + + } + + for (int si = 0; si < SecureSize.Length; si++) + { + if (SecureSize[si] > 0x4E20000) + { + 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) + { + 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 + { + 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"; + + 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); } } } - - private void ProcessFile() + 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) { - using CenterWinDialog center = new CenterWinDialog(this); - // Code needs refactoring LB_SelectedData.Text = ""; LB_DataOffset.Text = ""; LB_DataSize.Text = ""; @@ -178,1301 +1445,468 @@ namespace XCI_Explorer 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; - MessageBox.Show("File is corrupt or unsupported."); - } - } - catch (Exception e) - { - MessageBox.Show("Error: " + e.ToString() + "\nFile is corrupt or unsupported."); - } - + return; } - private void B_LoadROM_Click(object sender, EventArgs e) + 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) { - using CenterWinDialog center = new CenterWinDialog(this); - OpenFileDialog openFileDialog = new OpenFileDialog(); - openFileDialog.Filter = "Switch Game File (*.xci, *.nsp, *.nsz)|*.xci;*.nsp;*.nsz|All Files (*.*)|*.*"; - if (openFileDialog.ShowDialog() == DialogResult.OK) - { - TB_File.Text = openFileDialog.FileName; - ProcessFile(); - } + 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 = ""; } - private void LoadXCI() + if (!string.IsNullOrEmpty(expectedHash)) { - 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)"; - if (isTrimmed()) - B_TrimXCI.Enabled = false; - num2 = 0; - while (num3 >= 1024.0 && num2 < array.Length - 1) - { - num2++; - num3 /= 1024.0; - } - TB_UsedSpace.Text = $"{num3:0.##} {array[num2]}"; - TB_Capacity.Text = Util.GetCapacity(XCI.XCI_Headers[0].CardSize1); - LoadPartitions(); - LoadNCAData(); - LoadGameInfos(); + LB_ExpectedHash.Text = $"Header Hash: {expectedHash[..32]}"; + } + else + { + LB_ExpectedHash.Text = ""; } - // Giba's better implementation (more native) - public void LoadNSP() + if (!string.IsNullOrEmpty(actualHash)) { - 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 = ""; - 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.ToString() + " bytes)"; - TB_ExactUsedSpace.Text = TB_ROMExactSize.Text; - - while (num_fs >= 1024.0 && num2_fs < array_fs.Length - 1) + LB_ActualHash.Text = $"Actual Hash: {actualHash[..32]}"; + if (actualHash == expectedHash) { - num2_fs++; - num_fs /= 1024.0; - } - TB_ROMSize.Text = $"{num_fs:0.##} {array_fs[num2_fs]}"; - TB_UsedSpace.Text = TB_ROMSize.Text; - - 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(); - - // Console.WriteLine("FC: " + PFS0.PFS0_Headers[0].FileCount.ToString() + " Name: " + array3[n].Name); - - 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(); - contentType = xml.Element("ContentMeta").Element("Type").Value; - if (contentType == "Patch") - xmlVersion = "v" + xml.Element("ContentMeta").Element("Version").Value; - - /*string titleIDBaseGame = TB_TID.Text; - if (contentType != "Application") { - string titleIdBase = TB_TID.Text.Substring(0, 13); - if (contentType == "Patch") //UPDATE - { - titleIDBaseGame = titleIdBase + "000"; - } - else //DLC - { - long tmp = long.Parse(titleIdBase, System.Globalization.NumberStyles.HexNumber) - 1; - titleIDBaseGame = string.Format("0{0:X8}", tmp) + "000"; - } - }*/ - //data.TitleIDBaseGame = titleIDBaseGame; - - 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 = $"tools{Path.DirectorySeparatorChar}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")) - { - 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("-", ""); - xmlVersion = "v" + array7[0].TitleVersion.ToString(); - - if (array7[0].Type == (byte)CNMT.CNMT_Header.TitleType.REGULAR_APPLICATION) - { - contentType = "Application"; - } - else if (array7[0].Type == (byte)CNMT.CNMT_Header.TitleType.UPDATE_TITLE) - { - contentType = "Patch"; - } - else if (array7[0].Type == (byte)CNMT.CNMT_Header.TitleType.ADD_ON_CONTENT) - { - contentType = "AddOnContent"; - } - - 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($"tmp{Path.DirectorySeparatorChar}" + 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 = $"tools{Path.DirectorySeparatorChar}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($"tmp{Path.DirectorySeparatorChar}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 = $"tmp{Path.DirectorySeparatorChar}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]; - } - } - } - } - if (xmlVersion.Trim() == "") - { - TB_GameRev.Text = NACP.NACP_Datas[0].GameVer.Replace("\0", ""); - } - else - { - TB_GameRev.Text = xmlVersion + " (" + NACP.NACP_Datas[0].GameVer.Replace("\0", "") + ")"; - } - 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 { } - - /*if (contentType == "Patch") { - }*/ - } - else - { - TB_GameRev.Text = ""; - 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 = $"tools{Path.DirectorySeparatorChar}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; - 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 process = new Process(); - process.StartInfo = new ProcessStartInfo - { - WindowStyle = ProcessWindowStyle.Hidden, - FileName = $"tools{Path.DirectorySeparatorChar}hactool.exe", - Arguments = "-k keys.txt --section0dir=data meta", - UseShellExecute = false, - CreateNoWindow = true - }; - process.Start(); - process.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); - - 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) - { - 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 = $"tools{Path.DirectorySeparatorChar}hactool.exe", - Arguments = "-k keys.txt --romfsdir=data meta", - UseShellExecute = false, - CreateNoWindow = true - }; - process.Start(); - process.WaitForExit(); - - if (File.Exists($"data{Path.DirectorySeparatorChar}control.nacp")) - { - byte[] source = File.ReadAllBytes($"data{Path.DirectorySeparatorChar}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 = $"data{Path.DirectorySeparatorChar}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 { } - } - } - } - } - - TB_GameRev.Text = GameRevision; - CB_RegionName.SelectedIndex = 0; - - fileStream.Close(); - } + LB_ActualHash.ForeColor = Color.Green; } else { - TB_Dev.Text = Mkey + " not found"; - TB_Name.Text = Mkey + " not found"; + LB_ActualHash.ForeColor = Color.Red; } } - - private void LoadNCAData() + else { - 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); + 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; } - //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) + SaveFileDialog saveFileDialog = new SaveFileDialog(); + saveFileDialog.Filter = "gamecard_cert.dat (*.dat)|*.dat"; + saveFileDialog.FileName = Path.GetFileName("gamecard_cert.dat"); + if (saveFileDialog.ShowDialog() != DialogResult.OK) { - StringBuilder hex = new StringBuilder(ba.Length * 2 + 2); - hex.Append("0x"); - foreach (byte b in ba) - hex.AppendFormat("{0:x2}", b); - return hex.ToString(); + return; } - public static string SHA256Bytes(byte[] ba) + 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)) { - SHA256 mySHA256 = SHA256.Create(); - byte[] hashValue; - hashValue = mySHA256.ComputeHash(ba); - return ByteArrayToString(hashValue); + 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; } - public bool isTrimmed() + if (MessageBox.Show("The cert will be deleted permanently.\nContinue?", "XCI Explorer", MessageBoxButtons.YesNo) != DialogResult.Yes) { - return TB_ROMExactSize.Text == TB_ExactUsedSpace.Text; + return; } - private void LoadPartitions() + using Stream stream = File.Open(TB_File.Text, FileMode.Open); + byte[] array = new byte[512]; + for (int i = 0; i < array.Length; i++) { - string actualHash; - byte[] hashBuffer; - long offset; + array[i] = byte.MaxValue; + } + stream.Position = 28672L; + stream.Write(array, 0, array.Length); - 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); + new CenterWinDialog(this); + MessageBox.Show("Cert deleted."); - 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 B_Extract_Click(object sender, EventArgs e) + { + SaveFileDialog saveFileDialog = new SaveFileDialog + { + FileName = LB_SelectedData.Text + }; + + if (saveFileDialog.ShowDialog() != DialogResult.OK) + { + return; } - private void TV_Partitions_AfterSelect(object sender, TreeViewEventArgs e) + if (backgroundWorker1.IsBusy) { - 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) - { - LB_ActualHash.ForeColor = System.Drawing.Color.Green; - } - else - { - LB_ActualHash.ForeColor = System.Drawing.Color.Red; - } - } - else - { - LB_ActualHash.Text = ""; - } - - } - else - { - LB_SelectedData.Text = ""; - LB_DataOffset.Text = ""; - LB_DataSize.Text = ""; - LB_HashedRegionSize.Text = ""; - LB_ExpectedHash.Text = ""; - LB_ActualHash.Text = ""; - B_Extract.Enabled = false; - } + return; } - 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; - } + B_Extract.Enabled = false; + B_LoadROM.Enabled = false; + B_TrimXCI.Enabled = false; + B_ImportCert.Enabled = false; + B_ClearCert.Enabled = false; - 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; - } + // Start the asynchronous operation. + backgroundWorker1.RunWorkerAsync(saveFileDialog.FileName); + } - private void B_ExportCert_Click(object sender, EventArgs e) - { - using CenterWinDialog center = 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"); - } - } + public byte[] DecryptNCAHeader(long offset) + { + byte[] array = new byte[3072]; - private void B_ImportCert_Click(object sender, EventArgs e) + if (!File.Exists(TB_File.Text)) { - using CenterWinDialog center = 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)) - { - 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) - { - using CenterWinDialog center = 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) - { - using CenterWinDialog center = 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++) - { - array[i] = byte.MaxValue; - } - stream.Position = 28672L; - stream.Write(array, 0, array.Length); - 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)) - { - xtsStream.Read(array, 0, 3072); - } - } - File.Delete(TB_File.Text + ".tmp"); - fileStream.Close(); - } return array; } - private void CB_RegionName_SelectedIndexChanged(object sender, EventArgs e) + FileStream fileStream = new(TB_File.Text, FileMode.Open, FileAccess.Read) { - 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) + 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++) { - PB_GameIcon.BackgroundImage = Icons[num]; - } - else - { - for (int i = 0; i < CB_RegionName.Items.Count; i++) + if (Icons[i] == null) { - if (Icons[i] != null) - { - PB_GameIcon.BackgroundImage = Icons[i]; - break; - } + continue; } - } - 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) - { - using CenterWinDialog center = new CenterWinDialog(this); - if (Util.checkFile(TB_File.Text)) - { - if (MessageBox.Show("Trim XCI?", "XCI Explorer", MessageBoxButtons.YesNo) == DialogResult.Yes) - { - using CenterWinDialog centerInner = new CenterWinDialog(this); - if (!isTrimmed()) - { - 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]}"; - } - } - } - else - { - MessageBox.Show("File not found"); + PB_GameIcon.BackgroundImage = Icons[i]; + break; } } + TB_Name.Text = NACP.NACP_Strings[num].GameName; + TB_Dev.Text = NACP.NACP_Strings[num].GameAuthor; + } - private void LB_ExpectedHash_DoubleClick(object sender, EventArgs e) + private void B_TrimXCI_Click(object sender, EventArgs e) + { + new CenterWinDialog(this); + + if (!File.Exists(TB_File.Text)) { - BetterTreeNode betterTreeNode = (BetterTreeNode)TV_Partitions.SelectedNode; - if (betterTreeNode.Offset != -1) - { - Clipboard.SetText(betterTreeNode.ExpectedHash); - } + MessageBox.Show("File not found"); + return; } - private void LB_ActualHash_DoubleClick(object sender, EventArgs e) + if (MessageBox.Show("Trim XCI?", "XCI Explorer", MessageBoxButtons.YesNo) != DialogResult.Yes) { - BetterTreeNode betterTreeNode = (BetterTreeNode)TV_Partitions.SelectedNode; - if (betterTreeNode.Offset != -1) - { - Clipboard.SetText(betterTreeNode.ActualHash); - } + return; } - private void TB_File_DragDrop(object sender, DragEventArgs e) + new CenterWinDialog(this); + + if (isTrimmed()) { - if (backgroundWorker1.IsBusy != true) - { - string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); - TB_File.Text = files[0]; - ProcessFile(); - } + return; } - private void TB_File_DragEnter(object sender, DragEventArgs e) + 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] { - if (backgroundWorker1.IsBusy != true) - { - if (e.Data.GetDataPresent(DataFormats.FileDrop)) - { - e.Effect = DragDropEffects.Copy; - } - else - { - e.Effect = DragDropEffects.None; - } - } + "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; } - - private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) + 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) { - 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; - byte[] buffer = new byte[8192]; - long num = selectedSize; - int num2; - while ((num2 = fileStream.Read(buffer, 0, 8192)) > 0 && num > 0) - { - fileStream2.Write(buffer, 0, num2); - num -= num2; - } - fileStream.Close(); - } - } + num2++; + num3 /= 1024.0; } + TB_UsedSpace.Text = $"{num3:0.##} {array[num2]}"; + } - private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) + private void LB_ExpectedHash_DoubleClick(object sender, EventArgs e) + { + BetterTreeNode betterTreeNode = (BetterTreeNode)TV_Partitions.SelectedNode; + if (betterTreeNode.Offset != -1) { - using CenterWinDialog center = 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!"); - } + 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; + } + } + + 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!"); + } + } + + 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..f9b6716 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-13.2.1)", + 14 => "MasterKey13 (14.0.0-14.1.2)", + 15 => "MasterKey14 (15.0.0-?)", + 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) + { } }