mirror of
https://github.com/Gericom/EveryFileExplorer.git
synced 2025-06-19 09:25:42 -04:00
766 lines
22 KiB
C#
766 lines
22 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.IO;
|
|
using LibEveryFileExplorer.Files;
|
|
using System.Drawing;
|
|
using System.Windows.Forms;
|
|
using LibEveryFileExplorer.Files.SimpleFileSystem;
|
|
using NDS.UI;
|
|
using System.Xml.Serialization;
|
|
using System.Xml;
|
|
using LibEveryFileExplorer.IO;
|
|
|
|
namespace NDS.Nitro
|
|
{
|
|
public class NDS : FileFormat<NDS.NDSIdentifier>, IViewable, IWriteable
|
|
{
|
|
public NDS() { }
|
|
public NDS(byte[] data)
|
|
{
|
|
EndianBinaryReader er = new EndianBinaryReader(new MemoryStream(data), Endianness.LittleEndian);
|
|
Header = new RomHeader(er);
|
|
|
|
er.BaseStream.Position = Header.MainRomOffset;
|
|
MainRom = er.ReadBytes((int)Header.MainSize);
|
|
if (er.ReadUInt32() == 0xDEC00621)//Nitro Footer!
|
|
{
|
|
er.BaseStream.Position -= 4;
|
|
StaticFooter = new NitroFooter(er);
|
|
}
|
|
|
|
er.BaseStream.Position = Header.SubRomOffset;
|
|
SubRom = er.ReadBytes((int)Header.SubSize);
|
|
|
|
er.BaseStream.Position = Header.FntOffset;
|
|
Fnt = new RomFNT(er);
|
|
|
|
er.BaseStream.Position = Header.MainOvtOffset;
|
|
MainOvt = new RomOVT[Header.MainOvtSize / 32];
|
|
for (int i = 0; i < Header.MainOvtSize / 32; i++) MainOvt[i] = new RomOVT(er);
|
|
|
|
er.BaseStream.Position = Header.SubOvtOffset;
|
|
SubOvt = new RomOVT[Header.SubOvtSize / 32];
|
|
for (int i = 0; i < Header.SubOvtSize / 32; i++) SubOvt[i] = new RomOVT(er);
|
|
|
|
er.BaseStream.Position = Header.FatOffset;
|
|
Fat = new FileAllocationEntry[Header.FatSize / 8];
|
|
for (int i = 0; i < Header.FatSize / 8; i++) Fat[i] = new FileAllocationEntry(er);
|
|
|
|
if (Header.BannerOffset != 0)
|
|
{
|
|
er.BaseStream.Position = Header.BannerOffset;
|
|
Banner = new RomBanner(er);
|
|
}
|
|
|
|
FileData = new byte[Header.FatSize / 8][];
|
|
for (int i = 0; i < Header.FatSize / 8; i++)
|
|
{
|
|
er.BaseStream.Position = Fat[i].fileTop;
|
|
FileData[i] = er.ReadBytes((int)Fat[i].fileSize);
|
|
}
|
|
//RSA Signature
|
|
if (Header.RomSize + 0x88 <= er.BaseStream.Length)
|
|
{
|
|
er.BaseStream.Position = Header.RomSize;
|
|
byte[] RSASig = er.ReadBytes(0x88);
|
|
for (int i = 0; i < RSASig.Length; i++)
|
|
{
|
|
//It could be padding, so check if there is something other than 0xFF or 0x00
|
|
if (RSASig[i] != 0xFF || RSASig[i] != 0x00)
|
|
{
|
|
RSASignature = RSASig;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
er.Close();
|
|
}
|
|
|
|
public Form GetDialog()
|
|
{
|
|
return new NDSViewer(this);
|
|
}
|
|
|
|
public string GetSaveDefaultFileFilter()
|
|
{
|
|
return "Nintendo DS Rom (*.nds)|*.nds";
|
|
}
|
|
|
|
public byte[] Write()
|
|
{
|
|
MemoryStream m = new MemoryStream();
|
|
EndianBinaryWriter er = new EndianBinaryWriter(m, Endianness.LittleEndian);
|
|
//Header
|
|
//skip the header, and write it afterwards
|
|
er.BaseStream.Position = 16384;
|
|
Header.HeaderSize = (uint)er.BaseStream.Position;
|
|
//MainRom
|
|
Header.MainRomOffset = (uint)er.BaseStream.Position;
|
|
Header.MainSize = (uint)MainRom.Length;
|
|
er.Write(MainRom, 0, MainRom.Length);
|
|
//Static Footer
|
|
if (StaticFooter != null) StaticFooter.Write(er);
|
|
if (MainOvt.Length != 0)
|
|
{
|
|
while ((er.BaseStream.Position % 0x200) != 0) er.Write((byte)0);
|
|
//Main Ovt
|
|
Header.MainOvtOffset = (uint)er.BaseStream.Position;
|
|
Header.MainOvtSize = (uint)MainOvt.Length * 0x20;
|
|
foreach (var v in MainOvt) v.Write(er);
|
|
foreach (var v in MainOvt)
|
|
{
|
|
while ((er.BaseStream.Position % 0x200) != 0) er.Write((byte)0);
|
|
Fat[v.FileId].fileTop = (uint)er.BaseStream.Position;
|
|
Fat[v.FileId].fileBottom = (uint)er.BaseStream.Position + (uint)FileData[v.FileId].Length;
|
|
er.Write(FileData[v.FileId], 0, FileData[v.FileId].Length);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Header.MainOvtOffset = 0;
|
|
Header.MainOvtSize = 0;
|
|
}
|
|
while ((er.BaseStream.Position % 0x200) != 0) er.Write((byte)0xFF);
|
|
//SubRom
|
|
Header.SubRomOffset = (uint)er.BaseStream.Position;
|
|
Header.SubSize = (uint)SubRom.Length;
|
|
er.Write(SubRom, 0, SubRom.Length);
|
|
//I assume this works the same as the main ovt?
|
|
if (SubOvt.Length != 0)
|
|
{
|
|
while ((er.BaseStream.Position % 0x200) != 0) er.Write((byte)0);
|
|
//Sub Ovt
|
|
Header.SubOvtOffset = (uint)er.BaseStream.Position;
|
|
Header.SubOvtSize = (uint)SubOvt.Length * 0x20;
|
|
foreach (var v in SubOvt) v.Write(er);
|
|
foreach (var v in SubOvt)
|
|
{
|
|
while ((er.BaseStream.Position % 0x200) != 0) er.Write((byte)0);
|
|
Fat[v.FileId].fileTop = (uint)er.BaseStream.Position;
|
|
Fat[v.FileId].fileBottom = (uint)er.BaseStream.Position + (uint)FileData[v.FileId].Length;
|
|
er.Write(FileData[v.FileId], 0, FileData[v.FileId].Length);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
Header.SubOvtOffset = 0;
|
|
Header.SubOvtSize = 0;
|
|
}
|
|
while ((er.BaseStream.Position % 0x200) != 0) er.Write((byte)0xFF);
|
|
//FNT
|
|
Header.FntOffset = (uint)er.BaseStream.Position;
|
|
Fnt.Write(er);
|
|
Header.FntSize = (uint)er.BaseStream.Position - Header.FntOffset;
|
|
while ((er.BaseStream.Position % 0x200) != 0) er.Write((byte)0xFF);
|
|
//FAT
|
|
Header.FatOffset = (uint)er.BaseStream.Position;
|
|
Header.FatSize = (uint)Fat.Length * 8;
|
|
//Skip the fat, and write it after writing the data itself
|
|
er.BaseStream.Position += Header.FatSize;
|
|
//Banner
|
|
if (Banner != null)
|
|
{
|
|
while ((er.BaseStream.Position % 0x200) != 0) er.Write((byte)0xFF);
|
|
Header.BannerOffset = (uint)er.BaseStream.Position;
|
|
Banner.Write(er);
|
|
}
|
|
else Header.BannerOffset = 0;
|
|
//Files
|
|
for (int i = (int)(Header.MainOvtSize / 32 + Header.SubOvtSize / 32); i < FileData.Length; i++)
|
|
{
|
|
while ((er.BaseStream.Position % 0x200) != 0) er.Write((byte)0xFF);
|
|
Fat[i].fileTop = (uint)er.BaseStream.Position;
|
|
Fat[i].fileBottom = (uint)er.BaseStream.Position + (uint)FileData[i].Length;
|
|
er.Write(FileData[i], 0, FileData[i].Length);
|
|
}
|
|
while ((er.BaseStream.Position % 4/*0x200*/) != 0) er.Write((byte)0);
|
|
long curpos = er.BaseStream.Position;
|
|
Header.RomSize = (uint)er.BaseStream.Position;
|
|
uint CapacitySize = Header.RomSize;
|
|
CapacitySize |= CapacitySize >> 16;
|
|
CapacitySize |= CapacitySize >> 8;
|
|
CapacitySize |= CapacitySize >> 4;
|
|
CapacitySize |= CapacitySize >> 2;
|
|
CapacitySize |= CapacitySize >> 1;
|
|
CapacitySize++;
|
|
if (CapacitySize <= 0x20000) CapacitySize = 0x20000;
|
|
int Capacity = -18;
|
|
while (CapacitySize != 0) { CapacitySize >>= 1; Capacity++; }
|
|
Header.DeviceSize = (byte)((Capacity < 0) ? 0 : Capacity);
|
|
//RSA!
|
|
if (RSASignature != null) er.Write(RSASignature, 0, 0x88);
|
|
//Fat
|
|
er.BaseStream.Position = Header.FatOffset;
|
|
foreach (var v in Fat) v.Write(er);
|
|
//Header
|
|
er.BaseStream.Position = 0;
|
|
Header.Write(er);
|
|
byte[] result = m.ToArray();
|
|
er.Close();
|
|
return result;
|
|
}
|
|
|
|
public RomHeader Header;
|
|
[Serializable]
|
|
public class RomHeader
|
|
{
|
|
public RomHeader() { }
|
|
public RomHeader(EndianBinaryReader er)
|
|
{
|
|
GameName = er.ReadString(Encoding.ASCII, 12).Replace("\0", "");
|
|
GameCode = er.ReadString(Encoding.ASCII, 4).Replace("\0", "");
|
|
MakerCode = er.ReadString(Encoding.ASCII, 2).Replace("\0", "");
|
|
ProductId = er.ReadByte();
|
|
DeviceType = er.ReadByte();
|
|
DeviceSize = er.ReadByte();
|
|
ReservedA = er.ReadBytes(9);
|
|
GameVersion = er.ReadByte();
|
|
Property = er.ReadByte();
|
|
|
|
MainRomOffset = er.ReadUInt32();
|
|
MainEntryAddress = er.ReadUInt32();
|
|
MainRamAddress = er.ReadUInt32();
|
|
MainSize = er.ReadUInt32();
|
|
SubRomOffset = er.ReadUInt32();
|
|
SubEntryAddress = er.ReadUInt32();
|
|
SubRamAddress = er.ReadUInt32();
|
|
SubSize = er.ReadUInt32();
|
|
|
|
FntOffset = er.ReadUInt32();
|
|
FntSize = er.ReadUInt32();
|
|
|
|
FatOffset = er.ReadUInt32();
|
|
FatSize = er.ReadUInt32();
|
|
|
|
MainOvtOffset = er.ReadUInt32();
|
|
MainOvtSize = er.ReadUInt32();
|
|
|
|
SubOvtOffset = er.ReadUInt32();
|
|
SubOvtSize = er.ReadUInt32();
|
|
|
|
RomParamA = er.ReadBytes(8);
|
|
BannerOffset = er.ReadUInt32();
|
|
SecureCRC = er.ReadUInt16();
|
|
RomParamB = er.ReadBytes(2);
|
|
|
|
MainAutoloadDone = er.ReadUInt32();
|
|
SubAutoloadDone = er.ReadUInt32();
|
|
|
|
RomParamC = er.ReadBytes(8);
|
|
RomSize = er.ReadUInt32();
|
|
HeaderSize = er.ReadUInt32();
|
|
ReservedB = er.ReadBytes(0x38);
|
|
|
|
LogoData = er.ReadBytes(0x9C);
|
|
LogoCRC = er.ReadUInt16();
|
|
HeaderCRC = er.ReadUInt16();
|
|
}
|
|
public void Write(EndianBinaryWriter er)
|
|
{
|
|
MemoryStream m = new MemoryStream();
|
|
EndianBinaryWriter ew = new EndianBinaryWriter(m, Endianness.LittleEndian);
|
|
ew.Write(GameName.PadRight(12, '\0'), Encoding.ASCII, false);
|
|
ew.Write(GameCode.PadRight(4, '\0'), Encoding.ASCII, false);
|
|
ew.Write(MakerCode.PadRight(2, '\0'), Encoding.ASCII, false);
|
|
ew.Write(ProductId);
|
|
ew.Write(DeviceType);
|
|
ew.Write(DeviceSize);
|
|
ew.Write(ReservedA, 0, 9);
|
|
ew.Write(GameVersion);
|
|
ew.Write(Property);
|
|
|
|
ew.Write(MainRomOffset);
|
|
ew.Write(MainEntryAddress);
|
|
ew.Write(MainRamAddress);
|
|
ew.Write(MainSize);
|
|
ew.Write(SubRomOffset);
|
|
ew.Write(SubEntryAddress);
|
|
ew.Write(SubRamAddress);
|
|
ew.Write(SubSize);
|
|
|
|
ew.Write(FntOffset);
|
|
ew.Write(FntSize);
|
|
|
|
ew.Write(FatOffset);
|
|
ew.Write(FatSize);
|
|
|
|
ew.Write(MainOvtOffset);
|
|
ew.Write(MainOvtSize);
|
|
|
|
ew.Write(SubOvtOffset);
|
|
ew.Write(SubOvtSize);
|
|
|
|
ew.Write(RomParamA, 0, 8);
|
|
ew.Write(BannerOffset);
|
|
ew.Write(SecureCRC);
|
|
ew.Write(RomParamB, 0, 2);
|
|
|
|
ew.Write(MainAutoloadDone);
|
|
ew.Write(SubAutoloadDone);
|
|
|
|
ew.Write(RomParamC, 0, 8);
|
|
ew.Write(RomSize);
|
|
ew.Write(HeaderSize);
|
|
ew.Write(ReservedB, 0, 0x38);
|
|
|
|
ew.Write(LogoData, 0, 0x9C);
|
|
LogoCRC = CRC16.GetCRC16(LogoData);
|
|
ew.Write(LogoCRC);
|
|
|
|
byte[] header = m.ToArray();
|
|
ew.Close();
|
|
|
|
HeaderCRC = CRC16.GetCRC16(header);
|
|
|
|
er.Write(header, 0, header.Length);
|
|
er.Write(HeaderCRC);
|
|
}
|
|
public String GameName;//12
|
|
public String GameCode;//4
|
|
public String MakerCode;//2
|
|
public Byte ProductId;
|
|
public Byte DeviceType;
|
|
public Byte DeviceSize;
|
|
public byte[] ReservedA;//9
|
|
public Byte GameVersion;
|
|
public Byte Property;
|
|
|
|
[XmlIgnore]
|
|
public UInt32 MainRomOffset;
|
|
public UInt32 MainEntryAddress;
|
|
public UInt32 MainRamAddress;
|
|
[XmlIgnore]
|
|
public UInt32 MainSize;
|
|
[XmlIgnore]
|
|
public UInt32 SubRomOffset;
|
|
public UInt32 SubEntryAddress;
|
|
public UInt32 SubRamAddress;
|
|
[XmlIgnore]
|
|
public UInt32 SubSize;
|
|
|
|
[XmlIgnore]
|
|
public UInt32 FntOffset;
|
|
[XmlIgnore]
|
|
public UInt32 FntSize;
|
|
|
|
[XmlIgnore]
|
|
public UInt32 FatOffset;
|
|
[XmlIgnore]
|
|
public UInt32 FatSize;
|
|
|
|
[XmlIgnore]
|
|
public UInt32 MainOvtOffset;
|
|
[XmlIgnore]
|
|
public UInt32 MainOvtSize;
|
|
|
|
[XmlIgnore]
|
|
public UInt32 SubOvtOffset;
|
|
[XmlIgnore]
|
|
public UInt32 SubOvtSize;
|
|
|
|
public byte[] RomParamA;//8
|
|
[XmlIgnore]
|
|
public UInt32 BannerOffset;
|
|
public UInt16 SecureCRC;
|
|
public byte[] RomParamB;//2
|
|
|
|
public UInt32 MainAutoloadDone;
|
|
public UInt32 SubAutoloadDone;
|
|
|
|
public byte[] RomParamC;//8
|
|
[XmlIgnore]
|
|
public UInt32 RomSize;
|
|
[XmlIgnore]
|
|
public UInt32 HeaderSize;
|
|
public byte[] ReservedB;//0x38
|
|
|
|
public byte[] LogoData;//0x9C
|
|
[XmlIgnore]
|
|
public UInt16 LogoCRC;
|
|
[XmlIgnore]
|
|
public UInt16 HeaderCRC;
|
|
}
|
|
public Byte[] MainRom;
|
|
public NitroFooter StaticFooter;
|
|
[Serializable]
|
|
public class NitroFooter
|
|
{
|
|
public NitroFooter() { }
|
|
public NitroFooter(EndianBinaryReader er)
|
|
{
|
|
NitroCode = er.ReadUInt32();
|
|
_start_ModuleParamsOffset = er.ReadUInt32();
|
|
Unknown = er.ReadUInt32();
|
|
}
|
|
public void Write(EndianBinaryWriter er)
|
|
{
|
|
er.Write(NitroCode);
|
|
er.Write(_start_ModuleParamsOffset);
|
|
er.Write(Unknown);
|
|
}
|
|
public UInt32 NitroCode;
|
|
public UInt32 _start_ModuleParamsOffset;
|
|
public UInt32 Unknown;
|
|
}
|
|
|
|
|
|
public Byte[] SubRom;
|
|
public RomFNT Fnt;
|
|
public class RomFNT
|
|
{
|
|
public RomFNT()
|
|
{
|
|
DirectoryTable = new List<DirectoryTableEntry>();
|
|
EntryNameTable = new List<EntryNameTableEntry>();
|
|
}
|
|
public RomFNT(EndianBinaryReader er)
|
|
{
|
|
DirectoryTable = new List<DirectoryTableEntry>();
|
|
DirectoryTable.Add(new DirectoryTableEntry(er));
|
|
for (int i = 0; i < DirectoryTable[0].dirParentID - 1; i++)
|
|
{
|
|
DirectoryTable.Add(new DirectoryTableEntry(er));
|
|
}
|
|
EntryNameTable = new List<EntryNameTableEntry>();
|
|
int dirend = 0;
|
|
while (dirend < DirectoryTable[0].dirParentID)
|
|
{
|
|
byte entryNameLength = er.ReadByte();
|
|
er.BaseStream.Position--;
|
|
if (entryNameLength == 0)
|
|
{
|
|
EntryNameTable.Add(new EntryNameTableEndOfDirectoryEntry(er));
|
|
dirend++;
|
|
}
|
|
else if (entryNameLength < 0x80) EntryNameTable.Add(new EntryNameTableFileEntry(er));
|
|
else EntryNameTable.Add(new EntryNameTableDirectoryEntry(er));
|
|
}
|
|
}
|
|
public void Write(EndianBinaryWriter er)
|
|
{
|
|
foreach (DirectoryTableEntry e in DirectoryTable) e.Write(er);
|
|
foreach (EntryNameTableEntry e in EntryNameTable) e.Write(er);
|
|
}
|
|
public List<DirectoryTableEntry> DirectoryTable;
|
|
public List<EntryNameTableEntry> EntryNameTable;
|
|
}
|
|
public RomOVT[] MainOvt;
|
|
public RomOVT[] SubOvt;
|
|
[Serializable]
|
|
public class RomOVT
|
|
{
|
|
[Flags]
|
|
public enum OVTFlag : byte
|
|
{
|
|
Compressed = 1,
|
|
AuthenticationCode = 2
|
|
}
|
|
public RomOVT() { }
|
|
public RomOVT(EndianBinaryReader er)
|
|
{
|
|
Id = er.ReadUInt32();
|
|
RamAddress = er.ReadUInt32();
|
|
RamSize = er.ReadUInt32();
|
|
BssSize = er.ReadUInt32();
|
|
SinitInit = er.ReadUInt32();
|
|
SinitInitEnd = er.ReadUInt32();
|
|
FileId = er.ReadUInt32();
|
|
UInt32 tmp = er.ReadUInt32();
|
|
Compressed = tmp & 0xFFFFFF;
|
|
Flag = (OVTFlag)(tmp >> 24);
|
|
}
|
|
public void Write(EndianBinaryWriter er)
|
|
{
|
|
er.Write(Id);
|
|
er.Write(RamAddress);
|
|
er.Write(RamSize);
|
|
er.Write(BssSize);
|
|
er.Write(SinitInit);
|
|
er.Write(SinitInitEnd);
|
|
er.Write(FileId);
|
|
er.Write((uint)((((uint)Flag) & 0xFF) << 24 | (Compressed & 0xFFFFFF)));
|
|
}
|
|
[XmlAttribute]
|
|
public UInt32 Id;
|
|
public UInt32 RamAddress;
|
|
public UInt32 RamSize;
|
|
public UInt32 BssSize;
|
|
public UInt32 SinitInit;
|
|
public UInt32 SinitInitEnd;
|
|
[XmlIgnore]
|
|
public UInt32 FileId;
|
|
|
|
public UInt32 Compressed;//:24;
|
|
[XmlAttribute]
|
|
public OVTFlag Flag;// :8;
|
|
}
|
|
public FileAllocationEntry[] Fat;
|
|
public RomBanner Banner;
|
|
[Serializable]
|
|
public class RomBanner
|
|
{
|
|
public RomBanner() { }
|
|
public RomBanner(EndianBinaryReader er)
|
|
{
|
|
Header = new BannerHeader(er);
|
|
Banner = new BannerV1(er);
|
|
}
|
|
public void Write(EndianBinaryWriter er)
|
|
{
|
|
Header.CRC16_v1 = Banner.GetCRC();
|
|
Header.Write(er);
|
|
Banner.Write(er);
|
|
}
|
|
public BannerHeader Header;
|
|
[Serializable]
|
|
public class BannerHeader
|
|
{
|
|
public BannerHeader() { }
|
|
public BannerHeader(EndianBinaryReader er)
|
|
{
|
|
Version = er.ReadByte();
|
|
ReservedA = er.ReadByte();
|
|
CRC16_v1 = er.ReadUInt16();
|
|
ReservedB = er.ReadBytes(28);
|
|
}
|
|
public void Write(EndianBinaryWriter er)
|
|
{
|
|
er.Write(Version);
|
|
er.Write(ReservedA);
|
|
er.Write(CRC16_v1);
|
|
er.Write(ReservedB, 0, 28);
|
|
}
|
|
public Byte Version;
|
|
public Byte ReservedA;
|
|
[XmlIgnore]
|
|
public UInt16 CRC16_v1;
|
|
public Byte[] ReservedB;//28
|
|
}
|
|
public BannerV1 Banner;
|
|
[Serializable]
|
|
public class BannerV1
|
|
{
|
|
public BannerV1() { }
|
|
public BannerV1(EndianBinaryReader er)
|
|
{
|
|
Image = er.ReadBytes(32 * 32 / 2);
|
|
Pltt = er.ReadBytes(16 * 2);
|
|
GameName = new string[6];
|
|
GameName[0] = er.ReadString(Encoding.Unicode, 128).Replace("\0", "");
|
|
GameName[1] = er.ReadString(Encoding.Unicode, 128).Replace("\0", "");
|
|
GameName[2] = er.ReadString(Encoding.Unicode, 128).Replace("\0", "");
|
|
GameName[3] = er.ReadString(Encoding.Unicode, 128).Replace("\0", "");
|
|
GameName[4] = er.ReadString(Encoding.Unicode, 128).Replace("\0", "");
|
|
GameName[5] = er.ReadString(Encoding.Unicode, 128).Replace("\0", "");
|
|
}
|
|
public void Write(EndianBinaryWriter er)
|
|
{
|
|
er.Write(Image, 0, 32 * 32 / 2);
|
|
er.Write(Pltt, 0, 16 * 2);
|
|
foreach (string s in GameName) er.Write(GameName[0].PadRight(128, '\0'), Encoding.Unicode, false);
|
|
}
|
|
public Byte[] Image;//32*32/2
|
|
public Byte[] Pltt;//16*2
|
|
|
|
[XmlIgnore]
|
|
public String[] GameName;//6, 128 chars (UTF16-LE)
|
|
|
|
[XmlElement("GameName")]
|
|
public String[] Base64GameName
|
|
{
|
|
get
|
|
{
|
|
String[] b = new String[6];
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
b[i] = Convert.ToBase64String(Encoding.Unicode.GetBytes(GameName[i]));
|
|
}
|
|
return b;
|
|
}
|
|
set
|
|
{
|
|
GameName = new string[6];
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
GameName[i] = Encoding.Unicode.GetString(Convert.FromBase64String(value[i]));
|
|
}
|
|
}
|
|
}
|
|
|
|
public ushort GetCRC()
|
|
{
|
|
byte[] Data = new byte[2080];
|
|
Array.Copy(Image, Data, 512);
|
|
Array.Copy(Pltt, 0, Data, 512, 32);
|
|
Array.Copy(Encoding.Unicode.GetBytes(GameName[0].PadRight(128, '\0')), 0, Data, 544, 256);
|
|
Array.Copy(Encoding.Unicode.GetBytes(GameName[1].PadRight(128, '\0')), 0, Data, 544 + 256, 256);
|
|
Array.Copy(Encoding.Unicode.GetBytes(GameName[2].PadRight(128, '\0')), 0, Data, 544 + 256 * 2, 256);
|
|
Array.Copy(Encoding.Unicode.GetBytes(GameName[3].PadRight(128, '\0')), 0, Data, 544 + 256 * 3, 256);
|
|
Array.Copy(Encoding.Unicode.GetBytes(GameName[4].PadRight(128, '\0')), 0, Data, 544 + 256 * 4, 256);
|
|
Array.Copy(Encoding.Unicode.GetBytes(GameName[5].PadRight(128, '\0')), 0, Data, 544 + 256 * 5, 256);
|
|
return CRC16.GetCRC16(Data);
|
|
}
|
|
|
|
public Bitmap GetIcon()
|
|
{
|
|
return GPU.Textures.ToBitmap(Image, Pltt, 0, 32, 32, GPU.Textures.ImageFormat.PLTT16, GPU.Textures.CharFormat.CHAR, true);
|
|
}
|
|
}
|
|
}
|
|
public Byte[][] FileData;
|
|
|
|
public Byte[] RSASignature;
|
|
|
|
public void FromFileSystem(SFSDirectory Root)
|
|
{
|
|
int did = 0;
|
|
int fid = MainOvt.Length + SubOvt.Length;
|
|
Root.UpdateIDs(ref did, ref fid);
|
|
//FATB.numFiles = (ushort)Root.TotalNrSubFiles;
|
|
//List<byte> Data = new List<byte>();
|
|
uint nrfiles = Root.TotalNrSubFiles;
|
|
FileAllocationEntry[] overlays = new FileAllocationEntry[MainOvt.Length + SubOvt.Length];
|
|
Array.Copy(Fat, overlays, MainOvt.Length + SubOvt.Length);
|
|
Fat = new FileAllocationEntry[(MainOvt.Length + SubOvt.Length) + nrfiles];
|
|
Array.Copy(overlays, Fat, MainOvt.Length + SubOvt.Length);
|
|
byte[][] overlaydata = new byte[MainOvt.Length + SubOvt.Length][];
|
|
Array.Copy(FileData, overlaydata, MainOvt.Length + SubOvt.Length);
|
|
FileData = new byte[(MainOvt.Length + SubOvt.Length) + nrfiles][];
|
|
Array.Copy(overlaydata, FileData, MainOvt.Length + SubOvt.Length);
|
|
//FATB.allocationTable.Clear();
|
|
for (ushort i = (ushort)(MainOvt.Length + SubOvt.Length); i < nrfiles + MainOvt.Length + SubOvt.Length; i++)
|
|
{
|
|
var f = Root.GetFileByID(i);
|
|
Fat[i] = new FileAllocationEntry(0, 0);
|
|
FileData[i] = f.Data;
|
|
}
|
|
Fnt.DirectoryTable.Clear();
|
|
NitroFSUtil.GenerateDirectoryTable(Fnt.DirectoryTable, Root);
|
|
uint offset2 = Fnt.DirectoryTable[0].dirEntryStart;
|
|
ushort fileId = (ushort)(MainOvt.Length + SubOvt.Length);//0;
|
|
Fnt.EntryNameTable.Clear();
|
|
NitroFSUtil.GenerateEntryNameTable(Fnt.DirectoryTable, Fnt.EntryNameTable, Root, ref offset2, ref fileId);
|
|
}
|
|
|
|
public SFSDirectory ToFileSystem()
|
|
{
|
|
bool treereconstruct = false;//Some programs do not write the Directory Table well, so sometimes I need to reconstruct the tree based on the fnt, which is bad!
|
|
List<SFSDirectory> dirs = new List<SFSDirectory>();
|
|
dirs.Add(new SFSDirectory("/", true));
|
|
dirs[0].DirectoryID = 0xF000;
|
|
|
|
uint nrdirs = Fnt.DirectoryTable[0].dirParentID;
|
|
for (int i = 1; i < nrdirs; i++)
|
|
{
|
|
dirs.Add(new SFSDirectory((ushort)(0xF000 + i)));
|
|
}
|
|
for (int i = 1; i < nrdirs; i++)
|
|
{
|
|
if (Fnt.DirectoryTable[i].dirParentID - 0xF000 == i)
|
|
{
|
|
treereconstruct = true;
|
|
foreach (var v in dirs)
|
|
{
|
|
v.Parent = null;
|
|
}
|
|
break;
|
|
}
|
|
dirs[i].Parent = dirs[Fnt.DirectoryTable[i].dirParentID - 0xF000];
|
|
}
|
|
if (!treereconstruct)
|
|
{
|
|
for (int i = 0; i < nrdirs; i++)
|
|
{
|
|
for (int j = 0; j < nrdirs; j++)
|
|
{
|
|
if (dirs[i] == dirs[j].Parent)
|
|
{
|
|
dirs[i].SubDirectories.Add(dirs[j]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
uint offset = nrdirs * 8;
|
|
ushort fileid = Fnt.DirectoryTable[0].dirEntryFileID;
|
|
SFSDirectory curdir = null;
|
|
foreach (EntryNameTableEntry e in Fnt.EntryNameTable)
|
|
{
|
|
for (int i = 0; i < nrdirs; i++)
|
|
{
|
|
if (offset == Fnt.DirectoryTable[i].dirEntryStart)
|
|
{
|
|
curdir = dirs[i];
|
|
break;
|
|
}
|
|
}
|
|
if (e is EntryNameTableEndOfDirectoryEntry)
|
|
{
|
|
curdir = null;
|
|
offset++;
|
|
}
|
|
else if (e is EntryNameTableFileEntry)
|
|
{
|
|
curdir.Files.Add(new SFSFile(fileid++, ((EntryNameTableFileEntry)e).entryName, curdir));
|
|
offset += 1u + e.entryNameLength;
|
|
}
|
|
else if (e is EntryNameTableDirectoryEntry)
|
|
{
|
|
if (treereconstruct)
|
|
{
|
|
dirs[((EntryNameTableDirectoryEntry)e).directoryID - 0xF000].Parent = curdir;
|
|
curdir.SubDirectories.Add(dirs[((EntryNameTableDirectoryEntry)e).directoryID - 0xF000]);
|
|
}
|
|
dirs[((EntryNameTableDirectoryEntry)e).directoryID - 0xF000].DirectoryName = ((EntryNameTableDirectoryEntry)e).entryName;
|
|
offset += 3u + (e.entryNameLength & 0x7Fu);
|
|
}
|
|
}
|
|
for (int i = (MainOvt.Length + SubOvt.Length); i < Fat.Length; i++)
|
|
{
|
|
//byte[] data = new byte[fat[i].fileSize];
|
|
//Array.Copy(FileData FIMG.fileImage, fat[i].fileTop, data, 0, data.Length);
|
|
dirs[0].GetFileByID((ushort)i).Data = FileData[i];//data;
|
|
}
|
|
return dirs[0];
|
|
}
|
|
|
|
public byte[] GetDecompressedARM9()
|
|
{
|
|
if (StaticFooter != null) return ARM9.Decompress(MainRom, StaticFooter._start_ModuleParamsOffset);
|
|
else return ARM9.Decompress(MainRom);
|
|
}
|
|
|
|
public class NDSIdentifier : FileFormatIdentifier
|
|
{
|
|
public override string GetCategory()
|
|
{
|
|
return Category_Roms;
|
|
}
|
|
|
|
public override string GetFileDescription()
|
|
{
|
|
return "Nintendo DS Rom (NDS)";
|
|
}
|
|
|
|
public override string GetFileFilter()
|
|
{
|
|
return "Nintendo DS Rom (*.nds, *.srl)|*.nds;*.srl";
|
|
}
|
|
|
|
public override Bitmap GetIcon()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public override FormatMatch IsFormat(EFEFile File)
|
|
{
|
|
if (File.Name.ToLower().EndsWith(".nds") || File.Name.ToLower().EndsWith(".srl")) return FormatMatch.Extension;
|
|
return FormatMatch.No;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|