mirror of
https://github.com/Gericom/dspatch.git
synced 2025-06-18 17:05:42 -04:00
Add project files.
This commit is contained in:
parent
b57add0b63
commit
4b3548b6ab
34
dspatch.sln
Normal file
34
dspatch.sln
Normal file
@ -0,0 +1,34 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dspatch", "dspatch\dspatch.csproj", "{C8CAE5E5-40A9-4840-AE8A-ABBD2AE50749}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{C8CAE5E5-40A9-4840-AE8A-ABBD2AE50749}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C8CAE5E5-40A9-4840-AE8A-ABBD2AE50749}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C8CAE5E5-40A9-4840-AE8A-ABBD2AE50749}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{C8CAE5E5-40A9-4840-AE8A-ABBD2AE50749}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{C8CAE5E5-40A9-4840-AE8A-ABBD2AE50749}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{C8CAE5E5-40A9-4840-AE8A-ABBD2AE50749}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{C8CAE5E5-40A9-4840-AE8A-ABBD2AE50749}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C8CAE5E5-40A9-4840-AE8A-ABBD2AE50749}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C8CAE5E5-40A9-4840-AE8A-ABBD2AE50749}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{C8CAE5E5-40A9-4840-AE8A-ABBD2AE50749}.Release|x64.Build.0 = Release|Any CPU
|
||||
{C8CAE5E5-40A9-4840-AE8A-ABBD2AE50749}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{C8CAE5E5-40A9-4840-AE8A-ABBD2AE50749}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
6
dspatch/App.config
Normal file
6
dspatch/App.config
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
|
||||
</startup>
|
||||
</configuration>
|
89
dspatch/DS/DemoMenu.cs
Normal file
89
dspatch/DS/DemoMenu.cs
Normal file
@ -0,0 +1,89 @@
|
||||
using dspatch.IO;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace dspatch.DS
|
||||
{
|
||||
public class DemoMenu
|
||||
{
|
||||
public byte[] Write()
|
||||
{
|
||||
MemoryStream m = new MemoryStream();
|
||||
EndianBinaryWriter er = new EndianBinaryWriter(m);
|
||||
er.Write((byte)entries.Length);
|
||||
er.Write((byte)0);
|
||||
er.Write((byte)0);
|
||||
er.Write((byte)0);
|
||||
foreach (var e in entries)
|
||||
e.Write(er);
|
||||
er.Write((uint)0);
|
||||
byte[] result = m.ToArray();
|
||||
er.Close();
|
||||
return result;
|
||||
}
|
||||
public DemoMenuEntry[] entries;
|
||||
public class DemoMenuEntry
|
||||
{
|
||||
private string createString(string text, int length, bool nullTerminated = true)
|
||||
{
|
||||
if (text == null)
|
||||
text = "";
|
||||
if (text.Length > (length - (nullTerminated ? 1 : 0)))
|
||||
return text.Substring(0, length - (nullTerminated ? 1 : 0));
|
||||
return text.PadRight(length, '\0');
|
||||
}
|
||||
|
||||
public void Write(EndianBinaryWriter er)
|
||||
{
|
||||
er.Write(bannerImage, 0, 512);
|
||||
er.Write(bannerPalette, 0, 32);
|
||||
er.Write(createString(bannerText1, 0x80), Encoding.ASCII, false);
|
||||
er.Write(createString(bannerText2, 0x80), Encoding.ASCII, false);
|
||||
er.Write(rating);
|
||||
er.Write(guideMode);
|
||||
er.Write(createString(selectButtonText, 0x20), Encoding.ASCII, false);
|
||||
er.Write(createString(startButtonText, 0x20), Encoding.ASCII, false);
|
||||
er.Write(createString(aButtonText, 0x20), Encoding.ASCII, false);
|
||||
er.Write(createString(bButtonText, 0x20), Encoding.ASCII, false);
|
||||
er.Write(createString(xButtonText, 0x20), Encoding.ASCII, false);
|
||||
er.Write(createString(yButtonText, 0x20), Encoding.ASCII, false);
|
||||
er.Write(createString(lButtonText, 0x20), Encoding.ASCII, false);
|
||||
er.Write(createString(rButtonText, 0x20), Encoding.ASCII, false);
|
||||
er.Write(createString(dpadText, 0x20), Encoding.ASCII, false);
|
||||
er.Write(createString(unknown1Text, 0x20), Encoding.ASCII, false);
|
||||
er.Write(createString(unknown2Text, 0x20), Encoding.ASCII, false);
|
||||
er.Write(createString(unknown3Text, 0x20), Encoding.ASCII, false);
|
||||
er.Write(createString(touchText1, 0x20), Encoding.ASCII, false);
|
||||
er.Write(createString(touchText2, 0x20), Encoding.ASCII, false);
|
||||
er.Write(padding, 0, 0x40);
|
||||
er.Write(createString(internalName, 0xA, false), Encoding.ASCII, false);
|
||||
}
|
||||
public byte[] bannerImage;
|
||||
public byte[] bannerPalette;
|
||||
public string bannerText1;
|
||||
public string bannerText2;
|
||||
public byte rating = 0x1;//0x1 = Everyone
|
||||
public byte guideMode = 0x11;//0x11 = nothing, 0x13 = only buttons, 0x15 = only touch, 0x17 = buttons + touch
|
||||
public string selectButtonText;
|
||||
public string startButtonText;
|
||||
public string aButtonText;
|
||||
public string bButtonText;
|
||||
public string xButtonText;
|
||||
public string yButtonText;
|
||||
public string lButtonText;
|
||||
public string rButtonText;
|
||||
public string dpadText;
|
||||
public string unknown1Text;
|
||||
public string unknown2Text;
|
||||
public string unknown3Text;
|
||||
public string touchText1;
|
||||
public string touchText2;
|
||||
public byte[] padding = new byte[0x40];//?
|
||||
public string internalName;
|
||||
}
|
||||
}
|
||||
}
|
374
dspatch/IO/EndianBinaryReader.cs
Normal file
374
dspatch/IO/EndianBinaryReader.cs
Normal file
@ -0,0 +1,374 @@
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace dspatch.IO
|
||||
{
|
||||
public class EndianBinaryReader : IDisposable
|
||||
{
|
||||
private bool disposed;
|
||||
private byte[] buffer;
|
||||
|
||||
public Stream BaseStream { get; private set; }
|
||||
public Endianness Endianness { get; set; }
|
||||
public Endianness SystemEndianness { get { return BitConverter.IsLittleEndian ? Endianness.LittleEndian : Endianness.BigEndian; } }
|
||||
|
||||
private bool Reverse { get { return SystemEndianness != Endianness; } }
|
||||
|
||||
public EndianBinaryReader(Stream baseStream)
|
||||
: this(baseStream, Endianness.BigEndian)
|
||||
{ }
|
||||
|
||||
public EndianBinaryReader(Stream baseStream, Endianness endianness)
|
||||
{
|
||||
if (baseStream == null) throw new ArgumentNullException("baseStream");
|
||||
if (!baseStream.CanRead) throw new ArgumentException("baseStream");
|
||||
|
||||
BaseStream = baseStream;
|
||||
Endianness = endianness;
|
||||
}
|
||||
|
||||
~EndianBinaryReader()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
private void FillBuffer(int bytes, int stride)
|
||||
{
|
||||
if (buffer == null || buffer.Length < bytes)
|
||||
buffer = new byte[bytes];
|
||||
|
||||
BaseStream.Read(buffer, 0, bytes);
|
||||
|
||||
if (Reverse)
|
||||
for (int i = 0; i < bytes; i += stride)
|
||||
{
|
||||
Array.Reverse(buffer, i, stride);
|
||||
}
|
||||
}
|
||||
|
||||
public byte ReadByte()
|
||||
{
|
||||
FillBuffer(1, 1);
|
||||
|
||||
return buffer[0];
|
||||
}
|
||||
|
||||
public byte[] ReadBytes(int count)
|
||||
{
|
||||
byte[] temp;
|
||||
|
||||
FillBuffer(count, 1);
|
||||
temp = new byte[count];
|
||||
Array.Copy(buffer, 0, temp, 0, count);
|
||||
return temp;
|
||||
}
|
||||
|
||||
public sbyte ReadSByte()
|
||||
{
|
||||
FillBuffer(1, 1);
|
||||
|
||||
unchecked
|
||||
{
|
||||
return (sbyte)buffer[0];
|
||||
}
|
||||
}
|
||||
|
||||
public sbyte[] ReadSBytes(int count)
|
||||
{
|
||||
sbyte[] temp;
|
||||
|
||||
temp = new sbyte[count];
|
||||
FillBuffer(count, 1);
|
||||
|
||||
unchecked
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
temp[i] = (sbyte)buffer[i];
|
||||
}
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
public char ReadChar(Encoding encoding)
|
||||
{
|
||||
int size;
|
||||
|
||||
size = GetEncodingSize(encoding);
|
||||
FillBuffer(size, size);
|
||||
return encoding.GetChars(buffer, 0, size)[0];
|
||||
}
|
||||
|
||||
public char[] ReadChars(Encoding encoding, int count)
|
||||
{
|
||||
int size;
|
||||
|
||||
size = GetEncodingSize(encoding);
|
||||
FillBuffer(size * count, size);
|
||||
return encoding.GetChars(buffer, 0, size * count);
|
||||
}
|
||||
|
||||
private static int GetEncodingSize(Encoding encoding)
|
||||
{
|
||||
if (encoding == Encoding.UTF8 || encoding == Encoding.ASCII)
|
||||
return 1;
|
||||
else if (encoding == Encoding.Unicode || encoding == Encoding.BigEndianUnicode)
|
||||
return 2;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public string ReadStringNT(Encoding encoding)
|
||||
{
|
||||
string text;
|
||||
|
||||
text = "";
|
||||
|
||||
do
|
||||
{
|
||||
text += ReadChar(encoding);
|
||||
} while (!text.EndsWith("\0", StringComparison.Ordinal));
|
||||
|
||||
return text.Remove(text.Length - 1);
|
||||
}
|
||||
|
||||
public string ReadString(Encoding encoding, int count)
|
||||
{
|
||||
return new string(ReadChars(encoding, count));
|
||||
}
|
||||
|
||||
public double ReadDouble()
|
||||
{
|
||||
const int size = sizeof(double);
|
||||
FillBuffer(size, size);
|
||||
return BitConverter.ToDouble(buffer, 0);
|
||||
}
|
||||
|
||||
public double[] ReadDoubles(int count)
|
||||
{
|
||||
const int size = sizeof(double);
|
||||
double[] temp;
|
||||
|
||||
temp = new double[count];
|
||||
FillBuffer(size * count, size);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
temp[i] = BitConverter.ToDouble(buffer, size * i);
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
public Single ReadSingle()
|
||||
{
|
||||
const int size = sizeof(Single);
|
||||
FillBuffer(size, size);
|
||||
return BitConverter.ToSingle(buffer, 0);
|
||||
}
|
||||
|
||||
public Single[] ReadSingles(int count)
|
||||
{
|
||||
const int size = sizeof(Single);
|
||||
Single[] temp;
|
||||
|
||||
temp = new Single[count];
|
||||
FillBuffer(size * count, size);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
temp[i] = BitConverter.ToSingle(buffer, size * i);
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
public Single ReadFx16()
|
||||
{
|
||||
return ReadInt16() / 4096f;
|
||||
}
|
||||
|
||||
public Single ReadFx32()
|
||||
{
|
||||
return ReadInt32() / 4096f;
|
||||
}
|
||||
|
||||
public Single[] ReadFx32s(int count)
|
||||
{
|
||||
Single[] result = new float[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
result[i] = ReadInt32() / 4096f;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Int32 ReadInt32()
|
||||
{
|
||||
const int size = sizeof(Int32);
|
||||
FillBuffer(size, size);
|
||||
return BitConverter.ToInt32(buffer, 0);
|
||||
}
|
||||
|
||||
public Int32[] ReadInt32s(int count)
|
||||
{
|
||||
const int size = sizeof(Int32);
|
||||
Int32[] temp;
|
||||
|
||||
temp = new Int32[count];
|
||||
FillBuffer(size * count, size);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
temp[i] = BitConverter.ToInt32(buffer, size * i);
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
public Int64 ReadInt64()
|
||||
{
|
||||
const int size = sizeof(Int64);
|
||||
FillBuffer(size, size);
|
||||
return BitConverter.ToInt64(buffer, 0);
|
||||
}
|
||||
|
||||
public Int64[] ReadInt64s(int count)
|
||||
{
|
||||
const int size = sizeof(Int64);
|
||||
Int64[] temp;
|
||||
|
||||
temp = new Int64[count];
|
||||
FillBuffer(size * count, size);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
temp[i] = BitConverter.ToInt64(buffer, size * i);
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
public Int16 ReadInt16()
|
||||
{
|
||||
const int size = sizeof(Int16);
|
||||
FillBuffer(size, size);
|
||||
return BitConverter.ToInt16(buffer, 0);
|
||||
}
|
||||
|
||||
public Int16[] ReadInt16s(int count)
|
||||
{
|
||||
const int size = sizeof(Int16);
|
||||
Int16[] temp;
|
||||
|
||||
temp = new Int16[count];
|
||||
FillBuffer(size * count, size);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
temp[i] = BitConverter.ToInt16(buffer, size * i);
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
public UInt16 ReadUInt16()
|
||||
{
|
||||
const int size = sizeof(UInt16);
|
||||
FillBuffer(size, size);
|
||||
return BitConverter.ToUInt16(buffer, 0);
|
||||
}
|
||||
|
||||
public UInt16[] ReadUInt16s(int count)
|
||||
{
|
||||
const int size = sizeof(UInt16);
|
||||
UInt16[] temp;
|
||||
|
||||
temp = new UInt16[count];
|
||||
FillBuffer(size * count, size);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
temp[i] = BitConverter.ToUInt16(buffer, size * i);
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
public UInt32 ReadUInt32()
|
||||
{
|
||||
const int size = sizeof(UInt32);
|
||||
FillBuffer(size, size);
|
||||
return BitConverter.ToUInt32(buffer, 0);
|
||||
}
|
||||
|
||||
public UInt32[] ReadUInt32s(int count)
|
||||
{
|
||||
const int size = sizeof(UInt32);
|
||||
UInt32[] temp;
|
||||
|
||||
temp = new UInt32[count];
|
||||
FillBuffer(size * count, size);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
temp[i] = BitConverter.ToUInt32(buffer, size * i);
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
public UInt64 ReadUInt64()
|
||||
{
|
||||
const int size = sizeof(UInt64);
|
||||
FillBuffer(size, size);
|
||||
return BitConverter.ToUInt64(buffer, 0);
|
||||
}
|
||||
|
||||
public UInt64[] ReadUInt64s(int count)
|
||||
{
|
||||
const int size = sizeof(UInt64);
|
||||
UInt64[] temp;
|
||||
|
||||
temp = new UInt64[count];
|
||||
FillBuffer(size * count, size);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
temp[i] = BitConverter.ToUInt64(buffer, size * i);
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (BaseStream != null)
|
||||
{
|
||||
BaseStream.Close();
|
||||
}
|
||||
}
|
||||
|
||||
buffer = null;
|
||||
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum Endianness
|
||||
{
|
||||
BigEndian,
|
||||
LittleEndian,
|
||||
}
|
||||
}
|
344
dspatch/IO/EndianBinaryWriter.cs
Normal file
344
dspatch/IO/EndianBinaryWriter.cs
Normal file
@ -0,0 +1,344 @@
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System;
|
||||
|
||||
namespace dspatch.IO
|
||||
{
|
||||
public class EndianBinaryWriter : IDisposable
|
||||
{
|
||||
private bool disposed;
|
||||
private byte[] buffer;
|
||||
|
||||
public Stream BaseStream { get; private set; }
|
||||
public Endianness Endianness { get; set; }
|
||||
public Endianness SystemEndianness { get { return BitConverter.IsLittleEndian ? Endianness.LittleEndian : Endianness.BigEndian; } }
|
||||
|
||||
private bool Reverse { get { return SystemEndianness != Endianness; } }
|
||||
|
||||
public EndianBinaryWriter(Stream baseStream)
|
||||
: this(baseStream, Endianness.BigEndian)
|
||||
{ }
|
||||
|
||||
public EndianBinaryWriter(Stream baseStream, Endianness endianness)
|
||||
{
|
||||
if (baseStream == null) throw new ArgumentNullException("baseStream");
|
||||
if (!baseStream.CanWrite) throw new ArgumentException("baseStream");
|
||||
|
||||
BaseStream = baseStream;
|
||||
Endianness = endianness;
|
||||
}
|
||||
|
||||
~EndianBinaryWriter()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
private void WriteBuffer(int bytes, int stride)
|
||||
{
|
||||
if (Reverse)
|
||||
for (int i = 0; i < bytes; i += stride)
|
||||
{
|
||||
Array.Reverse(buffer, i, stride);
|
||||
}
|
||||
|
||||
BaseStream.Write(buffer, 0, bytes);
|
||||
}
|
||||
|
||||
private void CreateBuffer(int size)
|
||||
{
|
||||
if (buffer == null || buffer.Length < size)
|
||||
buffer = new byte[size];
|
||||
}
|
||||
|
||||
public void Write(byte value)
|
||||
{
|
||||
CreateBuffer(1);
|
||||
buffer[0] = value;
|
||||
WriteBuffer(1, 1);
|
||||
}
|
||||
|
||||
public void Write(byte[] value, int offset, int count)
|
||||
{
|
||||
CreateBuffer(count);
|
||||
Array.Copy(value, offset, buffer, 0, count);
|
||||
WriteBuffer(count, 1);
|
||||
}
|
||||
|
||||
public void Write(sbyte value)
|
||||
{
|
||||
CreateBuffer(1);
|
||||
unchecked
|
||||
{
|
||||
buffer[0] = (byte)value;
|
||||
}
|
||||
WriteBuffer(1, 1);
|
||||
}
|
||||
|
||||
public void Write(sbyte[] value, int offset, int count)
|
||||
{
|
||||
CreateBuffer(count);
|
||||
|
||||
unchecked
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
buffer[i] = (byte)value[i + offset];
|
||||
}
|
||||
}
|
||||
|
||||
WriteBuffer(count, 1);
|
||||
}
|
||||
|
||||
public void Write(char value, Encoding encoding)
|
||||
{
|
||||
int size;
|
||||
|
||||
size = GetEncodingSize(encoding);
|
||||
CreateBuffer(size);
|
||||
Array.Copy(encoding.GetBytes(new string(value, 1)), 0, buffer, 0, size);
|
||||
WriteBuffer(size, size);
|
||||
}
|
||||
|
||||
public void Write(char[] value, int offset, int count, Encoding encoding)
|
||||
{
|
||||
int size;
|
||||
|
||||
size = GetEncodingSize(encoding);
|
||||
CreateBuffer(size * count);
|
||||
Array.Copy(encoding.GetBytes(value, offset, count), 0, buffer, 0, count * size);
|
||||
WriteBuffer(size * count, size);
|
||||
}
|
||||
|
||||
private static int GetEncodingSize(Encoding encoding)
|
||||
{
|
||||
if (encoding == Encoding.UTF8 || encoding == Encoding.ASCII)
|
||||
return 1;
|
||||
else if (encoding == Encoding.Unicode || encoding == Encoding.BigEndianUnicode)
|
||||
return 2;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public void Write(string value,Encoding encoding, bool nullTerminated)
|
||||
{
|
||||
Write(value.ToCharArray(), 0, value.Length, encoding);
|
||||
if (nullTerminated)
|
||||
Write('\0', encoding);
|
||||
}
|
||||
|
||||
public void Write(double value)
|
||||
{
|
||||
const int size = sizeof(double);
|
||||
|
||||
CreateBuffer(size);
|
||||
Array.Copy(BitConverter.GetBytes(value), 0, buffer, 0, size);
|
||||
WriteBuffer(size, size);
|
||||
}
|
||||
|
||||
public void Write(double[] value, int offset, int count)
|
||||
{
|
||||
const int size = sizeof(double);
|
||||
|
||||
CreateBuffer(size * count);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Array.Copy(BitConverter.GetBytes(value[i + offset]), 0, buffer, i * size, size);
|
||||
}
|
||||
|
||||
WriteBuffer(size * count, size);
|
||||
}
|
||||
|
||||
public void Write(Single value)
|
||||
{
|
||||
const int size = sizeof(Single);
|
||||
|
||||
CreateBuffer(size);
|
||||
Array.Copy(BitConverter.GetBytes(value), 0, buffer, 0, size);
|
||||
WriteBuffer(size, size);
|
||||
}
|
||||
|
||||
public void Write(Single[] value, int offset, int count)
|
||||
{
|
||||
const int size = sizeof(Single);
|
||||
|
||||
CreateBuffer(size * count);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Array.Copy(BitConverter.GetBytes(value[i + offset]), 0, buffer, i * size, size);
|
||||
}
|
||||
|
||||
WriteBuffer(size * count, size);
|
||||
}
|
||||
|
||||
public void Write(Int32 value)
|
||||
{
|
||||
const int size = sizeof(Int32);
|
||||
|
||||
CreateBuffer(size);
|
||||
Array.Copy(BitConverter.GetBytes(value), 0, buffer, 0, size);
|
||||
WriteBuffer(size, size);
|
||||
}
|
||||
|
||||
public void Write(Int32[] value, int offset, int count)
|
||||
{
|
||||
const int size = sizeof(Int32);
|
||||
|
||||
CreateBuffer(size * count);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Array.Copy(BitConverter.GetBytes(value[i + offset]), 0, buffer, i * size, size);
|
||||
}
|
||||
|
||||
WriteBuffer(size * count, size);
|
||||
}
|
||||
|
||||
public void Write(Int64 value)
|
||||
{
|
||||
const int size = sizeof(Int64);
|
||||
|
||||
CreateBuffer(size);
|
||||
Array.Copy(BitConverter.GetBytes(value), 0, buffer, 0, size);
|
||||
WriteBuffer(size, size);
|
||||
}
|
||||
|
||||
public void Write(Int64[] value, int offset, int count)
|
||||
{
|
||||
const int size = sizeof(Int64);
|
||||
|
||||
CreateBuffer(size * count);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Array.Copy(BitConverter.GetBytes(value[i + offset]), 0, buffer, i * size, size);
|
||||
}
|
||||
|
||||
WriteBuffer(size * count, size);
|
||||
}
|
||||
|
||||
public void Write(Int16 value)
|
||||
{
|
||||
const int size = sizeof(Int16);
|
||||
|
||||
CreateBuffer(size);
|
||||
Array.Copy(BitConverter.GetBytes(value), 0, buffer, 0, size);
|
||||
WriteBuffer(size, size);
|
||||
}
|
||||
|
||||
public void Write(Int16[] value, int offset, int count)
|
||||
{
|
||||
const int size = sizeof(Int16);
|
||||
|
||||
CreateBuffer(size * count);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Array.Copy(BitConverter.GetBytes(value[i + offset]), 0, buffer, i * size, size);
|
||||
}
|
||||
|
||||
WriteBuffer(size * count, size);
|
||||
}
|
||||
|
||||
public void Write(UInt16 value)
|
||||
{
|
||||
const int size = sizeof(UInt16);
|
||||
|
||||
CreateBuffer(size);
|
||||
Array.Copy(BitConverter.GetBytes(value), 0, buffer, 0, size);
|
||||
WriteBuffer(size, size);
|
||||
}
|
||||
|
||||
public void Write(UInt16[] value, int offset, int count)
|
||||
{
|
||||
const int size = sizeof(UInt16);
|
||||
|
||||
CreateBuffer(size * count);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Array.Copy(BitConverter.GetBytes(value[i + offset]), 0, buffer, i * size, size);
|
||||
}
|
||||
|
||||
WriteBuffer(size * count, size);
|
||||
}
|
||||
|
||||
public void Write(UInt32 value)
|
||||
{
|
||||
const int size = sizeof(UInt32);
|
||||
|
||||
CreateBuffer(size);
|
||||
Array.Copy(BitConverter.GetBytes(value), 0, buffer, 0, size);
|
||||
WriteBuffer(size, size);
|
||||
}
|
||||
|
||||
public void Write(UInt32[] value, int offset, int count)
|
||||
{
|
||||
const int size = sizeof(UInt32);
|
||||
|
||||
CreateBuffer(size * count);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Array.Copy(BitConverter.GetBytes(value[i + offset]), 0, buffer, i * size, size);
|
||||
}
|
||||
|
||||
WriteBuffer(size * count, size);
|
||||
}
|
||||
|
||||
public void Write(UInt64 value)
|
||||
{
|
||||
const int size = sizeof(UInt64);
|
||||
|
||||
CreateBuffer(size);
|
||||
Array.Copy(BitConverter.GetBytes(value), 0, buffer, 0, size);
|
||||
WriteBuffer(size, size);
|
||||
}
|
||||
|
||||
public void Write(UInt64[] value, int offset, int count)
|
||||
{
|
||||
const int size = sizeof(UInt64);
|
||||
|
||||
CreateBuffer(size * count);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Array.Copy(BitConverter.GetBytes(value[i + offset]), 0, buffer, i * size, size);
|
||||
}
|
||||
|
||||
WriteBuffer(size * count, size);
|
||||
}
|
||||
|
||||
public void WriteFx16(Single Value)
|
||||
{
|
||||
Write((Int16)(Value * 4096f));
|
||||
}
|
||||
|
||||
public void WriteFx32(Single Value)
|
||||
{
|
||||
Write((Int32)(Value * 4096f));
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (BaseStream != null)
|
||||
{
|
||||
BaseStream.Close();
|
||||
}
|
||||
}
|
||||
|
||||
buffer = null;
|
||||
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
119
dspatch/IO/IOUtil.cs
Normal file
119
dspatch/IO/IOUtil.cs
Normal file
@ -0,0 +1,119 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace dspatch.IO
|
||||
{
|
||||
public class IOUtil
|
||||
{
|
||||
public static short ReadS16LE(byte[] Data, int Offset)
|
||||
{
|
||||
return (short)(Data[Offset] | (Data[Offset + 1] << 8));
|
||||
}
|
||||
|
||||
public static short[] ReadS16sLE(byte[] Data, int Offset, int Count)
|
||||
{
|
||||
short[] res = new short[Count];
|
||||
for (int i = 0; i < Count; i++) res[i] = ReadS16LE(Data, Offset + i * 2);
|
||||
return res;
|
||||
}
|
||||
|
||||
public static short ReadS16BE(byte[] Data, int Offset)
|
||||
{
|
||||
return (short)((Data[Offset] << 8) | Data[Offset + 1]);
|
||||
}
|
||||
|
||||
public static void WriteS16LE(byte[] Data, int Offset, short Value)
|
||||
{
|
||||
Data[Offset] = (byte)(Value & 0xFF);
|
||||
Data[Offset + 1] = (byte)((Value >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
public static void WriteS16sLE(byte[] Data, int Offset, short[] Values)
|
||||
{
|
||||
for (int i = 0; i < Values.Length; i++)
|
||||
{
|
||||
WriteS16LE(Data, Offset + i * 2, Values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static ushort ReadU16LE(byte[] Data, int Offset)
|
||||
{
|
||||
return (ushort)(Data[Offset] | (Data[Offset + 1] << 8));
|
||||
}
|
||||
|
||||
public static ushort ReadU16BE(byte[] Data, int Offset)
|
||||
{
|
||||
return (ushort)((Data[Offset] << 8) | Data[Offset + 1]);
|
||||
}
|
||||
|
||||
public static void WriteU16LE(byte[] Data, int Offset, ushort Value)
|
||||
{
|
||||
Data[Offset] = (byte)(Value & 0xFF);
|
||||
Data[Offset + 1] = (byte)((Value >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
public static uint ReadU24LE(byte[] Data, int Offset)
|
||||
{
|
||||
return (uint)(Data[Offset] | (Data[Offset + 1] << 8) | (Data[Offset + 2] << 16));
|
||||
}
|
||||
|
||||
public static uint ReadU32LE(byte[] Data, int Offset)
|
||||
{
|
||||
return (uint)(Data[Offset] | (Data[Offset + 1] << 8) | (Data[Offset + 2] << 16) | (Data[Offset + 3] << 24));
|
||||
}
|
||||
|
||||
public static uint ReadU32BE(byte[] Data, int Offset)
|
||||
{
|
||||
return (uint)((Data[Offset] << 24) | (Data[Offset + 1] << 16) | (Data[Offset + 2] << 8) | Data[Offset + 3]);
|
||||
}
|
||||
|
||||
public static void WriteU32LE(byte[] Data, int Offset, uint Value)
|
||||
{
|
||||
Data[Offset] = (byte)(Value & 0xFF);
|
||||
Data[Offset + 1] = (byte)((Value >> 8) & 0xFF);
|
||||
Data[Offset + 2] = (byte)((Value >> 16) & 0xFF);
|
||||
Data[Offset + 3] = (byte)((Value >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
public static void WriteU32BE(byte[] Data, int Offset, uint Value)
|
||||
{
|
||||
Data[Offset + 0] = (byte)((Value >> 24) & 0xFF);
|
||||
Data[Offset + 1] = (byte)((Value >> 16) & 0xFF);
|
||||
Data[Offset + 2] = (byte)((Value >> 8) & 0xFF);
|
||||
Data[Offset + 3] = (byte)(Value & 0xFF);
|
||||
}
|
||||
|
||||
public static ulong ReadU64LE(byte[] Data, int Offset)
|
||||
{
|
||||
return (ulong)Data[Offset] | ((ulong)Data[Offset + 1] << 8) | ((ulong)Data[Offset + 2] << 16) | ((ulong)Data[Offset + 3] << 24) | ((ulong)Data[Offset + 4] << 32) | ((ulong)Data[Offset + 5] << 40) | ((ulong)Data[Offset + 6] << 48) | ((ulong)Data[Offset + 7] << 56);
|
||||
}
|
||||
|
||||
public static ulong ReadU64BE(byte[] Data, int Offset)
|
||||
{
|
||||
return ((ulong)Data[Offset] << 56) | ((ulong)Data[Offset + 1] << 48) | ((ulong)Data[Offset + 2] << 40) | ((ulong)Data[Offset + 3] << 32) | ((ulong)Data[Offset + 4] << 24) | ((ulong)Data[Offset + 5] << 16) | ((ulong)Data[Offset + 6] << 8) | ((ulong)Data[Offset + 7] << 0);
|
||||
}
|
||||
|
||||
public static void WriteU64LE(byte[] Data, int Offset, ulong Value)
|
||||
{
|
||||
Data[Offset] = (byte)(Value & 0xFF);
|
||||
Data[Offset + 1] = (byte)((Value >> 8) & 0xFF);
|
||||
Data[Offset + 2] = (byte)((Value >> 16) & 0xFF);
|
||||
Data[Offset + 3] = (byte)((Value >> 24) & 0xFF);
|
||||
Data[Offset + 4] = (byte)((Value >> 32) & 0xFF);
|
||||
Data[Offset + 5] = (byte)((Value >> 40) & 0xFF);
|
||||
Data[Offset + 6] = (byte)((Value >> 48) & 0xFF);
|
||||
Data[Offset + 7] = (byte)((Value >> 56) & 0xFF);
|
||||
}
|
||||
|
||||
public static void WriteSingleLE(byte[] Data, int Offset, float Value)
|
||||
{
|
||||
byte[] a = BitConverter.GetBytes(Value);
|
||||
Data[0 + Offset] = a[0];
|
||||
Data[1 + Offset] = a[1];
|
||||
Data[2 + Offset] = a[2];
|
||||
Data[3 + Offset] = a[3];
|
||||
}
|
||||
}
|
||||
}
|
235
dspatch/IO/SFSDirectory.cs
Normal file
235
dspatch/IO/SFSDirectory.cs
Normal file
@ -0,0 +1,235 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace dspatch.IO
|
||||
{
|
||||
public class SFSDirectory
|
||||
{
|
||||
public SFSDirectory(string Name, bool Root)
|
||||
{
|
||||
DirectoryName = Name;
|
||||
IsRoot = Root;
|
||||
SubDirectories = new List<SFSDirectory>();
|
||||
Files = new List<SFSFile>();
|
||||
}
|
||||
public SFSDirectory(UInt16 Id)
|
||||
{
|
||||
DirectoryID = Id;
|
||||
IsRoot = false;
|
||||
SubDirectories = new List<SFSDirectory>();
|
||||
Files = new List<SFSFile>();
|
||||
}
|
||||
|
||||
public static SFSDirectory FromDirectory(String Path)
|
||||
{
|
||||
SFSDirectory Root = new SFSDirectory("/", true);
|
||||
FillSFSDirFromDisk(new DirectoryInfo(Path), Root);
|
||||
return Root;
|
||||
}
|
||||
|
||||
private static void FillSFSDirFromDisk(DirectoryInfo Dir, SFSDirectory Dst)
|
||||
{
|
||||
foreach (var v in Dir.EnumerateFiles())
|
||||
{
|
||||
Dst.Files.Add(new SFSFile(-1, v.Name, Dst) { Data = File.ReadAllBytes(v.FullName) });
|
||||
}
|
||||
foreach (var v in Dir.EnumerateDirectories())
|
||||
{
|
||||
SFSDirectory d = new SFSDirectory(v.Name, false) { Parent = Dst };
|
||||
Dst.SubDirectories.Add(d);
|
||||
FillSFSDirFromDisk(v, d);
|
||||
}
|
||||
}
|
||||
|
||||
public String DirectoryName;
|
||||
public UInt16 DirectoryID;
|
||||
|
||||
public SFSDirectory Parent;
|
||||
|
||||
public List<SFSDirectory> SubDirectories;
|
||||
public List<SFSFile> Files;
|
||||
|
||||
public Boolean IsRoot { get; set; }
|
||||
|
||||
public SFSFile this[string index]
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (SFSFile f in Files)
|
||||
{
|
||||
if (f.FileName == index) return f;
|
||||
}
|
||||
return null;
|
||||
//throw new FileNotFoundException("The file " + index + " does not exist in this directory.");
|
||||
}
|
||||
set
|
||||
{
|
||||
for (int i = 0; i < Files.Count; i++)
|
||||
{
|
||||
if (Files[i].FileName == index)
|
||||
{
|
||||
Files[i] = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new System.IO.FileNotFoundException("The file " + index + " does not exist in this directory.");
|
||||
}
|
||||
}
|
||||
|
||||
public UInt32 TotalNrSubDirectories
|
||||
{
|
||||
get
|
||||
{
|
||||
UInt32 nr = (UInt32)SubDirectories.Count;
|
||||
foreach (SFSDirectory d in SubDirectories) nr += d.TotalNrSubDirectories;
|
||||
return nr;
|
||||
}
|
||||
}
|
||||
|
||||
public UInt32 TotalNrSubFiles
|
||||
{
|
||||
get
|
||||
{
|
||||
UInt32 nr = (UInt32)Files.Count;
|
||||
foreach (SFSDirectory d in SubDirectories) nr += d.TotalNrSubFiles;
|
||||
return nr;
|
||||
}
|
||||
}
|
||||
|
||||
public SFSFile GetFileByID(int Id)
|
||||
{
|
||||
foreach (SFSFile f in Files)
|
||||
{
|
||||
if (f.FileID == Id) return f;
|
||||
}
|
||||
foreach (SFSDirectory d in SubDirectories)
|
||||
{
|
||||
SFSFile f = d.GetFileByID(Id);
|
||||
if (f != null) return f;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public SFSDirectory GetDirectoryByPath(String Path)
|
||||
{
|
||||
if (Path.TrimStart('/').StartsWith("../"))
|
||||
{
|
||||
if (Parent == null) return null;
|
||||
return Parent.GetDirectoryByPath("/" + Path.TrimStart('/').Substring(2));
|
||||
}
|
||||
if (!Path.StartsWith(DirectoryName)) return null;
|
||||
if (Path == DirectoryName) return this;
|
||||
Path = Path.Substring(DirectoryName.Length);
|
||||
if (Path.Length == 0 || !Path.StartsWith("/")) return null;
|
||||
String dir = Path.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries)[0];
|
||||
foreach(var v in SubDirectories)
|
||||
{
|
||||
if(v.DirectoryName == dir) return v.GetDirectoryByPath(Path.Substring(1));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public SFSFile GetFileByPath(String Path)
|
||||
{
|
||||
if (Path.TrimStart('/').StartsWith("../"))
|
||||
{
|
||||
if (Parent == null) return null;
|
||||
return Parent.GetFileByPath("/" + Path.TrimStart('/').Substring(2));
|
||||
}
|
||||
if (!Path.StartsWith(DirectoryName)) return null;
|
||||
Path = Path.Substring(DirectoryName.Length);
|
||||
if (Path.Length == 0 || !Path.StartsWith("/")) return null;
|
||||
//Sarc files may use slashes in their names (since they are just hashes, and do not have a real directory structure)
|
||||
var vvv = this[Path.Substring(1)];
|
||||
if (vvv != null) return vvv;
|
||||
|
||||
string[] parts = Path.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (parts.Length > 1)
|
||||
{
|
||||
String dir = parts[0];
|
||||
foreach (var v in SubDirectories)
|
||||
{
|
||||
if (v.DirectoryName == dir) return v.GetFileByPath(Path.Substring(1));
|
||||
}
|
||||
}
|
||||
else if(parts.Length == 1)
|
||||
{
|
||||
return this[parts[0]];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void UpdateIDs(ref int DirId, ref int FileID)
|
||||
{
|
||||
this.DirectoryID = (ushort)(0xF000 | DirId++);
|
||||
foreach (var v in Files)
|
||||
{
|
||||
v.FileID = FileID++;
|
||||
}
|
||||
foreach (var v in SubDirectories)
|
||||
{
|
||||
v.UpdateIDs(ref DirId, ref FileID);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsValidName(String Name)
|
||||
{
|
||||
char[] invalid = System.IO.Path.GetInvalidFileNameChars();
|
||||
foreach (char c in invalid)
|
||||
{
|
||||
if (Name.Contains(c)) return false;
|
||||
}
|
||||
foreach (var v in SubDirectories)
|
||||
{
|
||||
if (v.DirectoryName == Name) return false;
|
||||
}
|
||||
foreach (var v in Files)
|
||||
{
|
||||
if (v.FileName == Name) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void PrintTree(ref int indent)
|
||||
{
|
||||
Console.WriteLine(new string(' ', indent * 4) + DirectoryName + " (" + DirectoryID.ToString("X") + ")");
|
||||
indent++;
|
||||
foreach (var v in Files)
|
||||
{
|
||||
Console.WriteLine(new string(' ', indent * 4) + v.FileName + " (" + v.FileID.ToString("X") + ")");
|
||||
}
|
||||
foreach (var v in SubDirectories)
|
||||
{
|
||||
v.PrintTree(ref indent);
|
||||
}
|
||||
indent--;
|
||||
}
|
||||
|
||||
public void Export(String Path)
|
||||
{
|
||||
foreach (var v in Files)
|
||||
{
|
||||
System.IO.File.Create(Path + "\\" + v.FileName).Close();
|
||||
System.IO.File.WriteAllBytes(Path + "\\" + v.FileName, v.Data);
|
||||
}
|
||||
foreach (var v in SubDirectories)
|
||||
{
|
||||
System.IO.Directory.CreateDirectory(Path + "\\" + v.DirectoryName);
|
||||
v.Export(Path + "\\" + v.DirectoryName);
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (Parent != this)
|
||||
{
|
||||
if (!IsRoot) return Parent.ToString() + DirectoryName + "/";
|
||||
else return "/";
|
||||
}
|
||||
else return DirectoryName;
|
||||
}
|
||||
}
|
||||
}
|
27
dspatch/IO/SFSFile.cs
Normal file
27
dspatch/IO/SFSFile.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace dspatch.IO
|
||||
{
|
||||
public class SFSFile
|
||||
{
|
||||
public SFSFile(Int32 Id, String Name, SFSDirectory Parent)
|
||||
{
|
||||
FileID = Id;
|
||||
FileName = Name;
|
||||
this.Parent = Parent;
|
||||
}
|
||||
public String FileName;
|
||||
public Int32 FileID;
|
||||
public Byte[] Data;
|
||||
|
||||
public SFSDirectory Parent;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Parent.ToString() + FileName;
|
||||
}
|
||||
}
|
||||
}
|
171
dspatch/Nitro/ARM9.cs
Normal file
171
dspatch/Nitro/ARM9.cs
Normal file
@ -0,0 +1,171 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using dspatch.IO;
|
||||
|
||||
namespace dspatch.Nitro
|
||||
{
|
||||
public class ARM9
|
||||
{
|
||||
private UInt32 RamAddress;
|
||||
|
||||
private byte[] StaticData;
|
||||
|
||||
private UInt32 _start_ModuleParamsOffset;
|
||||
private CRT0.ModuleParams _start_ModuleParams;
|
||||
|
||||
private List<CRT0.AutoLoadEntry> AutoLoadList;
|
||||
|
||||
public ARM9(byte[] Data, UInt32 RamAddress)
|
||||
: this(Data, RamAddress, FindModuleParams(Data)) { }
|
||||
|
||||
public ARM9(byte[] Data, UInt32 RamAddress, UInt32 _start_ModuleParamsOffset)
|
||||
{
|
||||
//Unimportant static footer! Use it for _start_ModuleParamsOffset and remove it.
|
||||
if (IOUtil.ReadU32LE(Data, Data.Length - 12) == 0xDEC00621)
|
||||
{
|
||||
_start_ModuleParamsOffset = IOUtil.ReadU32LE(Data, Data.Length - 8);
|
||||
byte[] data_tmp = new byte[Data.Length - 12];
|
||||
Array.Copy(Data, data_tmp, Data.Length - 12);
|
||||
Data = data_tmp;
|
||||
}
|
||||
|
||||
this.RamAddress = RamAddress;
|
||||
this._start_ModuleParamsOffset = _start_ModuleParamsOffset;
|
||||
_start_ModuleParams = new CRT0.ModuleParams(Data, _start_ModuleParamsOffset);
|
||||
if (_start_ModuleParams.CompressedStaticEnd != 0)
|
||||
{
|
||||
Data = Decompress(Data, _start_ModuleParamsOffset);
|
||||
_start_ModuleParams = new CRT0.ModuleParams(Data, _start_ModuleParamsOffset);
|
||||
}
|
||||
|
||||
StaticData = new byte[_start_ModuleParams.AutoLoadStart - RamAddress];
|
||||
Array.Copy(Data, StaticData, _start_ModuleParams.AutoLoadStart - RamAddress);
|
||||
|
||||
AutoLoadList = new List<CRT0.AutoLoadEntry>();
|
||||
uint nr = (_start_ModuleParams.AutoLoadListEnd - _start_ModuleParams.AutoLoadListOffset) / 0xC;
|
||||
uint Offset = _start_ModuleParams.AutoLoadStart - RamAddress;
|
||||
for (int i = 0; i < nr; i++)
|
||||
{
|
||||
var entry = new CRT0.AutoLoadEntry(Data, _start_ModuleParams.AutoLoadListOffset - RamAddress + (uint)i * 0xC);
|
||||
entry.Data = new byte[entry.Size];
|
||||
Array.Copy(Data, Offset, entry.Data, 0, entry.Size);
|
||||
AutoLoadList.Add(entry);
|
||||
Offset += entry.Size;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] Write()
|
||||
{
|
||||
MemoryStream m = new MemoryStream();
|
||||
EndianBinaryWriter er = new EndianBinaryWriter(m, Endianness.LittleEndian);
|
||||
er.Write(StaticData, 0, StaticData.Length);
|
||||
_start_ModuleParams.AutoLoadStart = (uint)er.BaseStream.Position + RamAddress;
|
||||
foreach (var v in AutoLoadList) er.Write(v.Data, 0, v.Data.Length);
|
||||
_start_ModuleParams.AutoLoadListOffset = (uint)er.BaseStream.Position + RamAddress;
|
||||
foreach (var v in AutoLoadList) v.Write(er);
|
||||
_start_ModuleParams.AutoLoadListEnd = (uint)er.BaseStream.Position + RamAddress;
|
||||
long curpos = er.BaseStream.Position;
|
||||
er.BaseStream.Position = _start_ModuleParamsOffset;
|
||||
_start_ModuleParams.Write(er);
|
||||
er.BaseStream.Position = curpos;
|
||||
byte[] data = m.ToArray();
|
||||
er.Close();
|
||||
return data;
|
||||
}
|
||||
|
||||
public void AddAutoLoadEntry(UInt32 Address, byte[] Data)
|
||||
{
|
||||
AutoLoadList.Add(new CRT0.AutoLoadEntry(Address, Data));
|
||||
}
|
||||
|
||||
public bool WriteU16LE(UInt32 Address, UInt16 Value)
|
||||
{
|
||||
if (Address > RamAddress && Address < _start_ModuleParams.AutoLoadStart)
|
||||
{
|
||||
IOUtil.WriteU16LE(StaticData, (int)(Address - RamAddress), Value);
|
||||
return true;
|
||||
}
|
||||
foreach (var v in AutoLoadList)
|
||||
{
|
||||
if (Address > v.Address && Address < (v.Address + v.Size))
|
||||
{
|
||||
IOUtil.WriteU16LE(v.Data, (int)(Address - v.Address), Value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public UInt32 ReadU32LE(UInt32 Address)
|
||||
{
|
||||
if (Address > RamAddress && Address < _start_ModuleParams.AutoLoadStart)
|
||||
{
|
||||
return IOUtil.ReadU32LE(StaticData, (int)(Address - RamAddress));
|
||||
}
|
||||
foreach (var v in AutoLoadList)
|
||||
{
|
||||
if (Address > v.Address && Address < (v.Address + v.Size))
|
||||
{
|
||||
return IOUtil.ReadU32LE(v.Data, (int)(Address - v.Address));
|
||||
}
|
||||
}
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
public bool WriteU32LE(UInt32 Address, UInt32 Value)
|
||||
{
|
||||
if (Address > RamAddress && Address < _start_ModuleParams.AutoLoadStart)
|
||||
{
|
||||
IOUtil.WriteU32LE(StaticData, (int)(Address - RamAddress), Value);
|
||||
return true;
|
||||
}
|
||||
foreach (var v in AutoLoadList)
|
||||
{
|
||||
if (Address > v.Address && Address < (v.Address + v.Size))
|
||||
{
|
||||
IOUtil.WriteU32LE(v.Data, (int)(Address - v.Address), Value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static byte[] Decompress(byte[] Data)
|
||||
{
|
||||
uint offset = FindModuleParams(Data);
|
||||
if (offset == 0xffffffe3) return Data;//no moduleparams, so it must be uncompressed
|
||||
return Decompress(Data, offset);
|
||||
}
|
||||
|
||||
public static byte[] Decompress(byte[] Data, UInt32 _start_ModuleParamsOffset)
|
||||
{
|
||||
if (IOUtil.ReadU32LE(Data, (int)_start_ModuleParamsOffset + 0x14) == 0) return Data;//Not Compressed!
|
||||
byte[] Result = CRT0.MIi_UncompressBackward(Data);
|
||||
IOUtil.WriteU32LE(Result, (int)_start_ModuleParamsOffset + 0x14, 0);
|
||||
return Result;
|
||||
}
|
||||
|
||||
private static uint FindModuleParams(byte[] Data)
|
||||
{
|
||||
return (uint)IndexOf(Data, new byte[] { 0x21, 0x06, 0xC0, 0xDE, 0xDE, 0xC0, 0x06, 0x21 }) - 0x1C;
|
||||
}
|
||||
|
||||
private static unsafe long IndexOf(byte[] Data, byte[] Search)
|
||||
{
|
||||
fixed (byte* H = Data) fixed (byte* N = Search)
|
||||
{
|
||||
long i = 0;
|
||||
for (byte* hNext = H, hEnd = H + Data.LongLength; hNext < hEnd; i++, hNext++)
|
||||
{
|
||||
bool Found = true;
|
||||
for (byte* hInc = hNext, nInc = N, nEnd = N + Search.LongLength; Found && nInc < nEnd; Found = *nInc == *hInc, nInc++, hInc++) ;
|
||||
if (Found) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
62
dspatch/Nitro/CRC16.cs
Normal file
62
dspatch/Nitro/CRC16.cs
Normal file
@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace dspatch.Nitro
|
||||
{
|
||||
public class CRC16
|
||||
{
|
||||
private readonly static ushort[] CRC16Table =
|
||||
{
|
||||
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
|
||||
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
|
||||
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
|
||||
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
|
||||
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
|
||||
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
|
||||
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
|
||||
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
|
||||
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
|
||||
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
|
||||
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
|
||||
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
|
||||
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
|
||||
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
|
||||
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
|
||||
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
|
||||
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
|
||||
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
|
||||
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
|
||||
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
|
||||
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
|
||||
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
|
||||
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
|
||||
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
|
||||
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
|
||||
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
|
||||
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
|
||||
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
|
||||
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
|
||||
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
|
||||
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
|
||||
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
|
||||
};
|
||||
|
||||
public static ushort GetCRC16(byte[] Data)
|
||||
{
|
||||
return GetCRC16(Data, 0, Data.Length);
|
||||
}
|
||||
|
||||
|
||||
public static ushort GetCRC16(byte[] Data, int start, int length)
|
||||
{
|
||||
ushort result = 0xFFFF;
|
||||
for (int i = start; i < start + length; i++)
|
||||
{
|
||||
result = (ushort)((result >> 8) ^ CRC16Table[(result ^ Data[i]) & 0xFF]);
|
||||
}
|
||||
return (ushort)result;
|
||||
}
|
||||
}
|
||||
}
|
110
dspatch/Nitro/CRT0.cs
Normal file
110
dspatch/Nitro/CRT0.cs
Normal file
@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using dspatch.IO;
|
||||
|
||||
namespace dspatch.Nitro
|
||||
{
|
||||
public class CRT0
|
||||
{
|
||||
public class ModuleParams
|
||||
{
|
||||
public ModuleParams(byte[] Data, uint Offset)
|
||||
{
|
||||
AutoLoadListOffset = IOUtil.ReadU32LE(Data, (int)Offset + 0);
|
||||
AutoLoadListEnd = IOUtil.ReadU32LE(Data, (int)Offset + 4);
|
||||
AutoLoadStart = IOUtil.ReadU32LE(Data, (int)Offset + 8);
|
||||
StaticBssStart = IOUtil.ReadU32LE(Data, (int)Offset + 12);
|
||||
StaticBssEnd = IOUtil.ReadU32LE(Data, (int)Offset + 16);
|
||||
CompressedStaticEnd = IOUtil.ReadU32LE(Data, (int)Offset + 20);
|
||||
SDKVersion = IOUtil.ReadU32LE(Data, (int)Offset + 24);
|
||||
NitroCodeBE = IOUtil.ReadU32LE(Data, (int)Offset + 28);
|
||||
NitroCodeLE = IOUtil.ReadU32LE(Data, (int)Offset + 32);
|
||||
}
|
||||
public void Write(EndianBinaryWriter er)
|
||||
{
|
||||
er.Write(AutoLoadListOffset);
|
||||
er.Write(AutoLoadListEnd);
|
||||
er.Write(AutoLoadStart);
|
||||
er.Write(StaticBssStart);
|
||||
er.Write(StaticBssEnd);
|
||||
er.Write(CompressedStaticEnd);
|
||||
er.Write(SDKVersion);
|
||||
er.Write(NitroCodeBE);
|
||||
er.Write(NitroCodeLE);
|
||||
}
|
||||
public UInt32 AutoLoadListOffset;
|
||||
public UInt32 AutoLoadListEnd;
|
||||
public UInt32 AutoLoadStart;
|
||||
public UInt32 StaticBssStart;
|
||||
public UInt32 StaticBssEnd;
|
||||
public UInt32 CompressedStaticEnd;
|
||||
public UInt32 SDKVersion;
|
||||
public UInt32 NitroCodeBE;
|
||||
public UInt32 NitroCodeLE;
|
||||
}
|
||||
|
||||
public class AutoLoadEntry
|
||||
{
|
||||
public AutoLoadEntry(UInt32 Address, byte[] Data)
|
||||
{
|
||||
this.Address = Address;
|
||||
this.Data = Data;
|
||||
Size = (uint)Data.Length;
|
||||
BssSize = 0;
|
||||
}
|
||||
public AutoLoadEntry(byte[] Data, uint Offset)
|
||||
{
|
||||
Address = IOUtil.ReadU32LE(Data, (int)Offset + 0);
|
||||
Size = IOUtil.ReadU32LE(Data, (int)Offset + 4);
|
||||
BssSize = IOUtil.ReadU32LE(Data, (int)Offset + 8);
|
||||
}
|
||||
public void Write(EndianBinaryWriter er)
|
||||
{
|
||||
er.Write(Address);
|
||||
er.Write(Size);
|
||||
er.Write(BssSize);
|
||||
}
|
||||
public UInt32 Address;
|
||||
public UInt32 Size;
|
||||
public UInt32 BssSize;
|
||||
|
||||
public byte[] Data;
|
||||
}
|
||||
|
||||
public static byte[] MIi_UncompressBackward(byte[] Data)
|
||||
{
|
||||
UInt32 leng = IOUtil.ReadU32LE(Data, Data.Length - 4) + (uint)Data.Length;
|
||||
byte[] Result = new byte[leng];
|
||||
Array.Copy(Data, Result, Data.Length);
|
||||
int Offs = (int)(Data.Length - (IOUtil.ReadU32LE(Data, Data.Length - 8) >> 24));
|
||||
int dstoffs = (int)leng;
|
||||
while (true)
|
||||
{
|
||||
byte header = Result[--Offs];
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if ((header & 0x80) == 0) Result[--dstoffs] = Result[--Offs];
|
||||
else
|
||||
{
|
||||
byte a = Result[--Offs];
|
||||
byte b = Result[--Offs];
|
||||
int offs = (((a & 0xF) << 8) | b) + 2;//+ 1;
|
||||
int length = (a >> 4) + 2;
|
||||
do
|
||||
{
|
||||
Result[dstoffs - 1] = Result[dstoffs + offs];
|
||||
dstoffs--;
|
||||
length--;
|
||||
}
|
||||
while (length >= 0);
|
||||
}
|
||||
if (Offs <= (Data.Length - (IOUtil.ReadU32LE(Data, Data.Length - 8) & 0xFFFFFF))) return Result;
|
||||
header <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
719
dspatch/Nitro/NDS.cs
Normal file
719
dspatch/Nitro/NDS.cs
Normal file
@ -0,0 +1,719 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using dspatch.IO;
|
||||
using System.Xml.Serialization;
|
||||
using System.Xml;
|
||||
|
||||
namespace dspatch.Nitro
|
||||
{
|
||||
public class NDS
|
||||
{
|
||||
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 byte[] Write(bool multiboot = false)
|
||||
{
|
||||
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;
|
||||
if (!multiboot)
|
||||
{
|
||||
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);
|
||||
}
|
||||
else
|
||||
Header.DeviceSize = 0x0B;
|
||||
//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 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);
|
||||
}
|
||||
}
|
||||
}
|
165
dspatch/Nitro/NitroFS.cs
Normal file
165
dspatch/Nitro/NitroFS.cs
Normal file
@ -0,0 +1,165 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using dspatch.IO;
|
||||
|
||||
namespace dspatch.Nitro
|
||||
{
|
||||
public class FileAllocationEntry
|
||||
{
|
||||
public FileAllocationEntry(UInt32 Offset, UInt32 Size)
|
||||
{
|
||||
fileTop = Offset;
|
||||
fileBottom = Offset + Size;
|
||||
}
|
||||
public FileAllocationEntry(EndianBinaryReader er)
|
||||
{
|
||||
fileTop = er.ReadUInt32();
|
||||
fileBottom = er.ReadUInt32();
|
||||
}
|
||||
public void Write(EndianBinaryWriter er)
|
||||
{
|
||||
er.Write(fileTop);
|
||||
er.Write(fileBottom);
|
||||
}
|
||||
public UInt32 fileTop;
|
||||
public UInt32 fileBottom;
|
||||
|
||||
public UInt32 fileSize
|
||||
{
|
||||
get { return fileBottom - fileTop; }
|
||||
}
|
||||
}
|
||||
public class DirectoryTableEntry
|
||||
{
|
||||
public DirectoryTableEntry() { }
|
||||
public DirectoryTableEntry(EndianBinaryReader er)
|
||||
{
|
||||
dirEntryStart = er.ReadUInt32();
|
||||
dirEntryFileID = er.ReadUInt16();
|
||||
dirParentID = er.ReadUInt16();
|
||||
}
|
||||
public void Write(EndianBinaryWriter er)
|
||||
{
|
||||
er.Write(dirEntryStart);
|
||||
er.Write(dirEntryFileID);
|
||||
er.Write(dirParentID);
|
||||
}
|
||||
public UInt32 dirEntryStart;
|
||||
public UInt16 dirEntryFileID;
|
||||
public UInt16 dirParentID;
|
||||
}
|
||||
public class EntryNameTableEntry
|
||||
{
|
||||
protected EntryNameTableEntry() { }
|
||||
public EntryNameTableEntry(EndianBinaryReader er)
|
||||
{
|
||||
entryNameLength = er.ReadByte();
|
||||
}
|
||||
public virtual void Write(EndianBinaryWriter er)
|
||||
{
|
||||
er.Write(entryNameLength);
|
||||
}
|
||||
public Byte entryNameLength;
|
||||
}
|
||||
public class EntryNameTableEndOfDirectoryEntry : EntryNameTableEntry
|
||||
{
|
||||
public EntryNameTableEndOfDirectoryEntry() { }
|
||||
public EntryNameTableEndOfDirectoryEntry(EndianBinaryReader er)
|
||||
: base(er) { }
|
||||
public override void Write(EndianBinaryWriter er)
|
||||
{
|
||||
base.Write(er);
|
||||
}
|
||||
}
|
||||
public class EntryNameTableFileEntry : EntryNameTableEntry
|
||||
{
|
||||
public EntryNameTableFileEntry(String Name)
|
||||
{
|
||||
entryNameLength = (byte)Name.Length;
|
||||
entryName = Name;
|
||||
}
|
||||
public EntryNameTableFileEntry(EndianBinaryReader er)
|
||||
: base(er)
|
||||
{
|
||||
entryName = er.ReadString(Encoding.ASCII, entryNameLength);
|
||||
}
|
||||
public override void Write(EndianBinaryWriter er)
|
||||
{
|
||||
base.Write(er);
|
||||
er.Write(entryName, Encoding.ASCII, false);
|
||||
}
|
||||
public String entryName;
|
||||
}
|
||||
public class EntryNameTableDirectoryEntry : EntryNameTableEntry
|
||||
{
|
||||
public EntryNameTableDirectoryEntry(String Name, UInt16 DirectoryID)
|
||||
{
|
||||
entryNameLength = (byte)(Name.Length | 0x80);
|
||||
entryName = Name;
|
||||
directoryID = DirectoryID;
|
||||
}
|
||||
public EntryNameTableDirectoryEntry(EndianBinaryReader er)
|
||||
: base(er)
|
||||
{
|
||||
entryName = er.ReadString(Encoding.ASCII, entryNameLength & 0x7F);
|
||||
directoryID = er.ReadUInt16();
|
||||
}
|
||||
public override void Write(EndianBinaryWriter er)
|
||||
{
|
||||
base.Write(er);
|
||||
er.Write(entryName, Encoding.ASCII, false);
|
||||
er.Write(directoryID);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
360
dspatch/Program.cs
Normal file
360
dspatch/Program.cs
Normal file
@ -0,0 +1,360 @@
|
||||
using dspatch.DS;
|
||||
using dspatch.IO;
|
||||
using dspatch.Nitro;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace dspatch
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static byte[] lockIconImage =
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x8A,
|
||||
0x00, 0xA0, 0x88, 0x88, 0x00, 0x88, 0x57, 0x34, 0x80, 0x58, 0x33, 0x33,
|
||||
0x8A, 0x34, 0x04, 0x00, 0xA0, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xA8, 0x0A, 0x00, 0x00, 0x88, 0x88, 0x0A, 0x00,
|
||||
0x43, 0x75, 0x88, 0x00, 0x33, 0x33, 0x85, 0x08, 0x00, 0x40, 0x43, 0x88,
|
||||
0x00, 0x00, 0x37, 0x85, 0x00, 0x00, 0x40, 0x73, 0x00, 0x00, 0x00, 0x53,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x33,
|
||||
0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x33,
|
||||
0x00, 0x00, 0x00, 0x33, 0xDD, 0xDD, 0xDD, 0xDD, 0xA8, 0x00, 0x00, 0x00,
|
||||
0x88, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00,
|
||||
0x88, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00,
|
||||
0xDD, 0xED, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0x29, 0xFF, 0xFF, 0xBF, 0x11, 0xFF, 0xFF, 0x9F, 0x11,
|
||||
0xFF, 0xFF, 0xBF, 0x11, 0xFF, 0xFF, 0xFF, 0x16, 0xDD, 0xDD, 0xDD, 0xDD,
|
||||
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0x92, 0xDD, 0xDD, 0xDD,
|
||||
0x11, 0xDB, 0xDD, 0xDD, 0x11, 0xD9, 0xDD, 0xDD, 0x11, 0xDB, 0xDD, 0xDD,
|
||||
0x61, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0x00, 0x00, 0xDD, 0xDD, 0x00, 0x00,
|
||||
0xDD, 0xDD, 0x00, 0x00, 0xDD, 0xDD, 0x00, 0x00, 0xDD, 0xDD, 0x00, 0x00,
|
||||
0xDD, 0xDD, 0x00, 0x00, 0xDD, 0xDD, 0x00, 0x00, 0xDD, 0xDD, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x16,
|
||||
0xFF, 0xFF, 0xFF, 0x12, 0xFF, 0xFF, 0xCF, 0x11, 0xFF, 0xFF, 0x9F, 0x11,
|
||||
0xFF, 0xFF, 0x9F, 0x11, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0x61, 0xDD, 0xDD, 0xDD, 0x21, 0xDD, 0xDD, 0xDD,
|
||||
0x11, 0xDB, 0xDD, 0xDD, 0x11, 0xD9, 0xDD, 0xDD, 0x11, 0xD9, 0xDD, 0xDD,
|
||||
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
|
||||
0xDD, 0xDD, 0x00, 0x00, 0xDD, 0xDD, 0x00, 0x00, 0xDD, 0xDD, 0x00, 0x00,
|
||||
0xDD, 0xDD, 0x00, 0x00, 0xDD, 0xDD, 0x00, 0x00, 0xDD, 0xDD, 0x00, 0x00,
|
||||
0xDD, 0xDD, 0x00, 0x00, 0xDD, 0xED, 0x00, 0x00
|
||||
};
|
||||
|
||||
static byte[] lockIconPltt =
|
||||
{
|
||||
0x1C, 0x3C, 0x07, 0x25, 0x49, 0x25, 0xAA, 0x3D, 0xCB, 0x3D, 0xEC, 0x41,
|
||||
0xEF, 0x25, 0x0E, 0x4A, 0x2F, 0x4E, 0x74, 0x26, 0x71, 0x56, 0xF9, 0x2A,
|
||||
0x5B, 0x2F, 0x5E, 0x1B, 0x7E, 0x37, 0xBF, 0x2F
|
||||
};
|
||||
|
||||
static byte[] haxxStationIconImage =
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x90, 0x61, 0x66, 0x66, 0x69, 0x66, 0x66, 0x66, 0x61, 0xC8, 0xCC, 0xCC,
|
||||
0x66, 0xCC, 0xCC, 0x6C, 0x66, 0xCC, 0xCC, 0x6C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0xCC, 0xCC, 0xCC, 0xCC, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x16, 0x09, 0x66, 0x66, 0x66, 0x96,
|
||||
0xCC, 0xCC, 0x8C, 0x16, 0xC6, 0xCC, 0xCC, 0x66, 0xC6, 0xCC, 0xCC, 0x66,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0xCC, 0xCC, 0x6C,
|
||||
0x66, 0xCC, 0xCC, 0x6C, 0x66, 0xCC, 0xCC, 0x6C, 0x66, 0xCC, 0xCC, 0x6C,
|
||||
0x66, 0xCC, 0xCC, 0x6C, 0x66, 0x8C, 0xCC, 0x6C, 0x45, 0x65, 0x41, 0x85,
|
||||
0x89, 0xE2, 0xC0, 0x27, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x27, 0x16, 0x54, 0xB7, 0xD5, 0xE0, 0x9D, 0x14,
|
||||
0xC6, 0xCC, 0xCC, 0x66, 0xC6, 0xCC, 0xCC, 0x66, 0xC6, 0xCC, 0xCC, 0x66,
|
||||
0xC6, 0xCC, 0xCC, 0x66, 0xC6, 0xCC, 0xCC, 0x66, 0xC6, 0x99, 0xCC, 0x66,
|
||||
0x5C, 0x11, 0xC5, 0x66, 0x42, 0xEE, 0x24, 0x44, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x20, 0x0E, 0x00,
|
||||
0x00, 0x79, 0x00, 0x0B, 0x00, 0x01, 0x70, 0x08, 0xD0, 0x04, 0x2E, 0x00,
|
||||
0xB0, 0x07, 0x5D, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0x00, 0x77, 0x0C,
|
||||
0x24, 0x87, 0x52, 0x14, 0x66, 0x14, 0xC9, 0x6C, 0x66, 0xAC, 0xCC, 0x6C,
|
||||
0x66, 0xCC, 0xC1, 0x6C, 0x66, 0x1C, 0x16, 0x6C, 0x66, 0xCC, 0xC1, 0x6C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x80, 0x21, 0xA7, 0x00, 0x41, 0x88, 0x47, 0x41,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xF3, 0x63, 0x66, 0x66,
|
||||
0x36, 0x3F, 0x66, 0x66, 0x36, 0x3F, 0x66, 0x66, 0x0D, 0x00, 0xD0, 0x99,
|
||||
0x00, 0x88, 0x00, 0x00, 0x18, 0x44, 0x81, 0x99, 0x76, 0xCC, 0x57, 0x44,
|
||||
0xC6, 0xCC, 0xCC, 0x66, 0xC6, 0x6C, 0xCC, 0x66, 0xC6, 0xC6, 0xC6, 0x66,
|
||||
0xC6, 0x6C, 0xCC, 0x66, 0x90, 0x09, 0x89, 0x00, 0xB0, 0x07, 0x4D, 0x00,
|
||||
0xD0, 0x04, 0x10, 0x00, 0x00, 0x01, 0x80, 0x05, 0x00, 0x78, 0x00, 0x0E,
|
||||
0x00, 0x10, 0x0D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x66, 0xCC, 0xCC, 0x6C, 0x66, 0xCC, 0xCC, 0x6C, 0x66, 0xCC, 0xCC, 0x6C,
|
||||
0x61, 0xC8, 0xCC, 0xCC, 0x68, 0x66, 0x66, 0x66, 0x80, 0x61, 0x66, 0x66,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF3, 0x63, 0xFF, 0x6F,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xCC, 0xCC, 0xCC, 0xCC,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xC6, 0xCC, 0xCC, 0x66, 0xC6, 0xCC, 0xCC, 0x66,
|
||||
0xC6, 0xCC, 0xCC, 0x66, 0xCC, 0xCC, 0x8C, 0x16, 0x66, 0x66, 0x66, 0x86,
|
||||
0x66, 0x66, 0x16, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static byte[] haxxStationIconPltt =
|
||||
{
|
||||
0x1F, 0x7C, 0x42, 0x04, 0x83, 0x0C, 0xC5, 0x08, 0xC6, 0x18, 0xE7, 0x1C,
|
||||
0x00, 0x00, 0x29, 0x25, 0x8C, 0x2D, 0xAD, 0x35, 0xCE, 0x39, 0x0F, 0x3E,
|
||||
0x10, 0x42, 0x51, 0x46, 0x94, 0x52, 0x35, 0x23
|
||||
};
|
||||
|
||||
static byte[] haxxStationServer =
|
||||
{
|
||||
0x52, 0x43, 0x31, 0x20, 0x32, 0x30, 0x30, 0x36, 0x20, 0x30, 0x31, 0x20,
|
||||
0x32, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x65, 0x72, 0x69,
|
||||
0x63, 0x6F, 0x6D, 0x00, 0x00, 0x00, 0x48, 0x61, 0x78, 0x78, 0x53, 0x74,
|
||||
0x61, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x79, 0x20, 0x47, 0x65, 0x72,
|
||||
0x69, 0x63, 0x6F, 0x6D, 0x2C, 0x20, 0x73, 0x68, 0x75, 0x74, 0x74, 0x65,
|
||||
0x72, 0x62, 0x75, 0x67, 0x32, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x6E, 0x64, 0x20, 0x41, 0x70,
|
||||
0x61, 0x63, 0x68, 0x65, 0x20, 0x54, 0x68, 0x75, 0x6E, 0x64, 0x65, 0x72,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static byte[] dsHash =
|
||||
{
|
||||
0xF1, 0x8B, 0x55, 0xF3, 0xE1, 0x25, 0x9C, 0x03, 0xE1, 0x0D, 0x0E, 0xCB,
|
||||
0x54, 0x96, 0x93, 0xB4, 0x29, 0x05, 0xCE, 0xB5
|
||||
};
|
||||
|
||||
static byte[] exploitData =
|
||||
{
|
||||
0x44, 0x30, 0x9F, 0xE5, 0x2C, 0x00, 0x93, 0xE5, 0x2C, 0x10, 0x9F, 0xE5,
|
||||
0x01, 0x00, 0x40, 0xE0, 0x28, 0x10, 0x9F, 0xE5, 0x01, 0x00, 0x80, 0xE0,
|
||||
0x24, 0x10, 0x9F, 0xE5, 0x24, 0x20, 0x9F, 0xE5, 0x28, 0xE0, 0x9F, 0xE5,
|
||||
0x3E, 0xFF, 0x2F, 0xE1, 0x24, 0xE0, 0x9F, 0xE5, 0x3E, 0xFF, 0x2F, 0xE1,
|
||||
0x01, 0x00, 0xA0, 0xE3, 0x1C, 0xE0, 0x9F, 0xE5, 0x1E, 0xFF, 0x2F, 0xE1,
|
||||
0x00, 0xAE, 0x11, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||||
0x20, 0x6D, 0x11, 0x00, 0x40, 0xE8, 0x3F, 0x02, 0x08, 0xBB, 0x32, 0x02,
|
||||
0x24, 0xAF, 0x32, 0x02, 0x78, 0x3A, 0x32, 0x02
|
||||
};
|
||||
|
||||
static byte[] arm7Fix =
|
||||
{
|
||||
0x2C, 0x00, 0x9F, 0xE5, 0x8E, 0x07, 0x80, 0xE2, 0x1C, 0x10, 0x9F, 0xE5,
|
||||
0x1C, 0x20, 0x9F, 0xE5, 0x01, 0x30, 0xD0, 0xE4, 0x01, 0x30, 0xC1, 0xE4,
|
||||
0x01, 0x20, 0x52, 0xE2, 0xFB, 0xFF, 0xFF, 0xCA, 0x00, 0x00, 0x9F, 0xE5,
|
||||
0x10, 0xFF, 0x2F, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static void PrintUsage()
|
||||
{
|
||||
Console.WriteLine("Usage: dspatch download_station.nds rom_to_boot.nds result.nds");
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("== DS Download Station Patcher v1.0 ==");
|
||||
Console.WriteLine("Exploit by Gericom, shutterbug2000 and Apache Thunder\n");
|
||||
if (args.Length != 3)
|
||||
PrintUsage();
|
||||
else
|
||||
{
|
||||
byte[] dsdata = File.ReadAllBytes(args[0]);
|
||||
byte[] sha1 = SHA1.Create().ComputeHash(dsdata);
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
if (sha1[i] != dsHash[i])
|
||||
{
|
||||
Console.WriteLine("Error: Invalid download station rom!");
|
||||
Console.WriteLine("The patcher is only compatible with:");
|
||||
Console.WriteLine("xxxx - DS Download Station - Volume 1 (Kiosk WiFi Demo Cart) (U)(Independent).nds");
|
||||
Console.WriteLine("SHA1: F18B55F3E1259C03E10D0ECB549693B42905CEB5");
|
||||
return;
|
||||
}
|
||||
}
|
||||
NDS downloadStation = new NDS(dsdata);
|
||||
var fs = downloadStation.ToFileSystem();
|
||||
byte[] newRom = File.ReadAllBytes(args[1]);
|
||||
NDS newRom2 = new NDS(newRom);
|
||||
if (newRom2.Header.SubRamAddress >= 0x03000000)
|
||||
{
|
||||
byte[] newArm7 = new byte[newRom2.SubRom.Length + arm7Fix.Length];
|
||||
Array.Copy(arm7Fix, newArm7, arm7Fix.Length);
|
||||
Array.Copy(newRom2.SubRom, 0, newArm7, arm7Fix.Length, newRom2.SubRom.Length);
|
||||
IOUtil.WriteU32LE(newArm7, 0x28, newRom2.Header.SubEntryAddress);
|
||||
IOUtil.WriteU32LE(newArm7, 0x2C, newRom2.Header.SubRamAddress);
|
||||
IOUtil.WriteU32LE(newArm7, 0x30, newRom2.Header.SubSize);
|
||||
newRom2.SubRom = newArm7;
|
||||
newRom2.Header.SubSize = (uint)newArm7.Length;
|
||||
newRom2.Header.SubRamAddress = 0x02380000;
|
||||
newRom2.Header.SubEntryAddress = 0x02380000;
|
||||
}
|
||||
byte[] newRomFixed = newRom2.Write(true);
|
||||
{
|
||||
uint arm9offset = (uint)(newRomFixed[0x20] | (newRomFixed[0x21] << 8) | (newRomFixed[0x22] << 16) | (newRomFixed[0x23] << 24));
|
||||
uint arm9loadaddr = (uint)(newRomFixed[0x28] | (newRomFixed[0x29] << 8) | (newRomFixed[0x2A] << 16) | (newRomFixed[0x2B] << 24));
|
||||
uint arm9size = (uint)(newRomFixed[0x2C] | (newRomFixed[0x2D] << 8) | (newRomFixed[0x2E] << 16) | (newRomFixed[0x2F] << 24));
|
||||
uint arm7offset = (uint)(newRomFixed[0x30] | (newRomFixed[0x31] << 8) | (newRomFixed[0x32] << 16) | (newRomFixed[0x33] << 24));
|
||||
|
||||
//arm9 offset becomes 0x180
|
||||
newRomFixed[0x20] = 0x80;
|
||||
newRomFixed[0x21] = 0x01;
|
||||
newRomFixed[0x22] = 0x00;
|
||||
newRomFixed[0x23] = 0x00;
|
||||
//arm9 load becomes 0x02332C40 (rsa_GetDecodedHash)
|
||||
newRomFixed[0x28] = 0x40;
|
||||
newRomFixed[0x29] = 0x2C;
|
||||
newRomFixed[0x2A] = 0x33;
|
||||
newRomFixed[0x2B] = 0x02;
|
||||
//arm9 size becomes 0x100
|
||||
newRomFixed[0x2C] = 0x00;
|
||||
newRomFixed[0x2D] = 0x01;
|
||||
newRomFixed[0x2E] = 0x00;
|
||||
newRomFixed[0x2F] = 0x00;
|
||||
ushort newcrc = CRC16.GetCRC16(newRomFixed, 0, 0x15E);
|
||||
newRomFixed[0x15E] = (byte)(newcrc & 0xFF);
|
||||
newRomFixed[0x15F] = (byte)(newcrc >> 8);
|
||||
|
||||
exploitData[0x3C] = (byte)(arm7offset & 0xFF);
|
||||
exploitData[0x3D] = (byte)((arm7offset >> 8) & 0xFF);
|
||||
exploitData[0x3E] = (byte)((arm7offset >> 16) & 0xFF);
|
||||
exploitData[0x3F] = (byte)((arm7offset >> 24) & 0xFF);
|
||||
|
||||
exploitData[0x40] = (byte)(arm9offset & 0xFF);
|
||||
exploitData[0x41] = (byte)((arm9offset >> 8) & 0xFF);
|
||||
exploitData[0x42] = (byte)((arm9offset >> 16) & 0xFF);
|
||||
exploitData[0x43] = (byte)((arm9offset >> 24) & 0xFF);
|
||||
|
||||
exploitData[0x44] = (byte)(arm9loadaddr & 0xFF);
|
||||
exploitData[0x45] = (byte)((arm9loadaddr >> 8) & 0xFF);
|
||||
exploitData[0x46] = (byte)((arm9loadaddr >> 16) & 0xFF);
|
||||
exploitData[0x47] = (byte)((arm9loadaddr >> 24) & 0xFF);
|
||||
|
||||
exploitData[0x48] = (byte)(arm9size & 0xFF);
|
||||
exploitData[0x49] = (byte)((arm9size >> 8) & 0xFF);
|
||||
exploitData[0x4A] = (byte)((arm9size >> 16) & 0xFF);
|
||||
exploitData[0x4B] = (byte)((arm9size >> 24) & 0xFF);
|
||||
|
||||
Array.Copy(exploitData, 0, newRomFixed, 0x180, exploitData.Length);
|
||||
}
|
||||
SFSDirectory d = fs.GetDirectoryByPath("//ds_demo");
|
||||
d.Files.Add(new SFSFile(-1, "rom1.nds", d) { Data = newRomFixed });
|
||||
//this is shitty...
|
||||
d.Files.Remove(d.GetFileByPath("ds_demo/ANDEdemo"));
|
||||
d.Files.Remove(d.GetFileByPath("ds_demo/AGFEdemo"));
|
||||
d.Files.Remove(d.GetFileByPath("ds_demo/AMFEclip"));
|
||||
d.Files.Remove(d.GetFileByPath("ds_demo/AMTEdemo"));
|
||||
d.Files.Remove(d.GetFileByPath("ds_demo/APTEdemo"));
|
||||
d.Files.Remove(d.GetFileByPath("ds_demo/ATTEdemo"));
|
||||
d.Files.Remove(d.GetFileByPath("ds_demo/ATTEpush"));
|
||||
d.Files.Remove(d.GetFileByPath("ds_demo/testcode"));
|
||||
d.Files.Remove(d.GetFileByPath("ds_demo/AMCEdemo"));
|
||||
DemoMenu menu = new DemoMenu();
|
||||
menu.entries = new DemoMenu.DemoMenuEntry[]
|
||||
{
|
||||
new DemoMenu.DemoMenuEntry()
|
||||
{
|
||||
rating = 1,
|
||||
guideMode = 0x15,
|
||||
touchText1 = "HaxxStation by Gericom,",
|
||||
touchText2 = "shutterbug2000, Apache Thunder",
|
||||
internalName = "rom1.nds"
|
||||
},
|
||||
new DemoMenu.DemoMenuEntry()
|
||||
{
|
||||
bannerImage = new byte[512],
|
||||
bannerPalette = new byte[32],
|
||||
bannerText1 = "",
|
||||
bannerText2 = "",
|
||||
rating = 1,
|
||||
guideMode = 0x15,
|
||||
touchText1 = "HaxxStation by Gericom,",
|
||||
touchText2 = "shutterbug2000, Apache Thunder",
|
||||
internalName = "rom1.nds"
|
||||
},
|
||||
new DemoMenu.DemoMenuEntry()
|
||||
{
|
||||
bannerImage = new byte[512],
|
||||
bannerPalette = new byte[32],
|
||||
bannerText1 = "",
|
||||
bannerText2 = "",
|
||||
rating = 1,
|
||||
guideMode = 0x15,
|
||||
touchText1 = "HaxxStation by Gericom,",
|
||||
touchText2 = "shutterbug2000, Apache Thunder",
|
||||
internalName = "rom1.nds"
|
||||
}
|
||||
};
|
||||
if (newRom2.Banner != null)
|
||||
{
|
||||
string[] lines = newRom2.Banner.Banner.GameName[1].Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (lines.Length > 0)
|
||||
menu.entries[0].bannerText1 = lines[0];
|
||||
else
|
||||
menu.entries[0].bannerText1 = "Bannerless Homebrew";
|
||||
if (lines.Length > 1)
|
||||
menu.entries[0].bannerText2 = lines[1];
|
||||
else
|
||||
menu.entries[0].bannerText2 = "";
|
||||
menu.entries[0].bannerImage = newRom2.Banner.Banner.Image;
|
||||
menu.entries[0].bannerPalette = newRom2.Banner.Banner.Pltt;
|
||||
}
|
||||
else
|
||||
{
|
||||
menu.entries[0].bannerText1 = "Bannerless Homebrew";
|
||||
menu.entries[0].bannerText2 = "";
|
||||
menu.entries[0].bannerImage = new byte[512];
|
||||
menu.entries[0].bannerPalette = new byte[32];
|
||||
}
|
||||
byte[] demoMenu = menu.Write();
|
||||
fs.GetFileByPath("//ds_demo/demomenu").Data = demoMenu;
|
||||
fs.GetFileByPath("//mb/server").Data = haxxStationServer;
|
||||
fs.GetFileByPath("//mb/icon.nbfc").Data = haxxStationIconImage;
|
||||
fs.GetFileByPath("//mb/icon.nbfp").Data = haxxStationIconPltt;
|
||||
downloadStation.FromFileSystem(fs);
|
||||
//change banner
|
||||
downloadStation.Banner.Banner.Image = haxxStationIconImage;
|
||||
downloadStation.Banner.Banner.Pltt = haxxStationIconPltt;
|
||||
for(int i = 0; i < 6; i++)
|
||||
downloadStation.Banner.Banner.GameName[i] = "HaxxStation\nBy Gericom, shutterbug2000\nand Apache Thunder";
|
||||
byte[] finalResult = downloadStation.Write();
|
||||
File.Create(args[2]).Close();
|
||||
File.WriteAllBytes(args[2], finalResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
36
dspatch/Properties/AssemblyInfo.cs
Normal file
36
dspatch/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("DS Download Station Patcher")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("DS Download Station Patcher")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2017 Gericom, shutterbug2000 and Apache Thunder")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("c8cae5e5-40a9-4840-ae8a-abbd2ae50749")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
75
dspatch/dspatch.csproj
Normal file
75
dspatch/dspatch.csproj
Normal file
@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{C8CAE5E5-40A9-4840-AE8A-ABBD2AE50749}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>dspatch</RootNamespace>
|
||||
<AssemblyName>dspatch</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="DS\DemoMenu.cs" />
|
||||
<Compile Include="IO\IOUtil.cs" />
|
||||
<Compile Include="Nitro\ARM9.cs" />
|
||||
<Compile Include="Nitro\CRC16.cs" />
|
||||
<Compile Include="IO\EndianBinaryReader.cs" />
|
||||
<Compile Include="IO\EndianBinaryWriter.cs" />
|
||||
<Compile Include="Nitro\CRT0.cs" />
|
||||
<Compile Include="Nitro\NDS.cs" />
|
||||
<Compile Include="Nitro\NitroFS.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="IO\SFSDirectory.cs" />
|
||||
<Compile Include="IO\SFSFile.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="bin\Debug\" />
|
||||
</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.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
Loading…
Reference in New Issue
Block a user