From ec296621b7754b2339e4f1ada35bc8a534277397 Mon Sep 17 00:00:00 2001
From: StudentBlake <6874208+StudentBlake@users.noreply.github.com>
Date: Thu, 26 Jul 2018 15:10:14 -0400
Subject: [PATCH] Able to read NSP files
---
Properties/AssemblyInfo.cs | 4 +-
XCI Explorer.csproj | 2 +
XCI_Explorer/MainForm.cs | 176 +++++++++++++++++++++++++++++++++++--
3 files changed, 175 insertions(+), 7 deletions(-)
diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs
index 9876921..74336ea 100644
--- a/Properties/AssemblyInfo.cs
+++ b/Properties/AssemblyInfo.cs
@@ -16,5 +16,5 @@ using System.Runtime.Versioning;
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("206c6c47-87b1-477f-b6e6-f7e7c1a92f8f")]
-[assembly: AssemblyFileVersion("1.2.5.0")]
-[assembly: AssemblyVersion("1.2.5.0")]
+[assembly: AssemblyFileVersion("1.3.0.0")]
+[assembly: AssemblyVersion("1.3.0.0")]
diff --git a/XCI Explorer.csproj b/XCI Explorer.csproj
index 95f5446..295d680 100644
--- a/XCI Explorer.csproj
+++ b/XCI Explorer.csproj
@@ -42,6 +42,8 @@
C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll
+
+
diff --git a/XCI_Explorer/MainForm.cs b/XCI_Explorer/MainForm.cs
index 5567ea9..ef1fa8e 100644
--- a/XCI_Explorer/MainForm.cs
+++ b/XCI_Explorer/MainForm.cs
@@ -9,10 +9,10 @@ using System.Windows.Forms;
using System.Text;
using System.Security.Cryptography;
using System.Reflection;
-
using XCI_Explorer.Helpers;
using XTSSharp;
using System.Net;
+using System.Xml.Linq;
namespace XCI_Explorer {
public class MainForm : Form {
@@ -188,7 +188,20 @@ namespace XCI_Explorer {
}
private void ProcessFile() {
- if (CheckXCI()) {
+ if (Path.GetExtension(TB_File.Text).ToLower() == ".nsp") {
+ B_TrimXCI.Enabled = false;
+ B_ExportCert.Enabled = false;
+ B_ImportCert.Enabled = false;
+ B_ViewCert.Enabled = false;
+ B_ClearCert.Enabled = false;
+ LoadNSPMetadata();
+ }
+ 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 {
@@ -199,7 +212,7 @@ namespace XCI_Explorer {
private void B_LoadROM_Click(object sender, EventArgs e) {
OpenFileDialog openFileDialog = new OpenFileDialog();
- openFileDialog.Filter = "Switch XCI (*.xci)|*.xci|All files (*.*)|*.*";
+ openFileDialog.Filter = "Switch XCI/NSP (*.xci, *.nsp)|*.xci;*.nsp|All files (*.*)|*.*";
if (openFileDialog.ShowDialog() == DialogResult.OK) {
TB_File.Text = openFileDialog.FileName;
ProcessFile();
@@ -238,6 +251,152 @@ namespace XCI_Explorer {
LoadGameInfos();
}
+ public void LoadNSPMetadata() {
+ CB_RegionName.Items.Clear();
+ CB_RegionName.Enabled = true;
+ 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);
+ //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) {
+ 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 {
+ process.StartInfo = new ProcessStartInfo {
+ WindowStyle = ProcessWindowStyle.Hidden,
+ FileName = "hactool.exe",
+ Arguments = "-t pfs0 " + "\"" + TB_File.Text + "\"" + " --outdir=tmp"
+ };
+ process.Start();
+ process.WaitForExit();
+ process.Close();
+
+ List listXML = new List();
+ if (!Directory.Exists("tmp")) {
+ }
+ try {
+ foreach (string f in Directory.GetFiles("tmp", "*.xml")) {
+ listXML.Add(f);
+ break;
+ }
+ }
+ catch { }
+
+ XDocument xml = XDocument.Load(listXML.First());
+ TB_TID.Text = xml.Element("ContentMeta").Element("Id").Value.Remove(1, 2).ToUpper();
+ string ncaTarget = "";
+ foreach (XElement xe in xml.Descendants("Content")) {
+ if (xe.Element("Type").Value != "Control") {
+ continue;
+ }
+ ncaTarget = xe.Element("Id").Value + ".nca";
+ break;
+ }
+ process = new Process();
+ process.StartInfo = new ProcessStartInfo {
+ WindowStyle = ProcessWindowStyle.Hidden,
+ FileName = "hactool.exe",
+ Arguments = "-k keys.txt --romfsdir=tmp tmp/" + ncaTarget
+ };
+ process.Start();
+ process.WaitForExit();
+ process.Close();
+ byte[] flux = new byte[200];
+
+ byte[] source = File.ReadAllBytes("tmp\\control.nacp");
+ NACP.NACP_Datas[0] = new NACP.NACP_Data(source.Skip(0x3000).Take(0x1000).ToArray());
+
+ //data.Region_Icon = new Dictionary();
+ //data.Languagues = new List();
+
+ 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 = "data\\icon_" + Language[i].Replace(" ", "") + ".dat";
+ string icon_filename = "tmp\\icon_" + Language[i].Replace(" ", "") + ".dat";
+ if (File.Exists(icon_filename)) {
+ using (Bitmap original = new Bitmap(icon_filename)) {
+ Icons[i] = new Bitmap(original);
+ PB_GameIcon.BackgroundImage = Icons[i];
+ }
+ }
+ }
+ }
+ TB_GameRev.Text = 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;
+ }
+ }
+
+ //Lets get SDK Version, Distribution Type and Masterkey revision
+ //This is far from the best aproach, but its what we have for now
+ process = new Process();
+ process.StartInfo = new ProcessStartInfo {
+ WindowStyle = ProcessWindowStyle.Hidden,
+ FileName = "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] == "Distribution type") {
+ data.DistributionType = strArray[1].Trim();
+ }*/
+ else if (strArray[0] == "Master Key Revision") {
+ TB_MKeyRev.Text = "MasterKey" + strArray[1].Trim();
+ break;
+ }
+ }
+ process.WaitForExit();
+ process.Close();
+ }
+ catch { }
+ finally {
+ Directory.Delete("tmp", true);
+ }
+ TB_Capacity.Text = "eShop";
+ CB_RegionName.SelectedIndex = 0;
+ }
+
private void LoadGameInfos() {
CB_RegionName.Items.Clear();
CB_RegionName.Enabled = true;
@@ -541,7 +700,14 @@ namespace XCI_Explorer {
fileStream.Position = PFS0Offset;
fileStream.Read(array3, 0, 16);
PFS0.PFS0_Headers[0] = new PFS0.PFS0_Header(array3);
- PFS0.PFS0_Entry[] array8 = new PFS0.PFS0_Entry[PFS0.PFS0_Headers[0].FileCount];
+ 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);
@@ -941,7 +1107,7 @@ namespace XCI_Explorer {
this.B_LoadROM.Name = "B_LoadROM";
this.B_LoadROM.Size = new System.Drawing.Size(75, 23);
this.B_LoadROM.TabIndex = 0;
- this.B_LoadROM.Text = "Load XCI";
+ this.B_LoadROM.Text = "Load Game";
this.B_LoadROM.UseVisualStyleBackColor = true;
this.B_LoadROM.Click += new System.EventHandler(this.B_LoadROM_Click);
//