mirror of
https://github.com/kwsch/pk3DS.git
synced 2026-10-02 05:46:47 -05:00
Refactor to add in 3ds rebuilding code
Big thanks to SciresM for writing the IO code from 3DS-Builder. Improved a bit to make use of static methods (no more void methods with no inputs!)
This commit is contained in:
97
pk3DS/3DS/AES.cs
Normal file
97
pk3DS/3DS/AES.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace CTR
|
||||
{
|
||||
public class AesCtr
|
||||
{
|
||||
private AesManaged Aes = new AesManaged();
|
||||
private ICryptoTransform Encryptor;
|
||||
private AesCounter Counter;
|
||||
|
||||
public AesCtr(byte[] key, byte[] iv)
|
||||
{
|
||||
Aes.Key = key;
|
||||
Aes.Mode = CipherMode.ECB;
|
||||
Aes.Padding = PaddingMode.None;
|
||||
Counter = new AesCounter(iv);
|
||||
Encryptor = Aes.CreateEncryptor();
|
||||
}
|
||||
|
||||
public AesCtr(byte[] key, ulong PartitionID, ulong InitialCount)
|
||||
{
|
||||
Aes.Key = key;
|
||||
Aes.Mode = CipherMode.ECB;
|
||||
Aes.Padding = PaddingMode.None;
|
||||
Counter = new AesCounter(PartitionID, InitialCount);
|
||||
Encryptor = Aes.CreateEncryptor();
|
||||
}
|
||||
|
||||
public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
|
||||
{
|
||||
int BlockLength;
|
||||
for (int i = 0; i < inputCount; i += BlockLength)
|
||||
{
|
||||
BlockLength = inputCount - i > AesCounter.BufferSize ? AesCounter.BufferSize : inputCount - i;
|
||||
Encryptor.TransformBlock(Counter.ManageBufferCounters(BlockLength), 0, BlockLength, outputBuffer, outputOffset + i);
|
||||
for (int BlockWalker = i; BlockWalker < (i + BlockLength); BlockWalker += 8)
|
||||
{
|
||||
Array.Copy(BitConverter.GetBytes(BitConverter.ToInt64(outputBuffer, outputOffset + BlockWalker) ^ BitConverter.ToInt64(inputBuffer, inputOffset + BlockWalker)), 0, outputBuffer, outputOffset + BlockWalker, 8);
|
||||
}
|
||||
}
|
||||
return inputCount;
|
||||
}
|
||||
}
|
||||
public class AesCounter
|
||||
{
|
||||
public const int BufferSize = 0x400000; //4 MB Buffer
|
||||
private byte[] Counter = new byte[0x10];
|
||||
private byte[] Buffer = new byte[BufferSize];
|
||||
|
||||
public AesCounter(ulong high, ulong low)
|
||||
{
|
||||
Array.Copy(BitConverter.GetBytes(high).Reverse().ToArray(), Counter, 0x8);
|
||||
Array.Copy(BitConverter.GetBytes(low).Reverse().ToArray(), 0, Counter, 0x8, 0x8);
|
||||
}
|
||||
|
||||
public AesCounter(byte[] iv)
|
||||
{
|
||||
Array.Copy(BitConverter.GetBytes(BitConverter.ToUInt64(iv, 0)).Reverse().ToArray(), Counter, 0x10);
|
||||
}
|
||||
|
||||
public void Increment()
|
||||
{
|
||||
for (int i = Counter.Length - 1; i >= 0; i--)
|
||||
{
|
||||
if ((++Counter[i]) != 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] ManageBufferCounters(int size)
|
||||
{
|
||||
for (int i = 0; i < size; i += 0x10)
|
||||
{
|
||||
Array.Copy(Counter, 0, Buffer, i, 0x10);
|
||||
Increment();
|
||||
}
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
public ulong SwapBytes(ulong value)
|
||||
{
|
||||
ulong uvalue = value;
|
||||
ulong swapped =
|
||||
((0x00000000000000FF) & (uvalue >> 56)
|
||||
| (0x000000000000FF00) & (uvalue >> 40)
|
||||
| (0x0000000000FF0000) & (uvalue >> 24)
|
||||
| (0x00000000FF000000) & (uvalue >> 8)
|
||||
| (0x000000FF00000000) & (uvalue << 8)
|
||||
| (0x0000FF0000000000) & (uvalue << 24)
|
||||
| (0x00FF000000000000) & (uvalue << 40)
|
||||
| (0xFF00000000000000) & (uvalue << 56));
|
||||
return swapped;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace blz
|
||||
namespace BLZ
|
||||
{
|
||||
public class BLZCoder
|
||||
{
|
||||
344
pk3DS/3DS/CTR.cs
Normal file
344
pk3DS/3DS/CTR.cs
Normal file
@@ -0,0 +1,344 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using pk3DS.Properties;
|
||||
|
||||
namespace CTR
|
||||
{
|
||||
public class CTR
|
||||
{
|
||||
public const uint MEDIA_UNIT_SIZE = 0x200;
|
||||
|
||||
// Main wrapper that assembles the ROM based on the following specifications:
|
||||
internal 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)
|
||||
{
|
||||
PB_Show = PB_Show ?? new ProgressBar();
|
||||
TB_Progress = TB_Progress ?? new RichTextBox();
|
||||
|
||||
// Sanity check the input files.
|
||||
if (!(File.Exists(EXEFS_PATH) && File.Exists(ROMFS_PATH) && File.Exists(EXHEADER_PATH))) return false;
|
||||
|
||||
var NCCH = setNCCH(EXEFS_PATH, ROMFS_PATH, EXHEADER_PATH, SERIAL_TEXT, LOGO_NAME, PB_Show, TB_Progress);
|
||||
var NCSD = setNCSD(NCCH, Card2, PB_Show, TB_Progress);
|
||||
bool success = writeROM(NCSD, NCCH, SAVE_PATH, PB_Show, TB_Progress);
|
||||
return success;
|
||||
}
|
||||
|
||||
// Sub methods that drive the operation
|
||||
internal static NCCH setNCCH(string EXEFS_PATH, string ROMFS_PATH, string EXHEADER_PATH, string TB_Serial, string LOGO_NAME,
|
||||
ProgressBar PB_Show = null, RichTextBox TB_Progress = null)
|
||||
{
|
||||
PB_Show = PB_Show ?? new ProgressBar();
|
||||
TB_Progress = TB_Progress ?? new RichTextBox();
|
||||
SHA256Managed sha = new SHA256Managed();
|
||||
NCCH Content = new NCCH();
|
||||
updateTB(TB_Progress, "Adding Exheader...");
|
||||
Content.exheader = new Exheader(EXHEADER_PATH);
|
||||
Content.plainregion = new byte[0]; //No plain region by default.
|
||||
if (Content.exheader.isPokemon())
|
||||
{
|
||||
updateTB(TB_Progress, "Detected Pokemon Game. Adding Plain Region...");
|
||||
if (Content.exheader.isXY())
|
||||
{
|
||||
Content.plainregion = (byte[])Resources.ResourceManager.GetObject("XY");
|
||||
}
|
||||
else if (Content.exheader.isORAS())
|
||||
{
|
||||
Content.plainregion = (byte[])Resources.ResourceManager.GetObject("ORAS");
|
||||
}
|
||||
}
|
||||
updateTB(TB_Progress, "Adding ExeFS...");
|
||||
Content.exefs = new ExeFS(EXEFS_PATH);
|
||||
updateTB(TB_Progress, "Adding RomFS...");
|
||||
Content.romfs = new RomFS(ROMFS_PATH);
|
||||
|
||||
updateTB(TB_Progress, "Adding Logo...");
|
||||
Content.logo = (byte[])Resources.ResourceManager.GetObject(LOGO_NAME);
|
||||
updateTB(TB_Progress, "Building NCCH Header...");
|
||||
ulong Len = 0x200; //NCCH Signature + NCCH Header
|
||||
Content.header = new NCCH.Header { Signature = new byte[0x100], Magic = 0x4843434E };
|
||||
Content.header.TitleId = Content.header.ProgramId = Content.exheader.TitleID;
|
||||
Content.header.MakerCode = 0x3130; //01
|
||||
Content.header.FormatVersion = 0x2; //Default
|
||||
Content.header.LogoHash = sha.ComputeHash(Content.logo);
|
||||
Content.header.ProductCode = Encoding.ASCII.GetBytes(TB_Serial);
|
||||
Array.Resize(ref Content.header.ProductCode, 0x10);
|
||||
Content.header.ExheaderHash = Content.exheader.GetSuperBlockHash();
|
||||
Content.header.ExheaderSize = (uint)(Content.exheader.Data.Length);
|
||||
Len += Content.header.ExheaderSize + (uint)Content.exheader.AccessDescriptor.Length;
|
||||
Content.header.Flags = new byte[0x8];
|
||||
//FLAGS
|
||||
Content.header.Flags[3] = 0; // Crypto: 0 = <7.x, 1=7.x;
|
||||
Content.header.Flags[4] = 1; // Content Platform: 1 = CTR;
|
||||
Content.header.Flags[5] = 0x3; // Content Type Bitflags: 1=Data, 2=Executable, 4=SysUpdate, 8=Manual, 0x10=Trial;
|
||||
Content.header.Flags[6] = 0; // MEDIA_UNIT_SIZE = 0x200*Math.Pow(2, Content.header.Flags[6]);
|
||||
Content.header.Flags[7] = 1; // FixedCrypto = 1, NoMountRomfs = 2; NoCrypto=4;
|
||||
Content.header.LogoOffset = (uint)(Len / MEDIA_UNIT_SIZE);
|
||||
Content.header.LogoSize = (uint)(Content.logo.Length / MEDIA_UNIT_SIZE);
|
||||
Len += (uint)Content.logo.Length;
|
||||
Content.header.PlainRegionOffset = (uint)((Content.plainregion.Length > 0) ? Len / MEDIA_UNIT_SIZE : 0);
|
||||
Content.header.PlainRegionSize = (uint)Content.plainregion.Length / MEDIA_UNIT_SIZE;
|
||||
Len += (uint)Content.plainregion.Length;
|
||||
Content.header.ExefsOffset = (uint)(Len / MEDIA_UNIT_SIZE);
|
||||
Content.header.ExefsSize = (uint)(Content.exefs.Data.Length / MEDIA_UNIT_SIZE);
|
||||
Content.header.ExefsSuperBlockSize = 0x200 / MEDIA_UNIT_SIZE; //Static 0x200 for exefs superblock
|
||||
Len += (uint)Content.exefs.Data.Length;
|
||||
Len = (uint)Align(Len, 0x1000); //Romfs Start is aligned to 0x1000
|
||||
Content.header.RomfsOffset = (uint)(Len / MEDIA_UNIT_SIZE);
|
||||
Content.header.RomfsSize = (uint)((new FileInfo(Content.romfs.FileName)).Length / MEDIA_UNIT_SIZE);
|
||||
Content.header.RomfsSuperBlockSize = Content.romfs.SuperBlockLen / MEDIA_UNIT_SIZE;
|
||||
Len += Content.header.RomfsSize * MEDIA_UNIT_SIZE;
|
||||
Content.header.ExefsHash = Content.exefs.SuperBlockHash;
|
||||
Content.header.RomfsHash = Content.romfs.SuperBlockHash;
|
||||
Content.header.Size = (uint)(Len / MEDIA_UNIT_SIZE);
|
||||
//Build the Header byte[].
|
||||
Content.header.BuildHeader();
|
||||
|
||||
return Content;
|
||||
}
|
||||
internal static NCSD setNCSD(NCCH Content, bool Card2,
|
||||
ProgressBar PB_Show = null, RichTextBox TB_Progress = null)
|
||||
{
|
||||
PB_Show = PB_Show ?? new ProgressBar();
|
||||
TB_Progress = TB_Progress ?? new RichTextBox();
|
||||
NCSD Rom = new NCSD { NCCH_Array = new List<NCCH>() };
|
||||
Rom.NCCH_Array.Add(Content);
|
||||
updateTB(TB_Progress, "Building NCSD Header...");
|
||||
Rom.Card2 = Card2;
|
||||
Rom.header = new NCSD.Header { Signature = new byte[0x100], Magic = 0x4453434E };
|
||||
ulong Length = 0x80 * 0x100000; // 128 MB
|
||||
while (Length <= Content.header.Size * MEDIA_UNIT_SIZE + 0x400000) //Extra 4 MB for potential save data
|
||||
{
|
||||
Length *= 2;
|
||||
}
|
||||
Rom.header.MediaSize = (uint)(Length / MEDIA_UNIT_SIZE);
|
||||
Rom.header.TitleId = Content.exheader.TitleID;
|
||||
Rom.header.OffsetSizeTable = new NCSD.NCCH_Meta[8];
|
||||
ulong OSOfs = 0x4000;
|
||||
for (int i = 0; i < Rom.header.OffsetSizeTable.Length; i++)
|
||||
{
|
||||
NCSD.NCCH_Meta ncchm = new NCSD.NCCH_Meta();
|
||||
if (i < Rom.NCCH_Array.Count)
|
||||
{
|
||||
ncchm.Offset = (uint)(OSOfs / MEDIA_UNIT_SIZE);
|
||||
ncchm.Size = Rom.NCCH_Array[i].header.Size;
|
||||
}
|
||||
else
|
||||
{
|
||||
ncchm.Offset = 0;
|
||||
ncchm.Size = 0;
|
||||
}
|
||||
Rom.header.OffsetSizeTable[i] = ncchm;
|
||||
OSOfs += ncchm.Size * MEDIA_UNIT_SIZE;
|
||||
}
|
||||
Rom.header.flags = new byte[0x8];
|
||||
Rom.header.flags[0] = 0; // 0-255 seconds of waiting for save writing.
|
||||
Rom.header.flags[3] = (byte)(Rom.Card2 ? 2 : 1); // Media Card Device: 1 = NOR Flash, 2 = None, 3 = BT
|
||||
Rom.header.flags[4] = 1; // Media Platform Index: 1 = CTR
|
||||
Rom.header.flags[5] = (byte)(Rom.Card2 ? 2 : 1); // Media Type Index: 0 = Inner Device, 1 = Card1, 2 = Card2, 3 = Extended Device
|
||||
Rom.header.flags[6] = 0; // Media Unit Size. Same as NCCH.
|
||||
Rom.header.flags[7] = 0; // Old Media Card Device.
|
||||
Rom.header.NCCHIdTable = new ulong[8];
|
||||
for (int i = 0; i < Rom.NCCH_Array.Count; i++)
|
||||
{
|
||||
Rom.header.NCCHIdTable[i] = Rom.NCCH_Array[i].header.TitleId;
|
||||
}
|
||||
Rom.cardinfoheader = new NCSD.CardInfoHeader
|
||||
{
|
||||
WritableAddress = (uint)(Rom.GetWritableAddress()),
|
||||
CardInfoBitmask = 0,
|
||||
CIN = new NCSD.CardInfoHeader.CardInfoNotes
|
||||
{
|
||||
Reserved0 = new byte[0xF8],
|
||||
MediaSizeUsed = OSOfs,
|
||||
Reserved1 = 0,
|
||||
Unknown = 0,
|
||||
Reserved2 = new byte[0xC],
|
||||
CVerTitleId = 0,
|
||||
CVerTitleVersion = 0,
|
||||
Reserved3 = new byte[0xCD6]
|
||||
},
|
||||
NCCH0TitleId = Rom.NCCH_Array[0].header.TitleId,
|
||||
Reserved0 = 0,
|
||||
InitialData = new byte[0x30]
|
||||
};
|
||||
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
|
||||
byte[] randbuffer = new byte[0x2C];
|
||||
rng.GetBytes(randbuffer);
|
||||
Array.Copy(randbuffer, Rom.cardinfoheader.InitialData, randbuffer.Length);
|
||||
Rom.cardinfoheader.Reserved1 = new byte[0xC0];
|
||||
Rom.cardinfoheader.NCCH0Header = new byte[0x100];
|
||||
Array.Copy(Rom.NCCH_Array[0].header.Data, 0x100, Rom.cardinfoheader.NCCH0Header, 0, 0x100);
|
||||
|
||||
Rom.BuildHeader();
|
||||
|
||||
//NCSD is Initialized
|
||||
return Rom;
|
||||
}
|
||||
internal static bool writeROM(NCSD Rom, NCCH Content, string SAVE_PATH,
|
||||
ProgressBar PB_Show = null, RichTextBox TB_Progress = null)
|
||||
{
|
||||
PB_Show = PB_Show ?? new ProgressBar();
|
||||
TB_Progress = TB_Progress ?? new RichTextBox();
|
||||
using (FileStream OutFileStream = new FileStream(SAVE_PATH, FileMode.Create))
|
||||
{
|
||||
updateTB(TB_Progress, "Writing NCSD Header...");
|
||||
OutFileStream.Write(Rom.Data, 0, Rom.Data.Length);
|
||||
updateTB(TB_Progress, "Writing NCCH...");
|
||||
OutFileStream.Write(Rom.NCCH_Array[0].header.Data, 0, Rom.NCCH_Array[0].header.Data.Length); //Write NCCH header
|
||||
//AES time.
|
||||
byte[] key = new byte[0x10]; //Fixed-Crypto key is all zero.
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
AesCtr aesctr = new AesCtr(key, Rom.NCCH_Array[0].header.ProgramId, ((ulong)(i + 1)) << 56); //CTR is ProgramID, section id<<88
|
||||
switch (i)
|
||||
{
|
||||
case 0: //Exheader + AccessDesc
|
||||
updateTB(TB_Progress, "Writing Exheader...");
|
||||
byte[] inEncExheader = new byte[Rom.NCCH_Array[0].exheader.Data.Length + Rom.NCCH_Array[0].exheader.AccessDescriptor.Length];
|
||||
byte[] outEncExheader = new byte[Rom.NCCH_Array[0].exheader.Data.Length + Rom.NCCH_Array[0].exheader.AccessDescriptor.Length];
|
||||
Array.Copy(Rom.NCCH_Array[0].exheader.Data, inEncExheader, Rom.NCCH_Array[0].exheader.Data.Length);
|
||||
Array.Copy(Rom.NCCH_Array[0].exheader.AccessDescriptor, 0, inEncExheader, Rom.NCCH_Array[0].exheader.Data.Length, Rom.NCCH_Array[0].exheader.AccessDescriptor.Length);
|
||||
aesctr.TransformBlock(inEncExheader, 0, inEncExheader.Length, outEncExheader, 0);
|
||||
OutFileStream.Write(outEncExheader, 0, outEncExheader.Length); // Write Exheader
|
||||
break;
|
||||
case 1: //Exefs
|
||||
updateTB(TB_Progress, "Writing Exefs...");
|
||||
OutFileStream.Seek(0x4000 + Rom.NCCH_Array[0].header.ExefsOffset * MEDIA_UNIT_SIZE, SeekOrigin.Begin);
|
||||
byte[] OutExefs = new byte[Rom.NCCH_Array[0].exefs.Data.Length];
|
||||
aesctr.TransformBlock(Rom.NCCH_Array[0].exefs.Data, 0, Rom.NCCH_Array[0].exefs.Data.Length, OutExefs, 0);
|
||||
OutFileStream.Write(OutExefs, 0, OutExefs.Length);
|
||||
break;
|
||||
case 2: //Romfs
|
||||
updateTB(TB_Progress, "Writing Romfs...");
|
||||
OutFileStream.Seek(0x4000 + Rom.NCCH_Array[0].header.RomfsOffset * MEDIA_UNIT_SIZE, SeekOrigin.Begin);
|
||||
using (FileStream InFileStream = new FileStream(Rom.NCCH_Array[0].romfs.FileName, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
uint BUFFER_SIZE = 0;
|
||||
ulong RomfsLen = Rom.NCCH_Array[0].header.RomfsSize * MEDIA_UNIT_SIZE;
|
||||
PB_Show.Invoke((Action)(() =>
|
||||
{
|
||||
PB_Show.Minimum = 0;
|
||||
PB_Show.Maximum = (int)(RomfsLen / 0x400000);
|
||||
PB_Show.Value = 0;
|
||||
PB_Show.Step = 1;
|
||||
}));
|
||||
for (ulong j = 0; j < (RomfsLen); j += BUFFER_SIZE)
|
||||
{
|
||||
BUFFER_SIZE = (RomfsLen - j) > 0x400000 ? 0x400000 : (uint)(RomfsLen - j);
|
||||
byte[] buf = new byte[BUFFER_SIZE];
|
||||
byte[] outbuf = new byte[BUFFER_SIZE];
|
||||
InFileStream.Read(buf, 0, (int)BUFFER_SIZE);
|
||||
aesctr.TransformBlock(buf, 0, (int)BUFFER_SIZE, outbuf, 0);
|
||||
OutFileStream.Write(outbuf, 0, (int)BUFFER_SIZE);
|
||||
PB_Show.Invoke((Action)(PB_Show.PerformStep));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
updateTB(TB_Progress, "Writing Logo...");
|
||||
OutFileStream.Seek(0x4000 + Rom.NCCH_Array[0].header.LogoOffset * MEDIA_UNIT_SIZE, SeekOrigin.Begin);
|
||||
OutFileStream.Write(Rom.NCCH_Array[0].logo, 0, Rom.NCCH_Array[0].logo.Length);
|
||||
if (Rom.NCCH_Array[0].plainregion.Length > 0)
|
||||
{
|
||||
updateTB(TB_Progress, "Writing Plain Region...");
|
||||
OutFileStream.Seek(0x4000 + Rom.NCCH_Array[0].header.PlainRegionOffset * MEDIA_UNIT_SIZE, SeekOrigin.Begin);
|
||||
OutFileStream.Write(Rom.NCCH_Array[0].plainregion, 0, Rom.NCCH_Array[0].plainregion.Length);
|
||||
}
|
||||
|
||||
//NCSD Padding
|
||||
OutFileStream.Seek(Rom.header.OffsetSizeTable[Rom.NCCH_Array.Count - 1].Offset * MEDIA_UNIT_SIZE + Rom.header.OffsetSizeTable[Rom.NCCH_Array.Count - 1].Size * MEDIA_UNIT_SIZE, SeekOrigin.Begin);
|
||||
ulong TotalLen = Rom.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);
|
||||
}
|
||||
}
|
||||
|
||||
//Delete Temporary Romfs File
|
||||
File.Delete(Content.romfs.FileName);
|
||||
|
||||
updateTB(TB_Progress, "Done!");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Utility
|
||||
internal static bool isValid(string exeFS, string romFS, string exeheader, string path, string serial, bool Card2)
|
||||
{
|
||||
bool isSerialValid = true;
|
||||
if (serial.Length == 10)
|
||||
{
|
||||
string[] subs = serial.Split('-');
|
||||
if (subs.Length != 3)
|
||||
isSerialValid = false;
|
||||
else
|
||||
{
|
||||
if (subs[0].Length != 3 || subs[1].Length != 1 || subs[2].Length != 4)
|
||||
isSerialValid = false;
|
||||
else if (subs[0] != "CTR" && subs[0] != "KTR")
|
||||
isSerialValid = false;
|
||||
else if (subs[1] != "P" && subs[1] != "N" && subs[2] != "U")
|
||||
isSerialValid = false;
|
||||
else
|
||||
{
|
||||
foreach (char c in subs[2].Where(c => !Char.IsLetterOrDigit(c)))
|
||||
isSerialValid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
isSerialValid = false;
|
||||
}
|
||||
if (exeFS == string.Empty
|
||||
|| romFS == string.Empty
|
||||
|| exeheader == string.Empty
|
||||
|| path == string.Empty
|
||||
|| !isSerialValid)
|
||||
return false;
|
||||
|
||||
Exheader exh = new Exheader(exeheader);
|
||||
return !exh.isPokemon() || Card2;
|
||||
}
|
||||
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 { }
|
||||
}
|
||||
internal static ulong Align(ulong input, ulong alignsize)
|
||||
{
|
||||
ulong output = input;
|
||||
if (output % alignsize != 0)
|
||||
{
|
||||
output += (alignsize - (output % alignsize));
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,9 @@
|
||||
using System.Text;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace pk3DS
|
||||
namespace CTR
|
||||
{
|
||||
public class ExeFS //A lot of this is lifted directly from pk3DS.
|
||||
public class ExeFS
|
||||
{
|
||||
public byte[] Data;
|
||||
public byte[] SuperBlockHash;
|
||||
94
pk3DS/3DS/Exheader.cs
Normal file
94
pk3DS/3DS/Exheader.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using pk3DS.Properties;
|
||||
|
||||
namespace CTR
|
||||
{
|
||||
public class Exheader
|
||||
{
|
||||
public byte[] Data;
|
||||
public byte[] AccessDescriptor;
|
||||
public ulong TitleID;
|
||||
|
||||
public Exheader(string EXHEADER_PATH)
|
||||
{
|
||||
Data = File.ReadAllBytes(EXHEADER_PATH);
|
||||
AccessDescriptor = Data.Skip(0x400).Take(0x400).ToArray();
|
||||
Data = Data.Take(0x400).ToArray();
|
||||
TitleID = BitConverter.ToUInt64(Data, 0x200);
|
||||
}
|
||||
|
||||
public byte[] GetSuperBlockHash()
|
||||
{
|
||||
SHA256Managed sha = new SHA256Managed();
|
||||
return sha.ComputeHash(Data, 0, 0x400);
|
||||
}
|
||||
public string GetSerial()
|
||||
{
|
||||
const string output = "CTR-P-";
|
||||
|
||||
var RecognizedGames = new Dictionary<ulong, string[]>();
|
||||
string[] lines = Resources.ResourceManager.GetString("_3dsgames").Split('\n').ToArray();
|
||||
foreach (string l in lines)
|
||||
{
|
||||
string[] vars = l.Split('\t').ToArray();
|
||||
ulong titleid = Convert.ToUInt64(vars[0], 16);
|
||||
if (RecognizedGames.ContainsKey(titleid))
|
||||
{
|
||||
char lc = RecognizedGames[titleid].ToArray()[0].ToCharArray()[3];
|
||||
char lc2 = vars[1].ToCharArray()[3];
|
||||
if (lc2 == 'A' || lc2 == 'E' || (lc2 == 'P' && lc == 'J')) //Prefer games in order US, PAL, JP
|
||||
{
|
||||
RecognizedGames[titleid] = vars.Skip(1).Take(2).ToArray();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RecognizedGames.Add(titleid, vars.Skip(1).Take(2).ToArray());
|
||||
}
|
||||
}
|
||||
return output + RecognizedGames[TitleID][0];
|
||||
}
|
||||
|
||||
public bool isPokemon()
|
||||
{
|
||||
return (isORAS() || isXY());
|
||||
}
|
||||
public bool isORAS()
|
||||
{
|
||||
return (((TitleID & 0xFFFFFFFF) >> 8) == 0x11C5) || (((TitleID & 0xFFFFFFFF) >> 8) == 0x11C4);
|
||||
}
|
||||
public bool isXY()
|
||||
{
|
||||
return (((TitleID & 0xFFFFFFFF) >> 8) == 0x55D) || (((TitleID & 0xFFFFFFFF) >> 8) == 0x55E);
|
||||
}
|
||||
public string GetPokemonSerial()
|
||||
{
|
||||
if (!isPokemon())
|
||||
return "CTR-P-XXXX";
|
||||
string name = string.Empty;
|
||||
switch ((TitleID & 0xFFFFFFFF) >> 8)
|
||||
{
|
||||
case 0x11C5: //Alpha Sapphire
|
||||
name = "ECLA";
|
||||
break;
|
||||
case 0x11C4: //Omega Ruby
|
||||
name = "ECRA";
|
||||
break;
|
||||
case 0x55D: //X
|
||||
name = "EKJA";
|
||||
break;
|
||||
case 0x55E: //Y
|
||||
name = "EK2A";
|
||||
break;
|
||||
default:
|
||||
name = "XXXX";
|
||||
break;
|
||||
}
|
||||
return "CTR-P-" + name;
|
||||
}
|
||||
}
|
||||
}
|
||||
78
pk3DS/3DS/NCCH.cs
Normal file
78
pk3DS/3DS/NCCH.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
|
||||
namespace CTR
|
||||
{
|
||||
public class NCCH
|
||||
{
|
||||
public Header header;
|
||||
public ExeFS exefs;
|
||||
public RomFS romfs;
|
||||
public Exheader exheader;
|
||||
public byte[] logo;
|
||||
public byte[] plainregion;
|
||||
public const uint MEDIA_UNIT_SIZE = 0x200;
|
||||
|
||||
public class Header
|
||||
{
|
||||
public byte[] Signature; //Size: 0x100
|
||||
public uint Magic;
|
||||
public uint Size;
|
||||
public ulong TitleId;
|
||||
public ushort MakerCode;
|
||||
public ushort FormatVersion;
|
||||
//public uint padding0;
|
||||
public ulong ProgramId;
|
||||
//public byte[0x10] padding1;
|
||||
public byte[] LogoHash; // Size: 0x20
|
||||
public byte[] ProductCode; // Size: 0x10
|
||||
public byte[] ExheaderHash; // Size: 0x20
|
||||
public uint ExheaderSize;
|
||||
//public uint padding2;
|
||||
public byte[] Flags; // Size: 8
|
||||
public uint PlainRegionOffset;
|
||||
public uint PlainRegionSize;
|
||||
public uint LogoOffset;
|
||||
public uint LogoSize;
|
||||
public uint ExefsOffset;
|
||||
public uint ExefsSize;
|
||||
public uint ExefsSuperBlockSize;
|
||||
//public uint padding4;
|
||||
public uint RomfsOffset;
|
||||
public uint RomfsSize;
|
||||
public uint RomfsSuperBlockSize;
|
||||
//public uint padding5;
|
||||
public byte[] ExefsHash; // Size: 0x20
|
||||
public byte[] RomfsHash; // Size: 0x20
|
||||
|
||||
public byte[] Data;
|
||||
|
||||
public void BuildHeader()
|
||||
{
|
||||
Data = new byte[0x200];
|
||||
Array.Copy(Signature, Data, 0x100);
|
||||
Array.Copy(BitConverter.GetBytes(Magic), 0, Data, 0x100, 4);
|
||||
Array.Copy(BitConverter.GetBytes(Size), 0, Data, 0x104, 4);
|
||||
Array.Copy(BitConverter.GetBytes(TitleId), 0, Data, 0x108, 8);
|
||||
Array.Copy(BitConverter.GetBytes(MakerCode), 0, Data, 0x110, 2);
|
||||
Array.Copy(BitConverter.GetBytes(FormatVersion), 0, Data, 0x112, 2);
|
||||
//4 Byte Padding
|
||||
Array.Copy(BitConverter.GetBytes(ProgramId), 0, Data, 0x118, 8);
|
||||
//0x10 Byte Padding
|
||||
Array.Copy(LogoHash, 0, Data, 0x130, 0x20);
|
||||
Array.Copy(ProductCode, 0, Data, 0x150, 0x10);
|
||||
Array.Copy(ExheaderHash, 0, Data, 0x160, 0x20);
|
||||
Array.Copy(BitConverter.GetBytes(ExheaderSize), 0, Data, 0x180, 4);
|
||||
//4 Byte Padding
|
||||
Array.Copy(Flags, 0, Data, 0x188, 0x8);
|
||||
uint ofs = 0x190;
|
||||
foreach (uint val in new uint[] { PlainRegionOffset, PlainRegionSize, LogoOffset, LogoSize, ExefsOffset, ExefsSize, ExefsSuperBlockSize, 0, RomfsOffset, RomfsSize, RomfsSuperBlockSize, 0 })
|
||||
{
|
||||
Array.Copy(BitConverter.GetBytes(val), 0, Data, ofs, 4);
|
||||
ofs += 4;
|
||||
}
|
||||
Array.Copy(ExefsHash, 0, Data, 0x1C0, 0x20);
|
||||
Array.Copy(RomfsHash, 0, Data, 0x1E0, 0x20);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
110
pk3DS/3DS/NCSD.cs
Normal file
110
pk3DS/3DS/NCSD.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace CTR
|
||||
{
|
||||
public class NCSD
|
||||
{
|
||||
public Header header;
|
||||
public CardInfoHeader cardinfoheader;
|
||||
public List<NCCH> NCCH_Array;
|
||||
public bool Card2;
|
||||
public byte[] Data;
|
||||
|
||||
public class Header
|
||||
{
|
||||
public byte[] Signature; //Size 0x100;
|
||||
public uint Magic;
|
||||
public uint MediaSize;
|
||||
public ulong TitleId;
|
||||
//public byte[] padding; //Size: 0x10
|
||||
public NCCH_Meta[] OffsetSizeTable; //Size: 8
|
||||
//public byte[] padding; //Size: 0x28
|
||||
public byte[] flags; //Size: 0x8
|
||||
public ulong[] NCCHIdTable; //Size: 0x8;
|
||||
//public byte[] Padding2; //Size: 0x30;
|
||||
}
|
||||
public class CardInfoHeader
|
||||
{
|
||||
public uint WritableAddress;
|
||||
public uint CardInfoBitmask;
|
||||
public CardInfoNotes CIN;
|
||||
public ulong NCCH0TitleId;
|
||||
public ulong Reserved0;
|
||||
public byte[] InitialData; // Size: 0x30
|
||||
public byte[] Reserved1; // Size: 0xC0
|
||||
public byte[] NCCH0Header; // Size: 0x100
|
||||
|
||||
public class CardInfoNotes
|
||||
{
|
||||
public byte[] Reserved0; // Size: 0xF8;
|
||||
public ulong MediaSizeUsed;
|
||||
public ulong Reserved1;
|
||||
public uint Unknown;
|
||||
public byte[] Reserved2; //Size: 0xC;
|
||||
public ulong CVerTitleId;
|
||||
public ushort CVerTitleVersion;
|
||||
public byte[] Reserved3; //Size: 0xCD6;
|
||||
}
|
||||
}
|
||||
public class NCCH_Meta
|
||||
{
|
||||
public uint Offset;
|
||||
public uint Size;
|
||||
}
|
||||
|
||||
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)
|
||||
: 0x00000000FFFFFFFF;
|
||||
}
|
||||
public void BuildHeader()
|
||||
{
|
||||
Data = new byte[0x4000];
|
||||
Array.Copy(header.Signature, Data, 0x100);
|
||||
Array.Copy(BitConverter.GetBytes(header.Magic), 0, Data, 0x100, 4);
|
||||
Array.Copy(BitConverter.GetBytes(header.MediaSize), 0, Data, 0x104, 4);
|
||||
Array.Copy(BitConverter.GetBytes(header.TitleId), 0, Data, 0x108, 8);
|
||||
for (int i = 0; i < header.OffsetSizeTable.Length; i++)
|
||||
{
|
||||
Array.Copy(BitConverter.GetBytes(header.OffsetSizeTable[i].Offset), 0, Data, 0x120 + 8 * i, 4);
|
||||
Array.Copy(BitConverter.GetBytes(header.OffsetSizeTable[i].Size), 0, Data, 0x124 + 8 * i, 4);
|
||||
}
|
||||
Array.Copy(header.flags, 0, Data, 0x188, header.flags.Length);
|
||||
for (int i = 0; i < header.NCCHIdTable.Length; i++)
|
||||
{
|
||||
Array.Copy(BitConverter.GetBytes(header.NCCHIdTable[i]), 0, Data, 0x190 + 8 * i, 8);
|
||||
}
|
||||
//CardInfoHeader
|
||||
Array.Copy(BitConverter.GetBytes(cardinfoheader.WritableAddress), 0, Data, 0x200, 4);
|
||||
Array.Copy(BitConverter.GetBytes(cardinfoheader.CardInfoBitmask), 0, Data, 0x204, 4);
|
||||
Array.Copy(cardinfoheader.CIN.Reserved0, 0, Data, 0x208, cardinfoheader.CIN.Reserved0.Length);
|
||||
Array.Copy(BitConverter.GetBytes(cardinfoheader.CIN.MediaSizeUsed), 0, Data, 0x300, 8);
|
||||
Array.Copy(BitConverter.GetBytes(cardinfoheader.CIN.Reserved1), 0, Data, 0x308, 8);
|
||||
Array.Copy(BitConverter.GetBytes(cardinfoheader.CIN.Unknown), 0, Data, 0x310, 4);
|
||||
Array.Copy(cardinfoheader.CIN.Reserved2, 0, Data, 0x314, cardinfoheader.CIN.Reserved2.Length);
|
||||
Array.Copy(BitConverter.GetBytes(cardinfoheader.CIN.CVerTitleId), 0, Data, 0x320, 8);
|
||||
Array.Copy(BitConverter.GetBytes(cardinfoheader.CIN.CVerTitleVersion), 0, Data, 0x328, 2);
|
||||
Array.Copy(cardinfoheader.CIN.Reserved3, 0, Data, 0x32A, cardinfoheader.CIN.Reserved3.Length);
|
||||
Array.Copy(BitConverter.GetBytes(cardinfoheader.NCCH0TitleId), 0, Data, 0x1000, 8);
|
||||
Array.Copy(BitConverter.GetBytes(cardinfoheader.Reserved0), 0, Data, 0x1008, 8);
|
||||
Array.Copy(cardinfoheader.InitialData, 0, Data, 0x1010, cardinfoheader.InitialData.Length);
|
||||
Array.Copy(cardinfoheader.Reserved1, 0, Data, 0x1040, cardinfoheader.Reserved1.Length);
|
||||
Array.Copy(cardinfoheader.NCCH0Header, 0, Data, 0x1100, cardinfoheader.NCCH0Header.Length);
|
||||
Array.Copy(Enumerable.Repeat((byte)0xFF, 0x2E00).ToArray(), 0, Data, 0x1200, 0x2E00);
|
||||
}
|
||||
internal static ulong Align(ulong input, ulong alignsize)
|
||||
{
|
||||
ulong output = input;
|
||||
if (output % alignsize != 0)
|
||||
{
|
||||
output += (alignsize - (output % alignsize));
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,11 @@
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace pk3DS
|
||||
namespace CTR
|
||||
{
|
||||
// Info acquisition
|
||||
public class RomFS
|
||||
{
|
||||
// Get Info
|
||||
public string FileName;
|
||||
public bool isTempFile;
|
||||
public byte[] SuperBlockHash;
|
||||
@@ -35,10 +35,8 @@ public RomFS(string fn)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// File operation
|
||||
public class RomFSTool
|
||||
{
|
||||
|
||||
// Build
|
||||
internal const int PADDING_ALIGN = 16;
|
||||
internal static string ROOT_DIR;
|
||||
internal const string TempFile = "tempRomFS.bin";
|
||||
@@ -77,7 +75,7 @@ internal static void BuildRomFS(string outfile, string infile, RichTextBox TB_Pr
|
||||
updateTB(TB_Progress, "Creating Layout...");
|
||||
for (int i = 0; i < FNT.NumFiles; i++)
|
||||
{
|
||||
In[i] = new LayoutManager.Input {FilePath = FNT.NameEntryTable[i].FullName, AlignmentSize = 0x10};
|
||||
In[i] = new LayoutManager.Input { FilePath = FNT.NameEntryTable[i].FullName, AlignmentSize = 0x10 };
|
||||
}
|
||||
LayoutManager.Output[] Out = LayoutManager.Create(In);
|
||||
for (int i = 0; i < Out.Length; i++)
|
||||
@@ -110,10 +108,10 @@ internal static ulong Align(ulong input, ulong alignsize)
|
||||
internal static void MakeRomFSData(RomfsFile[] RomFiles, MemoryStream metadata, RichTextBox TB_Progress = null, ProgressBar PB_Show = null)
|
||||
{
|
||||
updateTB(TB_Progress, "Computing IVFC Header Data...");
|
||||
IVFCInfo ivfc = new IVFCInfo {Levels = new IVFCLevel[3]};
|
||||
IVFCInfo ivfc = new IVFCInfo { Levels = new IVFCLevel[3] };
|
||||
for (int i = 0; i < ivfc.Levels.Length; i++)
|
||||
{
|
||||
ivfc.Levels[i] = new IVFCLevel {BlockSize = 0x1000};
|
||||
ivfc.Levels[i] = new IVFCLevel { BlockSize = 0x1000 };
|
||||
}
|
||||
ivfc.Levels[2].DataLength = RomfsFile.GetDataBlockLength(RomFiles, (ulong)metadata.Length);
|
||||
ivfc.Levels[1].DataLength = (Align(ivfc.Levels[2].DataLength, ivfc.Levels[2].BlockSize) / ivfc.Levels[2].BlockSize) * 0x20; //0x20 per SHA256 hash
|
||||
@@ -154,7 +152,7 @@ internal static void MakeRomFSData(RomfsFile[] RomFiles, MemoryStream metadata,
|
||||
if (PB_Show.InvokeRequired)
|
||||
PB_Show.Invoke((MethodInvoker)delegate { PB_Show.Minimum = 0; PB_Show.Step = 1; PB_Show.Value = 0; PB_Show.Maximum = RomFiles.Length; });
|
||||
else { PB_Show.Minimum = 0; PB_Show.Step = 1; PB_Show.Value = 0; PB_Show.Maximum = RomFiles.Length; }
|
||||
|
||||
|
||||
foreach (RomfsFile t in RomFiles)
|
||||
{
|
||||
OutFileStream.Seek(baseOfs + (long)t.Offset, SeekOrigin.Begin);
|
||||
@@ -181,9 +179,9 @@ internal static void MakeRomFSData(RomfsFile[] RomFiles, MemoryStream metadata,
|
||||
byte[] buffer = new byte[(int)ivfc.Levels[i].BlockSize];
|
||||
|
||||
if (PB_Show.InvokeRequired)
|
||||
PB_Show.Invoke((MethodInvoker)delegate { PB_Show.Minimum = 0; PB_Show.Step = 1; PB_Show.Value = 0; PB_Show.Maximum = (int)(ivfc.Levels[i].DataLength / ivfc.Levels[i].BlockSize); });
|
||||
PB_Show.Invoke((MethodInvoker)delegate { PB_Show.Minimum = 0; PB_Show.Step = 1; PB_Show.Value = 0; PB_Show.Maximum = (int)(ivfc.Levels[i].DataLength / ivfc.Levels[i].BlockSize); });
|
||||
else { PB_Show.Minimum = 0; PB_Show.Step = 1; PB_Show.Value = 0; PB_Show.Maximum = (int)(ivfc.Levels[i].DataLength / ivfc.Levels[i].BlockSize); }
|
||||
|
||||
|
||||
for (long ofs = 0; ofs < (long)ivfc.Levels[i].DataLength; ofs += ivfc.Levels[i].BlockSize)
|
||||
{
|
||||
OutFileStream.Seek(hOfs, SeekOrigin.Begin);
|
||||
@@ -227,7 +225,7 @@ internal static void MakeRomFSData(RomfsFile[] RomFiles, MemoryStream metadata,
|
||||
}
|
||||
updateTB(TB_Progress, "RomFS Super Block Hash: " + ByteArrayToString(SuperBlockHash));
|
||||
updateTB(TB_Progress, "Saving to destination...");
|
||||
|
||||
|
||||
if (File.Exists(OutFile)) File.Delete(OutFile);
|
||||
File.Move(TempFile, OutFile);
|
||||
}
|
||||
@@ -264,7 +262,7 @@ internal static void WriteBinary(string tempFile, string outFile, RichTextBox TB
|
||||
}
|
||||
}
|
||||
File.Delete(TempFile);
|
||||
Util.Alert("Wrote RomFS to path:", outFile);
|
||||
updateTB(TB_Progress, "Wrote RomFS to path:" + Environment.NewLine + outFile);
|
||||
}
|
||||
internal static string ByteArrayToString(IEnumerable<byte> input)
|
||||
{
|
||||
@@ -317,7 +315,7 @@ internal static void CalcRomfsSize(Romfs_MetaData MetaData)
|
||||
MetaData.M_DirHashTableEntry = GetHashTableEntryCount(MetaData.DirNum);
|
||||
MetaData.M_FileHashTableEntry = GetHashTableEntryCount(MetaData.FileNum);
|
||||
|
||||
uint MetaDataSize = (uint)Align((0x28 + MetaData.M_DirHashTableEntry * 4 + MetaData.M_DirTableLen + MetaData.M_FileHashTableEntry * 4 + MetaData.M_FileTableLen), PADDING_ALIGN);
|
||||
uint MetaDataSize = (uint)Align((0x28 + MetaData.M_DirHashTableEntry * 4 + MetaData.M_DirTableLen + MetaData.M_FileHashTableEntry * 4 + MetaData.M_FileTableLen), PADDING_ALIGN);
|
||||
for (int i = 0; i < MetaData.M_DirHashTableEntry; i++)
|
||||
MetaData.DirHashTable.Add(ROMFS_UNUSED_ENTRY);
|
||||
|
||||
@@ -484,14 +482,14 @@ internal static void AddDir(Romfs_MetaData MetaData, DirectoryInfo Dir, uint par
|
||||
if (!DoSubs)
|
||||
{
|
||||
uint CurrentDir = MetaData.DirTableLen;
|
||||
Romfs_DirEntry Entry = new Romfs_DirEntry {ParentOffset = parent};
|
||||
Romfs_DirEntry Entry = new Romfs_DirEntry { ParentOffset = parent };
|
||||
Entry.ChildOffset = Entry.HashKeyPointer = Entry.FileOffset = ROMFS_UNUSED_ENTRY;
|
||||
Entry.SiblingOffset = sibling;
|
||||
Entry.FullName = Dir.FullName;
|
||||
Entry.Name = (Entry.FullName == ROOT_DIR) ? "" : Dir.Name;
|
||||
Entry.Offset = CurrentDir;
|
||||
MetaData.DirTable.DirectoryTable.Add(Entry);
|
||||
MetaData.DirTableLen += (CurrentDir == 0) ? 0x18 : 0x18 + (uint) Align((ulong) Dir.Name.Length*2, 4);
|
||||
MetaData.DirTableLen += (CurrentDir == 0) ? 0x18 : 0x18 + (uint)Align((ulong)Dir.Name.Length * 2, 4);
|
||||
// int ParentIndex = GetRomfsDirEntry(MetaData, Dir.FullName);
|
||||
// uint poff = MetaData.DirTable.DirectoryTable[ParentIndex].Offset;
|
||||
}
|
||||
@@ -611,12 +609,11 @@ internal static void WriteMetaDataToStream(Romfs_MetaData MetaData, MemoryStream
|
||||
|
||||
//Padding
|
||||
while (stream.Position % PADDING_ALIGN != 0)
|
||||
stream.Write(new byte[PADDING_ALIGN - (stream.Position % 0x10)], 0, (int)(PADDING_ALIGN - (stream.Position % 0x10)));
|
||||
stream.Write(new byte[PADDING_ALIGN - (stream.Position % 0x10)], 0, (int)(PADDING_ALIGN - (stream.Position % 0x10)));
|
||||
//All Done.
|
||||
}
|
||||
|
||||
//GetRomfs[...]Entry Functions are all O(n)
|
||||
|
||||
internal static int GetRomfsDirEntry(Romfs_MetaData MetaData, string FullName)
|
||||
{
|
||||
for (int i = 0; i < MetaData.DirTable.DirectoryTable.Count; i++)
|
||||
@@ -20,7 +20,7 @@
|
||||
using System.Media;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using blz;
|
||||
using BLZ;
|
||||
|
||||
namespace pk3DS
|
||||
{
|
||||
@@ -271,7 +271,7 @@ private void rebuildRomFS(object sender, EventArgs e)
|
||||
updateStatus(Environment.NewLine + "Building RomFS binary. Please wait until the program finishes.");
|
||||
|
||||
threads++;
|
||||
RomFSTool.BuildRomFS(sfd.FileName, RomFSPath, RTB_Status, pBar1);
|
||||
CTR.RomFS.BuildRomFS(sfd.FileName, RomFSPath, RTB_Status, pBar1);
|
||||
threads--;
|
||||
|
||||
updateStatus("RomFS binary saved." + Environment.NewLine);
|
||||
@@ -490,7 +490,7 @@ private void rebuildExeFS(object sender, EventArgs e)
|
||||
threads++;
|
||||
new BLZCoder(new[] { "-en", files[file] }, pBar1);
|
||||
Util.Alert("Compressed!");
|
||||
ExeFS.set(Directory.GetFiles(ExeFSPath), sfd.FileName);
|
||||
CTR.ExeFS.set(Directory.GetFiles(ExeFSPath), sfd.FileName);
|
||||
threads--;
|
||||
}).Start();
|
||||
}
|
||||
|
||||
90
pk3DS/Properties/Resources.Designer.cs
generated
90
pk3DS/Properties/Resources.Designer.cs
generated
@@ -4540,6 +4540,26 @@ internal class Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to 0004000000030500 ASSJ スーパーストリートファイターIV 3D EDITION
|
||||
///0004000000030B00 ADAJ nintendogs + cats 柴 & Newフレンズ
|
||||
///0004000000031000 ADBJ nintendogs + cats フレンチ・ブル & Newフレンズ
|
||||
///0004000000031500 ADCJ nintendogs + cats トイ・プードル & Newフレンズ
|
||||
///0004000000031E00 A66J 戦国無双 Chronicle
|
||||
///0004000000032A00 ABBJ とびだす!パズルボブル 3D
|
||||
///0004000000032900 AEEJ ウイニングイレブン 3DSoccer
|
||||
///0004000000031F00 AKKJ レイトン教授と奇跡の仮面
|
||||
///0004000000034500 ARBJ ラビッツ タイム・トラベル
|
||||
///0004000000032800 ARRJ リッジレーサー3D
|
||||
///0004000000034400 ASCJ Tom Clancy's スプリンターセル 3D
|
||||
///0004000000033300 ASFJ ASPHALT [rest of string was truncated]";.
|
||||
/// </summary>
|
||||
internal static string _3dsgames {
|
||||
get {
|
||||
return ResourceManager.GetString("_3dsgames", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
@@ -10430,6 +10450,16 @@ internal class Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] Distributed {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("Distributed", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
@@ -10450,6 +10480,26 @@ internal class Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] iQue {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("iQue", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] iQueForSystem {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("iQueForSystem", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
@@ -14640,6 +14690,36 @@ internal class Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] Licensed {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("Licensed", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] Nintendo {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("Nintendo", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] ORAS {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("ORAS", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
@@ -14649,5 +14729,15 @@ internal class Resources {
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] XY {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("XY", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4495,4 +4495,28 @@
|
||||
<data name="helditem" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\img\item\helditem.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Distributed" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\romdata\bin\Logo\Distributed.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="iQue" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\romdata\bin\Logo\iQue.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="iQueForSystem" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\romdata\bin\Logo\iQueForSystem.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="Licensed" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\romdata\bin\Logo\Licensed.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="Nintendo" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\romdata\bin\Logo\Nintendo.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="ORAS" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\romdata\bin\PlainRegion\ORAS.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="XY" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\romdata\bin\PlainRegion\XY.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="_3dsgames" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\romdata\txt\3dsgames.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
|
||||
</data>
|
||||
</root>
|
||||
3576
pk3DS/Resources/romdata/txt/3dsgames.txt
Normal file
3576
pk3DS/Resources/romdata/txt/3dsgames.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -50,12 +50,17 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="3DS\AES.cs" />
|
||||
<Compile Include="3DS\Exheader.cs" />
|
||||
<Compile Include="3DS\NCCH.cs" />
|
||||
<Compile Include="3DS\NCSD.cs" />
|
||||
<Compile Include="ARCUtil.cs" />
|
||||
<Compile Include="BLZ.cs" />
|
||||
<Compile Include="ExeFS.cs" />
|
||||
<Compile Include="3DS\BLZ.cs" />
|
||||
<Compile Include="3DS\CTR.cs" />
|
||||
<Compile Include="3DS\ExeFS.cs" />
|
||||
<Compile Include="png2bclim.cs" />
|
||||
<Compile Include="Randomizer.cs" />
|
||||
<Compile Include="RomFS.cs" />
|
||||
<Compile Include="3DS\RomFS.cs" />
|
||||
<Compile Include="Subforms\TitleScreen.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
@@ -278,6 +283,13 @@
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<None Include="Resources\romdata\bin\Logo\Distributed.bin" />
|
||||
<None Include="Resources\romdata\bin\Logo\iQue.bin" />
|
||||
<None Include="Resources\romdata\bin\Logo\iQueForSystem.bin" />
|
||||
<None Include="Resources\romdata\bin\Logo\Licensed.bin" />
|
||||
<None Include="Resources\romdata\bin\Logo\Nintendo.bin" />
|
||||
<None Include="Resources\romdata\bin\PlainRegion\ORAS.bin" />
|
||||
<None Include="Resources\romdata\bin\PlainRegion\XY.bin" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Resources\img\Pokemon Sprites\2.png" />
|
||||
@@ -4656,6 +4668,9 @@
|
||||
<ItemGroup>
|
||||
<None Include="Resources\img\item\helditem.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Resources\romdata\txt\3dsgames.txt" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
|
||||
Reference in New Issue
Block a user