NDS Editing and Saving!

This commit is contained in:
Gericom 2014-11-15 12:51:45 +01:00
parent c5a9972ee6
commit bca92666fe
5 changed files with 211 additions and 80 deletions

View File

@ -12,7 +12,7 @@ using NDS.Nitro;
namespace NDS
{
public class NDS : FileFormat<NDS.NDSIdentifier>, IViewable
public class NDS : FileFormat<NDS.NDSIdentifier>, IViewable, IWriteable
{
public NDS(byte[] data)
{
@ -54,6 +54,21 @@ namespace NDS
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();
}
@ -62,6 +77,11 @@ namespace NDS
return new NDSViewer(this);
}
public string GetSaveDefaultFileFilter()
{
return "Nintendo DS Rom (*.nds)|*.nds";
}
public byte[] Write()
{
MemoryStream m = new MemoryStream();
@ -76,9 +96,9 @@ namespace NDS
er.Write(MainRom, 0, MainRom.Length);
//Static Footer
if (StaticFooter != null) StaticFooter.Write(er);
while ((er.BaseStream.Position % 0x200) != 0) er.Write((byte)0);
if (MainOvt != null)
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;
@ -90,21 +110,21 @@ namespace NDS
Fat[v.FileId].fileBottom = (uint)er.BaseStream.Position + (uint)FileData[v.FileId].Length;
er.Write(FileData[v.FileId], 0, FileData[v.FileId].Length);
}
while ((er.BaseStream.Position % 0x200) != 0) er.Write((byte)0);
}
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);
while ((er.BaseStream.Position % 0x200) != 0) er.Write((byte)0);
//I assume this works the same as the main ovt?
if (SubOvt != null)
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;
@ -116,36 +136,58 @@ namespace NDS
Fat[v.FileId].fileBottom = (uint)er.BaseStream.Position + (uint)FileData[v.FileId].Length;
er.Write(FileData[v.FileId], 0, FileData[v.FileId].Length);
}
while ((er.BaseStream.Position % 0x200) != 0) er.Write((byte)0);
}
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)0);
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;
while ((er.BaseStream.Position % 0x200) != 0) er.Write((byte)0);
while ((er.BaseStream.Position % 0x200) != 0) er.Write((byte)0xFF);
//Banner
Header.BannerOffset = (uint)er.BaseStream.Position;
Banner.Write(er);
//Files
for (int i = (int)(Header.MainOvtSize / 32 + Header.SubOvtSize / 32); i < FileData.Length; i++)
{
while ((er.BaseStream.Position % 0x200) != 0) er.Write((byte)0);
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 % 0x200) != 0) er.Write((byte)0);
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;
@ -204,6 +246,66 @@ namespace NDS
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
@ -341,7 +443,7 @@ namespace NDS
er.Write(SinitInit);
er.Write(SinitInitEnd);
er.Write(FileId);
er.Write((uint)((((uint)Flag) & 0xFF) << 8 | (Compressed & 0xFFFFFF)));
er.Write((uint)((((uint)Flag) & 0xFF) << 24 | (Compressed & 0xFFFFFF)));
}
public UInt32 Id;
public UInt32 RamAddress;
@ -433,6 +535,38 @@ namespace NDS
}
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>();
FileAllocationEntry[] overlays = new FileAllocationEntry[MainOvt.Length + SubOvt.Length];
Array.Copy(Fat, overlays, MainOvt.Length + SubOvt.Length);
Fat = new FileAllocationEntry[(MainOvt.Length + SubOvt.Length) + Root.TotalNrSubFiles];
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) + Root.TotalNrSubFiles][];
Array.Copy(overlaydata, FileData, MainOvt.Length + SubOvt.Length);
//FATB.allocationTable.Clear();
for (ushort i = (ushort)(MainOvt.Length + SubOvt.Length); i < Root.TotalNrSubFiles + 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!
@ -505,7 +639,7 @@ namespace NDS
offset += 3u + (e.entryNameLength & 0x7Fu);
}
}
for (int i = (int)(Header.MainOvtSize / 32 + Header.SubOvtSize / 32); i < Header.FatSize / 8; i++)
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);

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using LibEveryFileExplorer.Files.SimpleFileSystem;
namespace NDS
{
@ -115,4 +116,50 @@ namespace NDS
public String entryName;
public UInt16 directoryID;
}
public class NitroFSUtil
{
public static void GenerateDirectoryTable(List<DirectoryTableEntry> directoryTable, SFSDirectory dir)
{
DirectoryTableEntry cur = new DirectoryTableEntry();
if (dir.IsRoot)
{
cur.dirParentID = (ushort)(dir.TotalNrSubDirectories + 1);
cur.dirEntryStart = cur.dirParentID * 8u;
}
else cur.dirParentID = dir.Parent.DirectoryID;
dir.DirectoryID = (ushort)(0xF000 + directoryTable.Count);
directoryTable.Add(cur);
foreach (SFSDirectory d in dir.SubDirectories)
{
GenerateDirectoryTable(directoryTable, d);
}
}
public static void GenerateEntryNameTable(List<DirectoryTableEntry> directoryTable, List<EntryNameTableEntry> entryNameTable, SFSDirectory dir, ref uint Offset, ref ushort FileId)
{
directoryTable[dir.DirectoryID - 0xF000].dirEntryStart = Offset;
directoryTable[dir.DirectoryID - 0xF000].dirEntryFileID = FileId;
foreach (SFSDirectory d in dir.SubDirectories)
{
entryNameTable.Add(new EntryNameTableDirectoryEntry(d.DirectoryName, d.DirectoryID));
Offset += (uint)d.DirectoryName.Length + 3u;
}
foreach (SFSFile f in dir.Files)
{
f.FileID = FileId;
entryNameTable.Add(new EntryNameTableFileEntry(f.FileName));
Offset += (uint)f.FileName.Length + 1u;
FileId++;
}
entryNameTable.Add(new EntryNameTableEndOfDirectoryEntry());
Offset++;
foreach (SFSDirectory d in dir.SubDirectories)
{
GenerateEntryNameTable(directoryTable, entryNameTable, d, ref Offset, ref FileId);
}
}
}
}

View File

@ -242,11 +242,11 @@ namespace NDS.NitroSystem.FND
}
FIMG.fileImage = Data.ToArray();
FNTB.directoryTable.Clear();
GenerateDirectoryTable(FNTB.directoryTable, Root);
NitroFSUtil.GenerateDirectoryTable(FNTB.directoryTable, Root);
uint offset2 = FNTB.directoryTable[0].dirEntryStart;
ushort fileId = 0;
FNTB.entryNameTable.Clear();
GenerateEntryNameTable(FNTB.directoryTable, FNTB.entryNameTable, Root, ref offset2, ref fileId);
NitroFSUtil.GenerateEntryNameTable(FNTB.directoryTable, FNTB.entryNameTable, Root, ref offset2, ref fileId);
}
public SFSDirectory ToFileSystem()
@ -330,49 +330,6 @@ namespace NDS.NitroSystem.FND
return dirs[0];
}
private static void GenerateDirectoryTable(List<DirectoryTableEntry> directoryTable, SFSDirectory dir)
{
DirectoryTableEntry cur = new DirectoryTableEntry();
if (dir.IsRoot)
{
cur.dirParentID = (ushort)(dir.TotalNrSubDirectories + 1);
cur.dirEntryStart = cur.dirParentID * 8u;
}
else cur.dirParentID = dir.Parent.DirectoryID;
dir.DirectoryID = (ushort)(0xF000 + directoryTable.Count);
directoryTable.Add(cur);
foreach (SFSDirectory d in dir.SubDirectories)
{
GenerateDirectoryTable(directoryTable, d);
}
}
private static void GenerateEntryNameTable(List<DirectoryTableEntry> directoryTable, List<EntryNameTableEntry> entryNameTable, SFSDirectory dir, ref uint Offset, ref ushort FileId)
{
directoryTable[dir.DirectoryID - 0xF000].dirEntryStart = Offset;
directoryTable[dir.DirectoryID - 0xF000].dirEntryFileID = FileId;
foreach (SFSDirectory d in dir.SubDirectories)
{
entryNameTable.Add(new EntryNameTableDirectoryEntry(d.DirectoryName, d.DirectoryID));
Offset += (uint)d.DirectoryName.Length + 3u;
}
foreach (SFSFile f in dir.Files)
{
f.FileID = FileId;
entryNameTable.Add(new EntryNameTableFileEntry(f.FileName));
Offset += (uint)f.FileName.Length + 1u;
FileId++;
}
entryNameTable.Add(new EntryNameTableEndOfDirectoryEntry());
Offset++;
foreach (SFSDirectory d in dir.SubDirectories)
{
GenerateEntryNameTable(directoryTable, entryNameTable, d, ref Offset, ref FileId);
}
}
public class NARCIdentifier : FileFormatIdentifier
{
public override string GetCategory()

View File

@ -76,10 +76,10 @@
this.fileBrowser1.Location = new System.Drawing.Point(0, 0);
this.fileBrowser1.Name = "fileBrowser1";
this.fileBrowser1.RenameEnabled = false;
this.fileBrowser1.ShowAddDirectoryButton = false;
this.fileBrowser1.ShowAddFileButton = false;
this.fileBrowser1.ShowDeleteButton = false;
this.fileBrowser1.ShowRenameButton = false;
this.fileBrowser1.ShowAddDirectoryButton = true;
this.fileBrowser1.ShowAddFileButton = true;
this.fileBrowser1.ShowDeleteButton = true;
this.fileBrowser1.ShowRenameButton = true;
this.fileBrowser1.Size = new System.Drawing.Size(475, 338);
this.fileBrowser1.TabIndex = 0;
this.fileBrowser1.OnDirectoryChanged += new LibEveryFileExplorer.UI.FileBrowser.OnDirectoryChangedEventHandler(this.fileBrowser1_OnDirectoryChanged);
@ -151,7 +151,6 @@
this.menuReplace.Enabled = false;
this.menuReplace.Index = 5;
this.menuReplace.Text = "Replace...";
this.menuReplace.Visible = false;
this.menuReplace.Click += new System.EventHandler(this.menuReplace_Click);
//
// menuRename
@ -159,7 +158,6 @@
this.menuRename.Enabled = false;
this.menuRename.Index = 6;
this.menuRename.Text = "Rename...";
this.menuRename.Visible = false;
this.menuRename.Click += new System.EventHandler(this.fileBrowser1_OnRename);
//
// menuDelete
@ -167,7 +165,6 @@
this.menuDelete.Enabled = false;
this.menuDelete.Index = 7;
this.menuDelete.Text = "Delete";
this.menuDelete.Visible = false;
this.menuDelete.Click += new System.EventHandler(this.fileBrowser1_OnRemove);
//
// menuItem5
@ -226,21 +223,18 @@
//
this.menuItem14.Index = 2;
this.menuItem14.Text = "Replace...";
this.menuItem14.Visible = false;
this.menuItem14.Click += new System.EventHandler(this.menuReplace_Click);
//
// menuItem10
//
this.menuItem10.Index = 3;
this.menuItem10.Text = "Rename...";
this.menuItem10.Visible = false;
this.menuItem10.Click += new System.EventHandler(this.fileBrowser1_OnRename);
//
// menuItem11
//
this.menuItem11.Index = 4;
this.menuItem11.Text = "Delete";
this.menuItem11.Visible = false;
this.menuItem11.Click += new System.EventHandler(this.fileBrowser1_OnRemove);
//
// saveFileDialog1

View File

@ -44,7 +44,7 @@ namespace NDS.UI
private void fileBrowser1_OnAddDirectory(object sender, EventArgs e)
{
/*var dir = Root.GetDirectoryByPath(fileBrowser1.SelectedFolderPath);
var dir = Root.GetDirectoryByPath(fileBrowser1.SelectedFolderPath);
if (dir == null) return;
String name = null;
retry:
@ -62,12 +62,12 @@ namespace NDS.UI
{
MessageBox.Show("The name contains either one or more invalid chars, or is already in use!", "Invalid Name");
goto retry;
}*/
}
}
private void fileBrowser1_OnAddFile(object sender, EventArgs e)
{
/*if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK
if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK
&& openFileDialog1.FileName.Length > 0)
{
var dir = Root.GetDirectoryByPath(fileBrowser1.SelectedFolderPath);
@ -101,12 +101,12 @@ namespace NDS.UI
}
Archive.FromFileSystem(Root);
fileBrowser1.UpdateDirectories(Root.GetTreeNodes(), true);
}*/
}
}
private void fileBrowser1_OnRemove(object sender, EventArgs e)
{
/*if (fileBrowser1.SelectedFolderPath == fileBrowser1.SelectedPath) return;
if (fileBrowser1.SelectedFolderPath == fileBrowser1.SelectedPath) return;
var dir = Root.GetDirectoryByPath(fileBrowser1.SelectedPath);
if (dir != null)
{
@ -122,12 +122,12 @@ namespace NDS.UI
file.Parent.Files.Remove(file);
Archive.FromFileSystem(Root);
fileBrowser1.UpdateDirectories(Root.GetTreeNodes(), true);
}*/
}
}
private void fileBrowser1_OnRename(object sender, EventArgs e)
{
/*if (fileBrowser1.SelectedFolderPath == fileBrowser1.SelectedPath) return;
if (fileBrowser1.SelectedFolderPath == fileBrowser1.SelectedPath) return;
var dir = Root.GetDirectoryByPath(fileBrowser1.SelectedPath);
if (dir != null)
{
@ -167,7 +167,7 @@ namespace NDS.UI
MessageBox.Show("The name contains either one or more invalid chars, or is already in use!", "Invalid Name");
goto retryf;
}
}*/
}
}
private void fileBrowser1_OnSelectionChanged(object sender, EventArgs e)
@ -217,21 +217,20 @@ namespace NDS.UI
private void menuReplace_Click(object sender, EventArgs e)
{
/*if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK
if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK
&& openFileDialog1.FileName.Length > 0)
{
var file = Root.GetFileByPath(fileBrowser1.SelectedPath);
file.Data = System.IO.File.ReadAllBytes(openFileDialog1.FileName);
Archive.FromFileSystem(Root);
fileBrowser1.UpdateDirectories(Root.GetTreeNodes(), true);
}*/
}
}
public void OnChildSave(ViewableFile File)
{
/*Archive.FromFileSystem(Root);
Archive.FromFileSystem(Root);
fileBrowser1.UpdateDirectories(Root.GetTreeNodes(), true);
*/
}
private void button1_Click(object sender, EventArgs e)