Merge pull request #431 from tom-overton/extract_and_rebuild_updates

Allow users to extract game files from CXI and 3DS files, and also allow them to rebuild into a trimmed 3DS file
This commit is contained in:
Kurt
2019-10-08 14:16:08 -07:00
committed by GitHub
10 changed files with 807 additions and 165 deletions

View File

@@ -17,7 +17,7 @@ public class CTRUtil
public static bool buildROM(bool Card2, string LOGO_NAME,
string EXEFS_PATH, string ROMFS_PATH, string EXHEADER_PATH,
string SERIAL_TEXT, string SAVE_PATH,
ProgressBar PB_Show = null, RichTextBox TB_Progress = null)
bool trimmed = false, ProgressBar PB_Show = null, RichTextBox TB_Progress = null)
{
PB_Show = PB_Show ?? new ProgressBar();
TB_Progress = TB_Progress ?? new RichTextBox();
@@ -37,7 +37,7 @@ public class CTRUtil
NCCH NCCH = setNCCH(EXEFS_PATH, ROMFS_PATH, EXHEADER_PATH, SERIAL_TEXT, LOGO_NAME, PB_Show, TB_Progress);
NCSD NCSD = setNCSD(NCCH, Card2, PB_Show, TB_Progress);
bool success = writeROM(NCSD, SAVE_PATH, PB_Show, TB_Progress);
bool success = writeROM(NCSD, SAVE_PATH, trimmed, PB_Show, TB_Progress);
return success;
}
@@ -62,6 +62,10 @@ public class CTRUtil
NCCH.plainregion = (byte[])Resources.ResourceManager.GetObject("XY");
else if (NCCH.exheader.isORAS())
NCCH.plainregion = (byte[])Resources.ResourceManager.GetObject("ORAS");
else if (NCCH.exheader.isSuMo())
NCCH.plainregion = (byte[])Resources.ResourceManager.GetObject("SuMo");
else if (NCCH.exheader.isUSUM())
NCCH.plainregion = (byte[])Resources.ResourceManager.GetObject("USUM");
}
updateTB(TB_Progress, "Adding ExeFS...");
NCCH.exefs = new ExeFS(EXEFS_PATH);
@@ -196,7 +200,7 @@ public class CTRUtil
return NCSD;
}
internal static bool writeROM(NCSD NCSD, string SAVE_PATH,
internal static bool writeROM(NCSD NCSD, string SAVE_PATH, bool trimmed = false,
ProgressBar PB_Show = null, RichTextBox TB_Progress = null)
{
PB_Show = PB_Show ?? new ProgressBar();
@@ -269,14 +273,17 @@ public class CTRUtil
}
//NCSD Padding
OutFileStream.Seek((NCSD.header.OffsetSizeTable[NCSD.NCCH_Array.Count - 1].Offset * MEDIA_UNIT_SIZE) + (NCSD.header.OffsetSizeTable[NCSD.NCCH_Array.Count - 1].Size * MEDIA_UNIT_SIZE), SeekOrigin.Begin);
ulong TotalLen = NCSD.header.MediaSize * MEDIA_UNIT_SIZE;
byte[] Buffer = Enumerable.Repeat((byte)0xFF, 0x400000).ToArray();
updateTB(TB_Progress, "Writing NCSD Padding...");
while ((ulong)OutFileStream.Position < TotalLen)
if (!trimmed)
{
int BUFFER_LEN = TotalLen - (ulong)OutFileStream.Position < 0x400000 ? (int)(TotalLen - (ulong)OutFileStream.Position) : 0x400000;
OutFileStream.Write(Buffer, 0, BUFFER_LEN);
OutFileStream.Seek((NCSD.header.OffsetSizeTable[NCSD.NCCH_Array.Count - 1].Offset * MEDIA_UNIT_SIZE) + (NCSD.header.OffsetSizeTable[NCSD.NCCH_Array.Count - 1].Size * MEDIA_UNIT_SIZE), SeekOrigin.Begin);
ulong TotalLen = NCSD.header.MediaSize * MEDIA_UNIT_SIZE;
byte[] Buffer = Enumerable.Repeat((byte)0xFF, 0x400000).ToArray();
updateTB(TB_Progress, "Writing NCSD Padding...");
while ((ulong)OutFileStream.Position < TotalLen)
{
int BUFFER_LEN = TotalLen - (ulong)OutFileStream.Position < 0x400000 ? (int)(TotalLen - (ulong)OutFileStream.Position) : 0x400000;
OutFileStream.Write(Buffer, 0, BUFFER_LEN);
}
}
}

View File

@@ -56,7 +56,17 @@ public string GetSerial()
public bool isPokemon()
{
return isORAS() || isXY();
return isORAS() || isXY() || isUSUM() || isSuMo();
}
public bool isUSUM()
{
return (TitleID & 0xFFFFFFFF) >> 8 == 0x1B50 || (TitleID & 0xFFFFFFFF) >> 8 == 0x1B51;
}
public bool isSuMo()
{
return (TitleID & 0xFFFFFFFF) >> 8 == 0x1648 || (TitleID & 0xFFFFFFFF) >> 8 == 0x175E;
}
public bool isORAS()
@@ -76,6 +86,18 @@ public string GetPokemonSerial()
string name;
switch ((TitleID & 0xFFFFFFFF) >> 8)
{
case 0x1B51:
name = "A2BA"; // Ultra Moon
break;
case 0x1B50:
name = "A2AA"; // Ultra Sun
break;
case 0x175E: // Moon
name = "BNEA";
break;
case 0x1648: // Sun
name = "BNDA";
break;
case 0x11C5: //Alpha Sapphire
name = "ECLA";
break;

View File

@@ -1,4 +1,6 @@
using System;
using System.IO;
using System.Windows.Forms;
namespace pk3DS.Core.CTR
{
@@ -73,6 +75,180 @@ public void BuildHeader()
Array.Copy(ExefsHash, 0, Data, 0x1C0, 0x20);
Array.Copy(RomfsHash, 0, Data, 0x1E0, 0x20);
}
public void BuildHeaderFromBytes(byte[] data)
{
Data = data;
Signature = new byte[0x100];
Array.Copy(data, Signature, 0x100);
Magic = BitConverter.ToUInt32(data, 0x100);
Size = BitConverter.ToUInt32(data, 0x104);
TitleId = BitConverter.ToUInt64(data, 0x108);
MakerCode = BitConverter.ToUInt16(data, 0x110);
FormatVersion = BitConverter.ToUInt16(data, 0x112);
//4 Byte Padding
ProgramId = BitConverter.ToUInt64(data, 0x118);
//0x10 Byte Padding
LogoHash = new byte[0x20];
Array.Copy(data, 0x130, LogoHash, 0x0, 0x20);
ProductCode = new byte[0x10];
Array.Copy(data, 0x150, ProductCode, 0x0, 0x10);
ExheaderHash = new byte[0x20];
Array.Copy(data, 0x160, ExheaderHash, 0x0, 0x20);
ExheaderSize = BitConverter.ToUInt32(data, 0x180);
//4 Byte Padding
Flags = new byte[0x8];
Array.Copy(data, 0x188, Flags, 0, 0x8);
PlainRegionOffset = BitConverter.ToUInt32(data, 0x190);
PlainRegionSize = BitConverter.ToUInt32(data, 0x194);
LogoOffset = BitConverter.ToUInt32(data, 0x198);
LogoSize = BitConverter.ToUInt32(data, 0x19C);
ExefsOffset = BitConverter.ToUInt32(data, 0x1A0);
ExefsSize = BitConverter.ToUInt32(data, 0x1A4);
ExefsSuperBlockSize = BitConverter.ToUInt32(data, 0x1A8);
//4 Byte Padding
RomfsOffset = BitConverter.ToUInt32(data, 0x1B0);
RomfsSize = BitConverter.ToUInt32(data, 0x1B4);
RomfsSuperBlockSize = BitConverter.ToUInt32(data, 0x1B8);
//4 Byte Padding
ExefsHash = new byte[0x20];
Array.Copy(data, 0x1C0, ExefsHash, 0x0, 0x20);
RomfsHash = new byte[0x20];
Array.Copy(data, 0x1E0, RomfsHash, 0x0, 0x20);
}
}
public void ExtractNCCHFromFile(string NCCH_PATH, string outputDirectory, RichTextBox TB_Progress = null, ProgressBar PB_Show = null)
{
if (!Directory.Exists(outputDirectory))
Directory.CreateDirectory(outputDirectory);
byte[] headerBytes = new byte[0x200];
using (FileStream fs = new FileStream(NCCH_PATH, FileMode.Open, FileAccess.Read))
{
fs.Read(headerBytes, 0, headerBytes.Length);
header = new Header();
header.BuildHeaderFromBytes(headerBytes);
logo = new byte[header.LogoSize * MEDIA_UNIT_SIZE];
fs.Seek(Convert.ToInt32(header.LogoOffset * MEDIA_UNIT_SIZE), SeekOrigin.Begin);
fs.Read(logo, 0, logo.Length);
plainregion = new byte[header.PlainRegionSize * MEDIA_UNIT_SIZE];
fs.Seek(Convert.ToInt32(header.PlainRegionOffset * MEDIA_UNIT_SIZE), SeekOrigin.Begin);
fs.Read(plainregion, 0, plainregion.Length);
}
ExtractExheader(NCCH_PATH, outputDirectory, TB_Progress);
ExtractExeFS(NCCH_PATH, outputDirectory, TB_Progress, PB_Show);
ExtractRomFS(NCCH_PATH, outputDirectory, TB_Progress, PB_Show);
}
private void ExtractExheader(string NCCH_PATH, string outputDirectory, RichTextBox TB_Progress = null)
{
string exheaderpath = Path.Combine(outputDirectory, "exheader.bin");
updateTB(TB_Progress, "Extracting exheader.bin from CXI...");
byte[] exheaderbytes = new byte[header.ExheaderSize * 2];
using (FileStream fs = new FileStream(NCCH_PATH, FileMode.Open, FileAccess.Read))
{
fs.Seek(Convert.ToInt32(0x200), SeekOrigin.Begin);
fs.Read(exheaderbytes, 0, exheaderbytes.Length);
}
File.WriteAllBytes(exheaderpath, exheaderbytes);
exheader = new Exheader(exheaderpath);
}
private void ExtractExeFS(string NCCH_PATH, string outputDirectory, RichTextBox TB_Progress = null, ProgressBar PB_Show = null)
{
string exefsbinpath = Path.Combine(outputDirectory, "exefs.bin");
string exefspath = Path.Combine(outputDirectory, "exefs");
updateTB(TB_Progress, "Extracting exefs.bin from CXI...");
byte[] exefsbytes = new byte[header.ExefsSize * MEDIA_UNIT_SIZE];
using (FileStream fs = new FileStream(NCCH_PATH, FileMode.Open, FileAccess.Read))
{
fs.Seek(Convert.ToInt32(header.ExefsOffset * MEDIA_UNIT_SIZE), SeekOrigin.Begin);
fs.Read(exefsbytes, 0, exefsbytes.Length);
}
File.WriteAllBytes(exefsbinpath, exefsbytes);
ExeFS.get(exefsbinpath, exefspath);
File.Delete(exefsbinpath);
}
private void ExtractRomFS(string NCCH_PATH, string outputDirectory, RichTextBox TB_Progress = null, ProgressBar PB_Show = null)
{
updateTB(TB_Progress, "Extracting romfs.bin from CXI...");
string romfsbinpath = Path.Combine(outputDirectory, "romfs.bin");
string romfspath = Path.Combine(outputDirectory, "romfs");
byte[] romfsBytes = new byte[MEDIA_UNIT_SIZE];
using (FileStream ncchstream = new FileStream(NCCH_PATH, FileMode.Open, FileAccess.Read),
romfsstream = new FileStream(romfsbinpath, FileMode.Append, FileAccess.Write))
{
ncchstream.Seek(Convert.ToInt32(header.RomfsOffset * MEDIA_UNIT_SIZE), SeekOrigin.Begin);
if (PB_Show.InvokeRequired)
PB_Show.Invoke((MethodInvoker)delegate { PB_Show.Minimum = 0; PB_Show.Step = 1; PB_Show.Value = 0; PB_Show.Maximum = Convert.ToInt32(header.RomfsSize); });
else { PB_Show.Minimum = 0; PB_Show.Step = 1; PB_Show.Value = 0; PB_Show.Maximum = Convert.ToInt32(header.RomfsSize); }
for (int i = 0; i < header.RomfsSize; i++)
{
ncchstream.Read(romfsBytes, 0, romfsBytes.Length);
romfsstream.Write(romfsBytes, 0, romfsBytes.Length);
if (PB_Show.InvokeRequired)
PB_Show.Invoke((MethodInvoker)PB_Show.PerformStep);
else { PB_Show.PerformStep(); }
}
}
RomFS romfs = new RomFS(romfsbinpath);
romfs.ExtractRomFS(romfspath, TB_Progress, PB_Show);
File.Delete(romfsbinpath);
}
private void WriteHeaderToFile(string outputDirectory, RichTextBox TB_Progress)
{
updateTB(TB_Progress, "Extracting ncchheader.bin from CXI...");
string headerParth = Path.Combine(outputDirectory, "ncchheader.bin");
using (FileStream headerStream = new FileStream(headerParth, FileMode.OpenOrCreate, FileAccess.Write))
{
headerStream.Write(this.header.Data, 0, this.header.Data.Length);
}
}
private void WritePlainRegionAndLogo(string outputDirectory, RichTextBox TB_Progress)
{
string plainRegionPath = Path.Combine(outputDirectory, "plain.bin");
string logoPath = Path.Combine(outputDirectory, "logo.bcma.lz");
updateTB(TB_Progress, "Extracting plain.bin and logo.bcma.lz from CXI...");
using (FileStream plainStream = new FileStream(plainRegionPath, FileMode.OpenOrCreate, FileAccess.Write),
logoStream = new FileStream(logoPath, FileMode.OpenOrCreate, FileAccess.Write))
{
plainStream.Write(this.plainregion, 0, this.plainregion.Length);
logoStream.Write(this.logo, 0, this.logo.Length);
}
}
internal static void updateTB(RichTextBox RTB, string progress)
{
try
{
if (RTB.InvokeRequired)
RTB.Invoke((MethodInvoker)delegate
{
RTB.AppendText(Environment.NewLine + progress);
RTB.SelectionStart = RTB.Text.Length;
RTB.ScrollToCaret();
});
else
{
RTB.SelectionStart = RTB.Text.Length;
RTB.ScrollToCaret();
RTB.AppendText(progress + Environment.NewLine);
}
}
catch { }
}
}
}

View File

@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
namespace pk3DS.Core.CTR
{
@@ -56,9 +58,10 @@ public class NCCH_Meta
public uint Size;
}
private const ulong MEDIA_UNIT_SIZE = 0x200;
public ulong GetWritableAddress()
{
const ulong MEDIA_UNIT_SIZE = 0x200;
return Card2
? Align((header.OffsetSizeTable[NCCH_Array.Count - 1].Offset * NCCH.MEDIA_UNIT_SIZE)
+ (header.OffsetSizeTable[NCCH_Array.Count - 1].Size * NCCH.MEDIA_UNIT_SIZE) + 0x1000, 0x10000) / MEDIA_UNIT_SIZE
@@ -101,6 +104,77 @@ public void BuildHeader()
Array.Copy(Enumerable.Repeat((byte)0xFF, 0x2E00).ToArray(), 0, Data, 0x1200, 0x2E00);
}
public Header CreateHeaderFromBytes(byte[] data)
{
Header header = new Header();
Data = data;
header.Signature = new byte[0x100];
Array.Copy(data, header.Signature, 0x100);
header.Magic = BitConverter.ToUInt32(data, 0x100);
header.MediaSize = BitConverter.ToUInt32(data, 0x104);
header.TitleId = BitConverter.ToUInt64(data, 0x108);
header.OffsetSizeTable = new NCCH_Meta[8];
for (int i = 0; i < 8; i++)
{
header.OffsetSizeTable[i] = new NCCH_Meta();
header.OffsetSizeTable[i].Offset = BitConverter.ToUInt32(data, 0x120 + (8 * i));
header.OffsetSizeTable[i].Size = BitConverter.ToUInt32(data, 0x124 + (8 * i));
}
header.flags = new byte[8];
Array.Copy(data, 0x188, header.flags, 0, 8);
header.NCCHIdTable = new ulong[8];
for (int i = 0; i < 8; i++)
{
header.NCCHIdTable[i] = BitConverter.ToUInt64(data, 0x190 + (8 * i));
}
return header;
}
public void ExtractFilesFromNCSD(string NCSD_PATH, string outputDirectory, RichTextBox TB_Progress = null, ProgressBar PB_Show = null)
{
if (!Directory.Exists(outputDirectory))
Directory.CreateDirectory(outputDirectory);
updateTB(TB_Progress, "Extracting game data (CXI) from .3DS file...");
byte[] headerBytes = new byte[0x200];
using (FileStream fs = new FileStream(NCSD_PATH, FileMode.Open, FileAccess.Read))
{
fs.Read(headerBytes, 0, headerBytes.Length);
}
header = CreateHeaderFromBytes(headerBytes);
string ncchPath = ExtractCXIfromNCSD(NCSD_PATH, outputDirectory, header.OffsetSizeTable[0].Size, PB_Show);
updateTB(TB_Progress, "CXI extracted, extracting files from CXI...");
NCCH ncch = new NCCH();
ncch.ExtractNCCHFromFile(ncchPath, outputDirectory, TB_Progress, PB_Show);
File.Delete(ncchPath);
}
private static string ExtractCXIfromNCSD(string NCSD_PATH, string outputDirectory, uint ncchSize, ProgressBar PB_Show = null)
{
byte[] buffer = new byte[MEDIA_UNIT_SIZE * 10];
string outputFile = Path.Combine(outputDirectory, "game.cxi");
if (PB_Show.InvokeRequired)
PB_Show.Invoke((MethodInvoker)delegate { PB_Show.Minimum = 0; PB_Show.Step = 1; PB_Show.Value = 0; PB_Show.Maximum = Convert.ToInt32(ncchSize); });
else { PB_Show.Minimum = 0; PB_Show.Step = 1; PB_Show.Value = 0; PB_Show.Maximum = Convert.ToInt32(ncchSize); }
using (FileStream inputFileStream = new FileStream(NCSD_PATH, FileMode.Open, FileAccess.Read),
outputFileStream = new FileStream(outputFile, FileMode.Append, FileAccess.Write))
{
inputFileStream.Seek(0x4000, SeekOrigin.Begin);
for (int i = 0; i < ncchSize; i++)
{
inputFileStream.Read(buffer, 0, buffer.Length);
outputFileStream.Write(buffer, 0, buffer.Length);
if (PB_Show.InvokeRequired)
PB_Show.Invoke((MethodInvoker)PB_Show.PerformStep);
else { PB_Show.PerformStep(); }
}
}
return outputFile;
}
internal static ulong Align(ulong input, ulong alignsize)
{
ulong output = input;
@@ -110,5 +184,26 @@ internal static ulong Align(ulong input, ulong alignsize)
}
return output;
}
internal static void updateTB(RichTextBox RTB, string progress)
{
try
{
if (RTB.InvokeRequired)
RTB.Invoke((MethodInvoker)delegate
{
RTB.AppendText(Environment.NewLine + progress);
RTB.SelectionStart = RTB.Text.Length;
RTB.ScrollToCaret();
});
else
{
RTB.SelectionStart = RTB.Text.Length;
RTB.ScrollToCaret();
RTB.AppendText(progress + Environment.NewLine);
}
}
catch { }
}
}
}

View File

@@ -64,6 +64,194 @@ internal static void updateTB(RichTextBox RTB, string progress)
catch { }
}
public void ExtractRomFS(string outputDirectory, RichTextBox TB_Progress = null, ProgressBar PB_Show = null)
{
byte[] ivfcHeaderBytes = new byte[0x5C];
using (FileStream file = new FileStream(FileName, FileMode.Open, FileAccess.Read))
{
file.Read(ivfcHeaderBytes, 0, ivfcHeaderBytes.Length);
}
IVFCInfo ivfc = GetIVFCInfoFromBytes(ivfcHeaderBytes);
ulong romfsDataOffset = Align(ivfc.Levels[0].HashOffset + ivfc.MasterHashSize, ivfc.Levels[2].BlockSize);
byte[] romfsInfoHeaderBytes = new byte[0x28];
using (FileStream file = new FileStream(FileName, FileMode.Open, FileAccess.Read))
{
file.Seek(Convert.ToInt64(romfsDataOffset), SeekOrigin.Begin);
file.Read(romfsInfoHeaderBytes, 0, romfsInfoHeaderBytes.Length);
}
Romfs_InfoHeader infoHeader = GetRomfsInfoHeaderFromBytes(romfsInfoHeaderBytes, Convert.ToUInt32(romfsDataOffset));
byte[] directoryMetadataBlock = new byte[infoHeader.Sections[1].Size];
byte[] fileMetadataBlock = new byte[infoHeader.Sections[3].Size];
using (FileStream file = new FileStream(FileName, FileMode.Open, FileAccess.Read))
{
file.Seek(Convert.ToInt64(infoHeader.Sections[1].Offset), SeekOrigin.Begin);
file.Read(directoryMetadataBlock, 0, directoryMetadataBlock.Length);
file.Seek(Convert.ToInt64(infoHeader.Sections[3].Offset), SeekOrigin.Begin);
file.Read(fileMetadataBlock, 0, fileMetadataBlock.Length);
}
if (!Directory.Exists(outputDirectory))
{
Directory.CreateDirectory(outputDirectory);
}
VisitDirectory(0, outputDirectory, directoryMetadataBlock, fileMetadataBlock, infoHeader.DataOffset, TB_Progress, PB_Show);
}
private static IVFCInfo GetIVFCInfoFromBytes(byte[] headerBytes)
{
IVFCInfo ivfc = new IVFCInfo();
uint magic1 = BitConverter.ToUInt32(headerBytes, 0x00);
uint magic2 = BitConverter.ToUInt32(headerBytes, 0x04);
if (magic1 != 0x43465649 || magic2 != 0x10000)
{
throw new ArgumentException("Bad IVFC Header");
}
ivfc.MasterHashSize = BitConverter.ToUInt32(headerBytes, 0x08);
ivfc.Levels = new IVFCLevel[3];
for (int i = 0; i < 3; i++)
{
ivfc.Levels[i] = new IVFCLevel();
ivfc.Levels[i].HashOffset = BitConverter.ToUInt64(headerBytes, 0x0C + (i * 0x18));
ivfc.Levels[i].DataLength = BitConverter.ToUInt64(headerBytes, 0x14 + (i * 0x18));
ivfc.Levels[i].BlockSize = 1U << BitConverter.ToInt32(headerBytes, 0x1C + (i * 0x18));
}
return ivfc;
}
private static Romfs_InfoHeader GetRomfsInfoHeaderFromBytes(byte[] headerBytes, uint bodyOffset)
{
Romfs_InfoHeader infoHeader = new Romfs_InfoHeader();
infoHeader.HeaderLength = BitConverter.ToUInt32(headerBytes, 0x00);
infoHeader.Sections = new Romfs_SectionHeader[4];
for (int i = 0; i < 4; i++)
{
infoHeader.Sections[i] = new Romfs_SectionHeader();
infoHeader.Sections[i].Offset = BitConverter.ToUInt32(headerBytes, 0x04 + (i * 0x08)) + bodyOffset;
infoHeader.Sections[i].Size = BitConverter.ToUInt32(headerBytes, 0x08 + (i * 0x08));
}
infoHeader.DataOffset = BitConverter.ToUInt32(headerBytes, 0x24) + bodyOffset;
return infoHeader;
}
private void VisitDirectory(
uint directoryOffset,
string rootPath,
byte[] directoryMetadataBlock,
byte[] fileMetadataBlock,
ulong dataOffset,
RichTextBox TB_Progress = null,
ProgressBar PB_Show = null)
{
Romfs_DirEntry entry = GetDirEntryFromMetadataBytes(directoryMetadataBlock, Convert.ToInt32(directoryOffset));
string currentPath = Path.Combine(rootPath, entry.Name);
Directory.CreateDirectory(currentPath);
if (entry.FileOffset != 0xFFFFFFFF)
{
VisitFile(entry.FileOffset, currentPath, fileMetadataBlock, dataOffset, TB_Progress, PB_Show);
}
if (entry.ChildOffset != 0xFFFFFFFF)
{
VisitDirectory(entry.ChildOffset, currentPath, directoryMetadataBlock, fileMetadataBlock, dataOffset, TB_Progress, PB_Show);
}
if (entry.SiblingOffset != 0xFFFFFFFF)
{
VisitDirectory(entry.SiblingOffset, rootPath, directoryMetadataBlock, fileMetadataBlock, dataOffset, TB_Progress, PB_Show);
}
}
private void VisitFile(
uint fileOffset,
string rootPath,
byte[] fileMetadataBlock,
ulong dataOffset,
RichTextBox TB_Progress = null,
ProgressBar PB_Show = null)
{
Romfs_FileEntry entry = GetFileEntryFromMetadataBytes(fileMetadataBlock, Convert.ToInt32(fileOffset));
string currentPath = Path.Combine(rootPath, entry.Name);
UpdateTB_Progress(string.Format("Extracting {0} from romfs", currentPath), TB_Progress);
ExtractFileFromRomFS(entry, currentPath, dataOffset, PB_Show);
if (entry.SiblingOffset != 0xFFFFFFFF)
{
VisitFile(entry.SiblingOffset, rootPath, fileMetadataBlock, dataOffset, TB_Progress, PB_Show);
}
}
private static Romfs_DirEntry GetDirEntryFromMetadataBytes(byte[] directoryMetadataBlock, int directoryOffset)
{
Romfs_DirEntry entry = new Romfs_DirEntry();
entry.ParentOffset = BitConverter.ToUInt32(directoryMetadataBlock, directoryOffset);
entry.SiblingOffset = BitConverter.ToUInt32(directoryMetadataBlock, directoryOffset + 0x04);
entry.ChildOffset = BitConverter.ToUInt32(directoryMetadataBlock, directoryOffset + 0x08);
entry.FileOffset = BitConverter.ToUInt32(directoryMetadataBlock, directoryOffset + 0x0C);
uint nameLength = BitConverter.ToUInt32(directoryMetadataBlock, directoryOffset + 0x14);
entry.Name = "";
if (nameLength != 0xFFFFFFFF)
{
byte[] fileNameBytes = new byte[nameLength];
Array.Copy(directoryMetadataBlock, directoryOffset + 0x18, fileNameBytes, 0, fileNameBytes.Length);
entry.Name = Encoding.Unicode.GetString(fileNameBytes);
}
return entry;
}
private static Romfs_FileEntry GetFileEntryFromMetadataBytes(byte[] fileMetadataBlock, int fileOffset)
{
Romfs_FileEntry entry = new Romfs_FileEntry();
entry.ParentDirOffset = BitConverter.ToUInt32(fileMetadataBlock, fileOffset);
entry.SiblingOffset = BitConverter.ToUInt32(fileMetadataBlock, fileOffset + 0x04);
entry.DataOffset = BitConverter.ToUInt64(fileMetadataBlock, fileOffset + 0x08);
entry.DataSize = BitConverter.ToUInt64(fileMetadataBlock, fileOffset + 0x10);
entry.NameSize = BitConverter.ToUInt32(fileMetadataBlock, fileOffset + 0x1C);
entry.Name = "";
if (entry.NameSize != 0xFFFFFFFF)
{
byte[] fileNameBytes = new byte[entry.NameSize];
Array.Copy(fileMetadataBlock, fileOffset + 0x20, fileNameBytes, 0, fileNameBytes.Length);
entry.Name = Encoding.Unicode.GetString(fileNameBytes);
}
return entry;
}
private void ExtractFileFromRomFS(Romfs_FileEntry entry, string path, ulong dataOffset, ProgressBar PB_Show = null)
{
ulong offsetInRomFS = dataOffset + entry.DataOffset;
byte[] buffer = new byte[0x2000];
using (FileStream romfsFileStream = new FileStream(FileName, FileMode.Open, FileAccess.Read),
outputFileStream = new FileStream(path, FileMode.Append, FileAccess.Write))
{
romfsFileStream.Seek(Convert.ToInt64(offsetInRomFS), SeekOrigin.Begin);
int remainingSize = Convert.ToInt32(entry.DataSize);
if (PB_Show.InvokeRequired)
PB_Show.Invoke((MethodInvoker)delegate { PB_Show.Minimum = 0; PB_Show.Step = 1; PB_Show.Value = 0; PB_Show.Maximum = remainingSize / buffer.Length; });
else { PB_Show.Minimum = 0; PB_Show.Step = 1; PB_Show.Value = 0; PB_Show.Maximum = remainingSize / buffer.Length; }
while (remainingSize > 0)
{
int sizeToReadWrite = buffer.Length > remainingSize ? remainingSize : buffer.Length;
romfsFileStream.Read(buffer, 0, sizeToReadWrite);
outputFileStream.Write(buffer, 0, sizeToReadWrite);
remainingSize -= sizeToReadWrite;
if (PB_Show.InvokeRequired)
PB_Show.Invoke((MethodInvoker)PB_Show.PerformStep);
else { PB_Show.PerformStep(); }
}
}
}
public static void BuildRomFS(string infile, string outfile, RichTextBox TB_Progress = null, ProgressBar PB_Show = null)
{
OutFile = outfile;
@@ -283,7 +471,17 @@ internal static string ByteArrayToString(IEnumerable<byte> input)
internal static void UpdateTB_Progress(string text, RichTextBox TB_Progress = null)
{
TB_Progress.Text += text + Environment.NewLine;
if (TB_Progress.InvokeRequired)
{
TB_Progress.Invoke((MethodInvoker)delegate
{
TB_Progress.Text += text + Environment.NewLine;
});
}
else
{
TB_Progress.Text += text + Environment.NewLine;
}
}
internal static void BuildRomFSHeader(MemoryStream romfs_stream, RomfsFile[] Entries, string DIR)
@@ -736,6 +934,7 @@ public static ulong GetDataBlockLength(RomfsFile[] files, ulong PreData)
public class IVFCInfo
{
public uint MasterHashSize;
public IVFCLevel[] Levels;
}

Binary file not shown.

Binary file not shown.

View File

@@ -3573,4 +3573,8 @@
000400000011BB00 JXQE Johnny Dynamite
0004000000158C00 JT7E 3D Thunder Blade
0004000000158200 JT7P 3D Thunder Blade
000400000016AC00 JWXE Samurai Defender
000400000016AC00 JWXE Samurai Defender
0004000000164800 BNDA Pokémon™ Sun
0004000000175E00 BNEA Pokémon™ Moon
00040000001B5000 A2AA Pokémon™ Ultra Sun
00040000001B5100 A2BA Pokémon™ Ultra Moon

321
pk3DS/Main.Designer.cs generated
View File

@@ -48,10 +48,13 @@ private void InitializeComponent()
this.Menu_BLZ = new System.Windows.Forms.ToolStripMenuItem();
this.Menu_LZ11 = new System.Windows.Forms.ToolStripMenuItem();
this.Menu_Shuffler = new System.Windows.Forms.ToolStripMenuItem();
this.Menu_Extract = new System.Windows.Forms.ToolStripMenuItem();
this.Menu_Extract_CXI = new System.Windows.Forms.ToolStripMenuItem();
this.Menu_Rebuild = new System.Windows.Forms.ToolStripMenuItem();
this.Menu_RomFS = new System.Windows.Forms.ToolStripMenuItem();
this.Menu_ExeFS = new System.Windows.Forms.ToolStripMenuItem();
this.Menu_CRO = new System.Windows.Forms.ToolStripMenuItem();
this.Menu_Trimmed3DS = new System.Windows.Forms.ToolStripMenuItem();
this.Menu_3DS = new System.Windows.Forms.ToolStripMenuItem();
this.Menu_Patch = new System.Windows.Forms.ToolStripMenuItem();
this.Menu_SMDH = new System.Windows.Forms.ToolStripMenuItem();
@@ -92,6 +95,7 @@ private void InitializeComponent()
this.B_Static = new System.Windows.Forms.Button();
this.Tab_Output = new System.Windows.Forms.TabPage();
this.L_Status = new System.Windows.Forms.Label();
this.Menu_Extract_3DS = new System.Windows.Forms.ToolStripMenuItem();
this.menuStrip1.SuspendLayout();
this.TC_RomFS.SuspendLayout();
this.Tab_RomFS.SuspendLayout();
@@ -102,19 +106,19 @@ private void InitializeComponent()
this.FLP_CRO.SuspendLayout();
this.Tab_Output.SuspendLayout();
this.SuspendLayout();
//
//
// TB_Path
//
this.TB_Path.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
//
this.TB_Path.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.TB_Path.Location = new System.Drawing.Point(158, 3);
this.TB_Path.Name = "TB_Path";
this.TB_Path.ReadOnly = true;
this.TB_Path.Size = new System.Drawing.Size(214, 20);
this.TB_Path.TabIndex = 1;
//
//
// L_Game
//
//
this.L_Game.AutoSize = true;
this.L_Game.ForeColor = System.Drawing.Color.Red;
this.L_Game.Location = new System.Drawing.Point(157, 23);
@@ -122,18 +126,18 @@ private void InitializeComponent()
this.L_Game.Size = new System.Drawing.Size(91, 13);
this.L_Game.TabIndex = 2;
this.L_Game.Text = "No Game Loaded";
//
//
// pBar1
//
this.pBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
//
this.pBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.pBar1.Location = new System.Drawing.Point(12, 225);
this.pBar1.Name = "pBar1";
this.pBar1.Size = new System.Drawing.Size(360, 14);
this.pBar1.TabIndex = 6;
//
//
// B_OPower
//
//
this.B_OPower.Location = new System.Drawing.Point(215, 32);
this.B_OPower.Name = "B_OPower";
this.B_OPower.Size = new System.Drawing.Size(100, 23);
@@ -141,9 +145,9 @@ private void InitializeComponent()
this.B_OPower.Text = "O-Powers";
this.B_OPower.UseVisualStyleBackColor = true;
this.B_OPower.Click += new System.EventHandler(this.B_OPower_Click);
//
//
// B_Pickup
//
//
this.B_Pickup.Location = new System.Drawing.Point(109, 32);
this.B_Pickup.Name = "B_Pickup";
this.B_Pickup.Size = new System.Drawing.Size(100, 23);
@@ -151,9 +155,9 @@ private void InitializeComponent()
this.B_Pickup.Text = "Pickup Items";
this.B_Pickup.UseVisualStyleBackColor = true;
this.B_Pickup.Click += new System.EventHandler(this.B_Pickup_Click);
//
//
// B_Mart
//
//
this.B_Mart.Location = new System.Drawing.Point(3, 32);
this.B_Mart.Name = "B_Mart";
this.B_Mart.Size = new System.Drawing.Size(100, 23);
@@ -161,9 +165,9 @@ private void InitializeComponent()
this.B_Mart.Text = "Poké Mart";
this.B_Mart.UseVisualStyleBackColor = true;
this.B_Mart.Click += new System.EventHandler(this.B_Mart_Click);
//
//
// B_MoveTutor
//
//
this.B_MoveTutor.Location = new System.Drawing.Point(3, 3);
this.B_MoveTutor.Name = "B_MoveTutor";
this.B_MoveTutor.Size = new System.Drawing.Size(100, 23);
@@ -171,9 +175,9 @@ private void InitializeComponent()
this.B_MoveTutor.Text = "Move Tutors";
this.B_MoveTutor.UseVisualStyleBackColor = true;
this.B_MoveTutor.Click += new System.EventHandler(this.B_MoveTutor_Click);
//
//
// B_TMHM
//
//
this.B_TMHM.Location = new System.Drawing.Point(109, 3);
this.B_TMHM.Name = "B_TMHM";
this.B_TMHM.Size = new System.Drawing.Size(100, 23);
@@ -181,9 +185,9 @@ private void InitializeComponent()
this.B_TMHM.Text = "TMs/HMs";
this.B_TMHM.UseVisualStyleBackColor = true;
this.B_TMHM.Click += new System.EventHandler(this.B_TMHM_Click);
//
//
// RTB_Status
//
//
this.RTB_Status.Dock = System.Windows.Forms.DockStyle.Fill;
this.RTB_Status.Location = new System.Drawing.Point(0, 0);
this.RTB_Status.Name = "RTB_Status";
@@ -191,9 +195,9 @@ private void InitializeComponent()
this.RTB_Status.Size = new System.Drawing.Size(352, 154);
this.RTB_Status.TabIndex = 7;
this.RTB_Status.Text = "";
//
//
// menuStrip1
//
//
this.menuStrip1.BackColor = System.Drawing.Color.Transparent;
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.Menu_File,
@@ -204,54 +208,55 @@ private void InitializeComponent()
this.menuStrip1.Size = new System.Drawing.Size(384, 24);
this.menuStrip1.TabIndex = 9;
this.menuStrip1.Text = "menuStrip1";
//
//
// Menu_File
//
//
this.Menu_File.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.Menu_Open,
this.Menu_Exit});
this.Menu_File.Name = "Menu_File";
this.Menu_File.Size = new System.Drawing.Size(37, 20);
this.Menu_File.Text = "File";
//
//
// Menu_Open
//
//
this.Menu_Open.Name = "Menu_Open";
this.Menu_Open.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.O)));
this.Menu_Open.Size = new System.Drawing.Size(155, 22);
this.Menu_Open.Text = "&Open...";
this.Menu_Open.Click += new System.EventHandler(this.B_Open_Click);
//
//
// Menu_Exit
//
//
this.Menu_Exit.Name = "Menu_Exit";
this.Menu_Exit.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Q)));
this.Menu_Exit.Size = new System.Drawing.Size(155, 22);
this.Menu_Exit.Text = "&Exit";
this.Menu_Exit.Click += new System.EventHandler(this.Menu_Exit_Click);
//
//
// Menu_Tools
//
//
this.Menu_Tools.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.Menu_Restore,
this.Menu_Misc,
this.Menu_Extract,
this.Menu_Rebuild,
this.Menu_SMDH,
this.randomizationToolStripMenuItem});
this.Menu_Tools.Name = "Menu_Tools";
this.Menu_Tools.Size = new System.Drawing.Size(47, 20);
this.Menu_Tools.Size = new System.Drawing.Size(46, 20);
this.Menu_Tools.Text = "Tools";
//
//
// Menu_Restore
//
//
this.Menu_Restore.Enabled = false;
this.Menu_Restore.Name = "Menu_Restore";
this.Menu_Restore.Size = new System.Drawing.Size(184, 22);
this.Menu_Restore.Text = "Restore Original Files";
this.Menu_Restore.Click += new System.EventHandler(this.L_Game_Click);
//
//
// Menu_Misc
//
//
this.Menu_Misc.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.unPackBCLIMToolStripMenuItem,
this.Menu_BLZ,
@@ -260,115 +265,140 @@ private void InitializeComponent()
this.Menu_Misc.Name = "Menu_Misc";
this.Menu_Misc.Size = new System.Drawing.Size(184, 22);
this.Menu_Misc.Text = "Misc Tools";
//
//
// unPackBCLIMToolStripMenuItem
//
//
this.unPackBCLIMToolStripMenuItem.Name = "unPackBCLIMToolStripMenuItem";
this.unPackBCLIMToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.T)));
this.unPackBCLIMToolStripMenuItem.Size = new System.Drawing.Size(216, 22);
this.unPackBCLIMToolStripMenuItem.Text = "(un)Pack + BCLIM";
this.unPackBCLIMToolStripMenuItem.Click += new System.EventHandler(this.L_SubTools_Click);
//
//
// Menu_BLZ
//
//
this.Menu_BLZ.Name = "Menu_BLZ";
this.Menu_BLZ.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.B)));
this.Menu_BLZ.Size = new System.Drawing.Size(216, 22);
this.Menu_BLZ.Text = "(de)Compress BLZ";
this.Menu_BLZ.Click += new System.EventHandler(this.Menu_BLZ_Click);
//
//
// Menu_LZ11
//
//
this.Menu_LZ11.Name = "Menu_LZ11";
this.Menu_LZ11.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.L)));
this.Menu_LZ11.Size = new System.Drawing.Size(216, 22);
this.Menu_LZ11.Text = "(de)Compress LZ11";
this.Menu_LZ11.Click += new System.EventHandler(this.Menu_LZ11_Click);
//
//
// Menu_Shuffler
//
//
this.Menu_Shuffler.Enabled = false;
this.Menu_Shuffler.Name = "Menu_Shuffler";
this.Menu_Shuffler.Size = new System.Drawing.Size(216, 22);
this.Menu_Shuffler.Text = "GARC Shuffler";
this.Menu_Shuffler.Click += new System.EventHandler(this.Menu_Shuffler_Click);
//
//
// Menu_Extract
//
this.Menu_Extract.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.Menu_Extract_CXI,
this.Menu_Extract_3DS});
this.Menu_Extract.Name = "Menu_Extract";
this.Menu_Extract.Size = new System.Drawing.Size(184, 22);
this.Menu_Extract.Text = "Extract...";
//
// Menu_Extract_CXI
//
this.Menu_Extract_CXI.Name = "Menu_Extract_CXI";
this.Menu_Extract_CXI.Size = new System.Drawing.Size(180, 22);
this.Menu_Extract_CXI.Text = ".CXI";
this.Menu_Extract_CXI.Click += new System.EventHandler(this.B_ExtractCXI_Click);
//
// Menu_Rebuild
//
//
this.Menu_Rebuild.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.Menu_RomFS,
this.Menu_ExeFS,
this.Menu_CRO,
this.Menu_Trimmed3DS,
this.Menu_3DS,
this.Menu_Patch});
this.Menu_Rebuild.Name = "Menu_Rebuild";
this.Menu_Rebuild.Size = new System.Drawing.Size(184, 22);
this.Menu_Rebuild.Text = "Rebuild...";
//
//
// Menu_RomFS
//
//
this.Menu_RomFS.Enabled = false;
this.Menu_RomFS.Name = "Menu_RomFS";
this.Menu_RomFS.Size = new System.Drawing.Size(111, 22);
this.Menu_RomFS.Size = new System.Drawing.Size(180, 22);
this.Menu_RomFS.Text = "RomFS";
this.Menu_RomFS.Click += new System.EventHandler(this.rebuildRomFS);
//
//
// Menu_ExeFS
//
//
this.Menu_ExeFS.Enabled = false;
this.Menu_ExeFS.Name = "Menu_ExeFS";
this.Menu_ExeFS.Size = new System.Drawing.Size(111, 22);
this.Menu_ExeFS.Size = new System.Drawing.Size(180, 22);
this.Menu_ExeFS.Text = "ExeFS";
this.Menu_ExeFS.Click += new System.EventHandler(this.rebuildExeFS);
//
//
// Menu_CRO
//
//
this.Menu_CRO.Enabled = false;
this.Menu_CRO.Name = "Menu_CRO";
this.Menu_CRO.Size = new System.Drawing.Size(111, 22);
this.Menu_CRO.Size = new System.Drawing.Size(180, 22);
this.Menu_CRO.Text = "CRO";
this.Menu_CRO.Click += new System.EventHandler(this.patchCRO_CRR);
//
//
// Menu_Trimmed3DS
//
this.Menu_Trimmed3DS.Enabled = false;
this.Menu_Trimmed3DS.Name = "Menu_Trimmed3DS";
this.Menu_Trimmed3DS.Size = new System.Drawing.Size(180, 22);
this.Menu_Trimmed3DS.Text = "Trimmed .3DS";
this.Menu_Trimmed3DS.Click += new System.EventHandler(this.B_RebuildTrimmed3DS_Click);
//
// Menu_3DS
//
//
this.Menu_3DS.Enabled = false;
this.Menu_3DS.Name = "Menu_3DS";
this.Menu_3DS.Size = new System.Drawing.Size(111, 22);
this.Menu_3DS.Size = new System.Drawing.Size(180, 22);
this.Menu_3DS.Text = ".3DS";
this.Menu_3DS.Click += new System.EventHandler(this.B_Rebuild3DS_Click);
//
//
// Menu_Patch
//
//
this.Menu_Patch.Enabled = false;
this.Menu_Patch.Name = "Menu_Patch";
this.Menu_Patch.Size = new System.Drawing.Size(111, 22);
this.Menu_Patch.Size = new System.Drawing.Size(180, 22);
this.Menu_Patch.Text = "Patch";
this.Menu_Patch.Click += new System.EventHandler(this.B_Patch_Click);
//
//
// Menu_SMDH
//
//
this.Menu_SMDH.Name = "Menu_SMDH";
this.Menu_SMDH.Size = new System.Drawing.Size(184, 22);
this.Menu_SMDH.Text = "SMDH Editor (Icon)";
this.Menu_SMDH.Click += new System.EventHandler(this.Menu_SMDH_Click);
//
//
// randomizationToolStripMenuItem
//
//
this.randomizationToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.setInt32SeedToolStripMenuItem});
this.randomizationToolStripMenuItem.Name = "randomizationToolStripMenuItem";
this.randomizationToolStripMenuItem.Size = new System.Drawing.Size(184, 22);
this.randomizationToolStripMenuItem.Text = "Randomization";
//
//
// setInt32SeedToolStripMenuItem
//
//
this.setInt32SeedToolStripMenuItem.Name = "setInt32SeedToolStripMenuItem";
this.setInt32SeedToolStripMenuItem.Size = new System.Drawing.Size(146, 22);
this.setInt32SeedToolStripMenuItem.Text = "Set int32 seed";
this.setInt32SeedToolStripMenuItem.Click += new System.EventHandler(this.setInt32SeedToolStripMenuItem_Click);
//
//
// Menu_Options
//
//
this.Menu_Options.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.Menu_Language,
this.Menu_About,
@@ -376,17 +406,17 @@ private void InitializeComponent()
this.Menu_Options.Name = "Menu_Options";
this.Menu_Options.Size = new System.Drawing.Size(61, 20);
this.Menu_Options.Text = "Options";
//
//
// Menu_Language
//
//
this.Menu_Language.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.CB_Lang});
this.Menu_Language.Name = "Menu_Language";
this.Menu_Language.Size = new System.Drawing.Size(146, 22);
this.Menu_Language.Text = "Language";
//
//
// CB_Lang
//
//
this.CB_Lang.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.CB_Lang.Items.AddRange(new object[] {
"カタカナ",
@@ -402,27 +432,27 @@ private void InitializeComponent()
this.CB_Lang.Name = "CB_Lang";
this.CB_Lang.Size = new System.Drawing.Size(121, 23);
this.CB_Lang.SelectedIndexChanged += new System.EventHandler(this.ChangeLanguage);
//
//
// Menu_About
//
//
this.Menu_About.Name = "Menu_About";
this.Menu_About.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.B)));
this.Menu_About.ShowShortcutKeys = false;
this.Menu_About.Size = new System.Drawing.Size(146, 22);
this.Menu_About.Text = "A&bout pk3DS";
this.Menu_About.Click += new System.EventHandler(this.L_About_Click);
//
//
// Menu_GARCs
//
//
this.Menu_GARCs.Name = "Menu_GARCs";
this.Menu_GARCs.Size = new System.Drawing.Size(146, 22);
this.Menu_GARCs.Text = "About GARCs";
this.Menu_GARCs.Click += new System.EventHandler(this.L_GARCInfo_Click);
//
//
// TC_RomFS
//
this.TC_RomFS.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
//
this.TC_RomFS.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.TC_RomFS.Controls.Add(this.Tab_RomFS);
this.TC_RomFS.Controls.Add(this.Tab_ExeFS);
@@ -433,9 +463,9 @@ private void InitializeComponent()
this.TC_RomFS.SelectedIndex = 0;
this.TC_RomFS.Size = new System.Drawing.Size(360, 180);
this.TC_RomFS.TabIndex = 11;
//
//
// Tab_RomFS
//
//
this.Tab_RomFS.Controls.Add(this.FLP_RomFS);
this.Tab_RomFS.Location = new System.Drawing.Point(4, 22);
this.Tab_RomFS.Name = "Tab_RomFS";
@@ -444,9 +474,9 @@ private void InitializeComponent()
this.Tab_RomFS.TabIndex = 0;
this.Tab_RomFS.Text = "RomFS";
this.Tab_RomFS.UseVisualStyleBackColor = true;
//
//
// FLP_RomFS
//
//
this.FLP_RomFS.AutoScroll = true;
this.FLP_RomFS.Controls.Add(this.B_GameText);
this.FLP_RomFS.Controls.Add(this.B_StoryText);
@@ -468,9 +498,9 @@ private void InitializeComponent()
this.FLP_RomFS.Name = "FLP_RomFS";
this.FLP_RomFS.Size = new System.Drawing.Size(346, 148);
this.FLP_RomFS.TabIndex = 13;
//
//
// B_GameText
//
//
this.B_GameText.Location = new System.Drawing.Point(3, 3);
this.B_GameText.Name = "B_GameText";
this.B_GameText.Size = new System.Drawing.Size(100, 23);
@@ -478,9 +508,9 @@ private void InitializeComponent()
this.B_GameText.Text = "Game Text";
this.B_GameText.UseVisualStyleBackColor = true;
this.B_GameText.Click += new System.EventHandler(this.B_GameText_Click);
//
//
// B_StoryText
//
//
this.B_StoryText.Location = new System.Drawing.Point(109, 3);
this.B_StoryText.Name = "B_StoryText";
this.B_StoryText.Size = new System.Drawing.Size(100, 23);
@@ -488,9 +518,9 @@ private void InitializeComponent()
this.B_StoryText.Text = "Story Text";
this.B_StoryText.UseVisualStyleBackColor = true;
this.B_StoryText.Click += new System.EventHandler(this.B_StoryText_Click);
//
//
// B_Personal
//
//
this.B_Personal.Location = new System.Drawing.Point(215, 3);
this.B_Personal.Name = "B_Personal";
this.B_Personal.Size = new System.Drawing.Size(100, 23);
@@ -498,9 +528,9 @@ private void InitializeComponent()
this.B_Personal.Text = "Personal Stats";
this.B_Personal.UseVisualStyleBackColor = true;
this.B_Personal.Click += new System.EventHandler(this.B_Personal_Click);
//
//
// B_Evolution
//
//
this.B_Evolution.Location = new System.Drawing.Point(3, 32);
this.B_Evolution.Name = "B_Evolution";
this.B_Evolution.Size = new System.Drawing.Size(100, 23);
@@ -508,9 +538,9 @@ private void InitializeComponent()
this.B_Evolution.Text = "Evolutions";
this.B_Evolution.UseVisualStyleBackColor = true;
this.B_Evolution.Click += new System.EventHandler(this.B_Evolution_Click);
//
//
// B_LevelUp
//
//
this.B_LevelUp.Location = new System.Drawing.Point(109, 32);
this.B_LevelUp.Name = "B_LevelUp";
this.B_LevelUp.Size = new System.Drawing.Size(100, 23);
@@ -518,9 +548,9 @@ private void InitializeComponent()
this.B_LevelUp.Text = "Level Up Moves";
this.B_LevelUp.UseVisualStyleBackColor = true;
this.B_LevelUp.Click += new System.EventHandler(this.B_LevelUp_Click);
//
//
// B_Wild
//
//
this.B_Wild.Location = new System.Drawing.Point(215, 32);
this.B_Wild.Name = "B_Wild";
this.B_Wild.Size = new System.Drawing.Size(100, 23);
@@ -528,9 +558,9 @@ private void InitializeComponent()
this.B_Wild.Text = "Wild Encounters";
this.B_Wild.UseVisualStyleBackColor = true;
this.B_Wild.Click += new System.EventHandler(this.B_Wild_Click);
//
//
// B_MegaEvo
//
//
this.B_MegaEvo.Location = new System.Drawing.Point(3, 61);
this.B_MegaEvo.Name = "B_MegaEvo";
this.B_MegaEvo.Size = new System.Drawing.Size(100, 23);
@@ -538,9 +568,9 @@ private void InitializeComponent()
this.B_MegaEvo.Text = "Mega Evolutions";
this.B_MegaEvo.UseVisualStyleBackColor = true;
this.B_MegaEvo.Click += new System.EventHandler(this.B_MegaEvo_Click);
//
//
// B_EggMove
//
//
this.B_EggMove.Location = new System.Drawing.Point(109, 61);
this.B_EggMove.Name = "B_EggMove";
this.B_EggMove.Size = new System.Drawing.Size(100, 23);
@@ -548,9 +578,9 @@ private void InitializeComponent()
this.B_EggMove.Text = "Egg Moves";
this.B_EggMove.UseVisualStyleBackColor = true;
this.B_EggMove.Click += new System.EventHandler(this.B_EggMove_Click);
//
//
// B_Trainer
//
//
this.B_Trainer.Location = new System.Drawing.Point(215, 61);
this.B_Trainer.Name = "B_Trainer";
this.B_Trainer.Size = new System.Drawing.Size(100, 23);
@@ -558,9 +588,9 @@ private void InitializeComponent()
this.B_Trainer.Text = "Trainers";
this.B_Trainer.UseVisualStyleBackColor = true;
this.B_Trainer.Click += new System.EventHandler(this.B_Trainer_Click);
//
//
// B_Maison
//
//
this.B_Maison.Location = new System.Drawing.Point(3, 90);
this.B_Maison.Name = "B_Maison";
this.B_Maison.Size = new System.Drawing.Size(100, 23);
@@ -568,9 +598,9 @@ private void InitializeComponent()
this.B_Maison.Text = "Battle Maison";
this.B_Maison.UseVisualStyleBackColor = true;
this.B_Maison.Click += new System.EventHandler(this.B_Maison_Click);
//
//
// B_Royal
//
//
this.B_Royal.Location = new System.Drawing.Point(109, 90);
this.B_Royal.Name = "B_Royal";
this.B_Royal.Size = new System.Drawing.Size(100, 23);
@@ -578,9 +608,9 @@ private void InitializeComponent()
this.B_Royal.Text = "Battle Royal/Tree";
this.B_Royal.UseVisualStyleBackColor = true;
this.B_Royal.Click += new System.EventHandler(this.B_Maison_Click);
//
//
// B_Item
//
//
this.B_Item.Location = new System.Drawing.Point(215, 90);
this.B_Item.Name = "B_Item";
this.B_Item.Size = new System.Drawing.Size(100, 23);
@@ -588,9 +618,9 @@ private void InitializeComponent()
this.B_Item.Text = "Item Stats";
this.B_Item.UseVisualStyleBackColor = true;
this.B_Item.Click += new System.EventHandler(this.B_Item_Click);
//
//
// B_Move
//
//
this.B_Move.Location = new System.Drawing.Point(3, 119);
this.B_Move.Name = "B_Move";
this.B_Move.Size = new System.Drawing.Size(100, 23);
@@ -598,9 +628,9 @@ private void InitializeComponent()
this.B_Move.Text = "Move Stats";
this.B_Move.UseVisualStyleBackColor = true;
this.B_Move.Click += new System.EventHandler(this.B_Move_Click);
//
//
// B_TitleScreen
//
//
this.B_TitleScreen.Location = new System.Drawing.Point(109, 119);
this.B_TitleScreen.Name = "B_TitleScreen";
this.B_TitleScreen.Size = new System.Drawing.Size(100, 23);
@@ -608,9 +638,9 @@ private void InitializeComponent()
this.B_TitleScreen.Text = "Title Screen";
this.B_TitleScreen.UseVisualStyleBackColor = true;
this.B_TitleScreen.Click += new System.EventHandler(this.B_TitleScreen_Click);
//
//
// B_OWSE
//
//
this.B_OWSE.Location = new System.Drawing.Point(215, 119);
this.B_OWSE.Name = "B_OWSE";
this.B_OWSE.Size = new System.Drawing.Size(100, 23);
@@ -618,9 +648,9 @@ private void InitializeComponent()
this.B_OWSE.Text = "OWSE [Dev]";
this.B_OWSE.UseVisualStyleBackColor = true;
this.B_OWSE.Click += new System.EventHandler(this.B_OWSE_Click);
//
//
// Tab_ExeFS
//
//
this.Tab_ExeFS.Controls.Add(this.FLP_ExeFS);
this.Tab_ExeFS.Location = new System.Drawing.Point(4, 22);
this.Tab_ExeFS.Name = "Tab_ExeFS";
@@ -629,9 +659,9 @@ private void InitializeComponent()
this.Tab_ExeFS.TabIndex = 1;
this.Tab_ExeFS.Text = "ExeFS";
this.Tab_ExeFS.UseVisualStyleBackColor = true;
//
//
// FLP_ExeFS
//
//
this.FLP_ExeFS.AutoScroll = true;
this.FLP_ExeFS.Controls.Add(this.B_MoveTutor);
this.FLP_ExeFS.Controls.Add(this.B_TMHM);
@@ -645,9 +675,9 @@ private void InitializeComponent()
this.FLP_ExeFS.Name = "FLP_ExeFS";
this.FLP_ExeFS.Size = new System.Drawing.Size(346, 148);
this.FLP_ExeFS.TabIndex = 11;
//
//
// B_TM
//
//
this.B_TM.Location = new System.Drawing.Point(215, 3);
this.B_TM.Name = "B_TM";
this.B_TM.Size = new System.Drawing.Size(100, 23);
@@ -655,9 +685,9 @@ private void InitializeComponent()
this.B_TM.Text = "TMs";
this.B_TM.UseVisualStyleBackColor = true;
this.B_TM.Click += new System.EventHandler(this.B_TMHM_Click);
//
//
// B_ShinyRate
//
//
this.B_ShinyRate.Location = new System.Drawing.Point(3, 61);
this.B_ShinyRate.Name = "B_ShinyRate";
this.B_ShinyRate.Size = new System.Drawing.Size(100, 23);
@@ -665,9 +695,9 @@ private void InitializeComponent()
this.B_ShinyRate.Text = "Shiny Rate";
this.B_ShinyRate.UseVisualStyleBackColor = true;
this.B_ShinyRate.Click += new System.EventHandler(this.B_ShinyRate_Click);
//
//
// Tab_CRO
//
//
this.Tab_CRO.Controls.Add(this.FLP_CRO);
this.Tab_CRO.Location = new System.Drawing.Point(4, 22);
this.Tab_CRO.Name = "Tab_CRO";
@@ -675,9 +705,9 @@ private void InitializeComponent()
this.Tab_CRO.TabIndex = 2;
this.Tab_CRO.Text = "CRO";
this.Tab_CRO.UseVisualStyleBackColor = true;
//
//
// FLP_CRO
//
//
this.FLP_CRO.Controls.Add(this.B_TypeChart);
this.FLP_CRO.Controls.Add(this.B_Starter);
this.FLP_CRO.Controls.Add(this.B_Gift);
@@ -688,9 +718,9 @@ private void InitializeComponent()
this.FLP_CRO.Padding = new System.Windows.Forms.Padding(3);
this.FLP_CRO.Size = new System.Drawing.Size(352, 154);
this.FLP_CRO.TabIndex = 1;
//
//
// B_TypeChart
//
//
this.B_TypeChart.Location = new System.Drawing.Point(6, 6);
this.B_TypeChart.Name = "B_TypeChart";
this.B_TypeChart.Size = new System.Drawing.Size(100, 23);
@@ -698,9 +728,9 @@ private void InitializeComponent()
this.B_TypeChart.Text = "Type Chart";
this.B_TypeChart.UseVisualStyleBackColor = true;
this.B_TypeChart.Click += new System.EventHandler(this.B_TypeChart_Click);
//
//
// B_Starter
//
//
this.B_Starter.Location = new System.Drawing.Point(112, 6);
this.B_Starter.Name = "B_Starter";
this.B_Starter.Size = new System.Drawing.Size(100, 23);
@@ -708,9 +738,9 @@ private void InitializeComponent()
this.B_Starter.Text = "Starter Pokémon";
this.B_Starter.UseVisualStyleBackColor = true;
this.B_Starter.Click += new System.EventHandler(this.B_Starter_Click);
//
//
// B_Gift
//
//
this.B_Gift.Location = new System.Drawing.Point(218, 6);
this.B_Gift.Name = "B_Gift";
this.B_Gift.Size = new System.Drawing.Size(100, 23);
@@ -718,9 +748,9 @@ private void InitializeComponent()
this.B_Gift.Text = "Gift Pokémon";
this.B_Gift.UseVisualStyleBackColor = true;
this.B_Gift.Click += new System.EventHandler(this.B_Gift_Click);
//
//
// B_Static
//
//
this.B_Static.Location = new System.Drawing.Point(6, 35);
this.B_Static.Name = "B_Static";
this.B_Static.Size = new System.Drawing.Size(100, 23);
@@ -728,9 +758,9 @@ private void InitializeComponent()
this.B_Static.Text = "Static Encounters";
this.B_Static.UseVisualStyleBackColor = true;
this.B_Static.Click += new System.EventHandler(this.B_Static_Click);
//
//
// Tab_Output
//
//
this.Tab_Output.Controls.Add(this.RTB_Status);
this.Tab_Output.Location = new System.Drawing.Point(4, 22);
this.Tab_Output.Name = "Tab_Output";
@@ -738,17 +768,24 @@ private void InitializeComponent()
this.Tab_Output.TabIndex = 3;
this.Tab_Output.Text = "Output";
this.Tab_Output.UseVisualStyleBackColor = true;
//
//
// L_Status
//
//
this.L_Status.Location = new System.Drawing.Point(203, 37);
this.L_Status.Name = "L_Status";
this.L_Status.Size = new System.Drawing.Size(163, 20);
this.L_Status.TabIndex = 14;
this.L_Status.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
//
// Menu_Extract_3DS
//
this.Menu_Extract_3DS.Name = "Menu_Extract_3DS";
this.Menu_Extract_3DS.Size = new System.Drawing.Size(180, 22);
this.Menu_Extract_3DS.Text = ".3DS";
this.Menu_Extract_3DS.Click += new System.EventHandler(this.B_Extract3DS_Click);
//
// Main
//
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(384, 252);
@@ -845,5 +882,9 @@ private void InitializeComponent()
private System.Windows.Forms.Button B_TM;
private System.Windows.Forms.ToolStripMenuItem randomizationToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem setInt32SeedToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem Menu_Extract;
private System.Windows.Forms.ToolStripMenuItem Menu_Extract_CXI;
private System.Windows.Forms.ToolStripMenuItem Menu_Trimmed3DS;
private System.Windows.Forms.ToolStripMenuItem Menu_Extract_3DS;
}
}

View File

@@ -234,6 +234,8 @@ private void openQuick(string path)
Menu_Patch.Enabled = RomFSPath != null && ExeFSPath != null;
Menu_3DS.Enabled =
ExHeaderPath != null && RomFSPath != null && ExeFSPath != null;
Menu_Trimmed3DS.Enabled =
ExHeaderPath != null && RomFSPath != null && ExeFSPath != null;
// Change L_Game if RomFS and ExeFS exists to a better descriptor
SMDH = ExeFSPath != null ? File.Exists(Path.Combine(ExeFSPath, "icon.bin")) ? new SMDH(Path.Combine(ExeFSPath, "icon.bin")) : null : null;
@@ -249,6 +251,84 @@ private void openQuick(string path)
}
}
private void B_ExtractCXI_Click(object sender, EventArgs e)
{
if (WinFormsUtil.Prompt(
MessageBoxButtons.OKCancel,
"Extracting a CXI requires multiple GB of disc space and takes some time to complete.",
"If you want to continue, press OK to select your CXI and then select your output directory. For best results, make sure the output directory is an empty directory.") == DialogResult.OK)
{
string inputCXI;
OpenFileDialog ofd = new OpenFileDialog();
ofd.Title = "Select CXI";
ofd.Filter = "CXI files (*.cxi)|*.cxi";
if (ofd.ShowDialog() == DialogResult.OK)
inputCXI = ofd.FileName;
else
return;
FolderBrowserDialog fbd = new FolderBrowserDialog();
DialogResult result = fbd.ShowDialog();
if (result == DialogResult.OK)
extractNCCH(inputCXI, fbd.SelectedPath);
}
}
private void B_Extract3DS_Click(object sender, EventArgs e)
{
if (WinFormsUtil.Prompt(
MessageBoxButtons.OKCancel,
"Extracting a 3DS file requires multiple GB of disc space and takes some time to complete.",
"If you want to continue, press OK to select your CXI and then select your output directory. For best results, make sure the output directory is an empty directory.") == DialogResult.OK)
{
string input3DS;
OpenFileDialog ofd = new OpenFileDialog();
ofd.Title = "Select 3DS";
ofd.Filter = "3DS files (*.3ds)|*.3ds";
if (ofd.ShowDialog() == DialogResult.OK)
input3DS = ofd.FileName;
else
return;
FolderBrowserDialog fbd = new FolderBrowserDialog();
DialogResult result = fbd.ShowDialog();
if (result == DialogResult.OK)
extractNCSD(input3DS, fbd.SelectedPath);
}
}
private void extractNCCH(string ncchPath, string outputDirectory)
{
if (!File.Exists(ncchPath))
return;
NCCH ncch = new NCCH();
new Thread(() =>
{
threads++;
ncch.ExtractNCCHFromFile(ncchPath, outputDirectory, RTB_Status, pBar1);
threads--;
WinFormsUtil.Prompt(MessageBoxButtons.OK, "Extraction complete!");
}).Start();
}
private void extractNCSD(string ncsdPath, string outputDirectory)
{
if (!File.Exists(ncsdPath))
return;
NCSD ncsd = new NCSD();
new Thread(() =>
{
threads++;
ncsd.ExtractFilesFromNCSD(ncsdPath, outputDirectory, RTB_Status, pBar1);
threads--;
WinFormsUtil.Prompt(MessageBoxButtons.OK, "Extraction complete!");
}).Start();
}
private void ToggleSubEditors()
{
// Hide all buttons
@@ -1140,16 +1220,9 @@ private void B_Static_Click(object sender, EventArgs e)
new StaticEncounterEditor6().ShowDialog();
}
// 3DS Building
private void B_Rebuild3DS_Click(object sender, EventArgs e)
// CXI Building
private void B_RebuildTrimmed3DS_Click(object sender, EventArgs e)
{
// Ensure that the romfs paths are valid
string[] files = Directory.GetFiles(TB_Path.Text, "*", SearchOption.AllDirectories);
if (!Config.IsRebuildable(files.Length))
{
WinFormsUtil.Error("RomFS file count does not match the default game file count.");
return;
}
if (threadActive())
return;
@@ -1166,8 +1239,33 @@ private void B_Rebuild3DS_Click(object sender, EventArgs e)
{
threads++;
Exheader exh = new Exheader(ExHeaderPath);
CTRUtil.buildROM(true, "Nintendo", ExeFSPath, RomFSPath, ExHeaderPath, exh.GetSerial(), path, pBar1,
RTB_Status);
CTRUtil.buildROM(true, "Nintendo", ExeFSPath, RomFSPath, ExHeaderPath, exh.GetSerial(), path,
true, pBar1, RTB_Status);
threads--;
}).Start();
}
// 3DS Building
private void B_Rebuild3DS_Click(object sender, EventArgs e)
{
if (threadActive())
return;
SaveFileDialog sfd = new SaveFileDialog
{
FileName = "newROM.3ds",
Filter = "Binary File|*.*"
};
if (sfd.ShowDialog() != DialogResult.OK)
return;
string path = sfd.FileName;
new Thread(() =>
{
threads++;
Exheader exh = new Exheader(ExHeaderPath);
CTRUtil.buildROM(true, "Nintendo", ExeFSPath, RomFSPath, ExHeaderPath, exh.GetSerial(), path,
false, pBar1, RTB_Status);
threads--;
}).Start();
}