Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ClusterM/nes-containers.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com>2020-11-25 11:05:44 +0300
committerAlexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com>2020-11-25 11:05:44 +0300
commit448bda7a1feac448d04eaac8ca2997d482eae249 (patch)
tree0a6260b2b6c33b5a0bba4b43afb29eee8b56a57f
parentfcae9cde2ff4abd0251372303744c4ba9f34542c (diff)
Refactoring, FDS classes
-rw-r--r--FdsDiskInfoBlock.cs251
-rw-r--r--FdsFile.cs46
-rw-r--r--FdsFileAmountBlock.cs37
-rw-r--r--FdsFileDataBlock.cs45
-rw-r--r--FdsFileHeaderBlock.cs95
-rw-r--r--IFdsBlock.cs16
-rw-r--r--NesContainers.csproj6
-rw-r--r--NesFile.cs73
-rw-r--r--NesHeaderFixer.cs2
9 files changed, 534 insertions, 37 deletions
diff --git a/FdsDiskInfoBlock.cs b/FdsDiskInfoBlock.cs
new file mode 100644
index 0000000..3861ecd
--- /dev/null
+++ b/FdsDiskInfoBlock.cs
@@ -0,0 +1,251 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace com.clusterrr.Famicom.Containers
+{
+ [StructLayout(LayoutKind.Sequential, Size = 58, Pack = 1, CharSet = CharSet.Ansi)]
+ public class FdsDiskInfoBlock : IFdsBlock
+ {
+ public enum DiskSizes
+ {
+ SideA = 0,
+ SideB = 1,
+ }
+ public enum DiskTypes
+ {
+ FMS = 0, // Normal
+ FSC = 1, // With shutter
+ }
+
+ [MarshalAs(UnmanagedType.U1)]
+ // Raw byte: 0x01
+ private byte blockType = 1;
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)]
+ // Literal ASCII string: *NINTENDO-HVC*
+ char[] diskVerification;
+ public string DiskVerification { get => new string(diskVerification).Trim(new char[] { '\0', ' ' }); set => diskVerification = value.PadRight(14).ToCharArray(); }
+
+ [MarshalAs(UnmanagedType.U1)]
+ private byte manufacturerCode;
+ public byte ManufacturerCode { get => manufacturerCode; set => manufacturerCode = value; }
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ // 3-letter ASCII code per game (e.g. ZEL for The Legend of Zelda)
+ char[] gameName;
+ public string GameName { get => new string(gameName).Trim(new char[] { '\0', ' ' }); set => gameName = value.PadRight(3).ToCharArray(); }
+
+ [MarshalAs(UnmanagedType.U1)]
+ char gameType;
+ public char GameType { get => gameType; set => gameType = value; }
+
+ [MarshalAs(UnmanagedType.U1)]
+ byte gameVersion;
+ public byte GameVersion { get => gameVersion; set => gameVersion = value; }
+
+ [MarshalAs(UnmanagedType.U1)]
+ // $00 = Side A, $01 = Side B. Single-sided disks use $00
+ byte diskSide;
+ public DiskSizes DiskSide { get => (DiskSizes)diskSide; set => diskSide = (byte)value; }
+
+ [MarshalAs(UnmanagedType.U1)]
+ // First disk is $00, second is $01, etc.
+ byte diskNumber;
+ public byte DiskNumber { get => diskNumber; set => diskNumber = value; }
+
+ [MarshalAs(UnmanagedType.U1)]
+ // $00 = FMC ("normal card"), $01 = FSC ("card with shutter"). May correlate with FMC and FSC product codes
+ byte diskType;
+ public DiskTypes DiskType { get => (DiskTypes)diskType; set => diskType = (byte)value; }
+
+ [MarshalAs(UnmanagedType.U1)]
+ // Speculative: (Err.10) Possibly indicates disk #; usually $00
+ // Speculative: $00 = yellow disk, $01 = blue or gold disk, $FE = white disk, $FF = blue disk
+ byte unknown01 = 0x00;
+ [MarshalAs(UnmanagedType.U1)]
+ // Refers to the file code/file number to load upon boot/start-up
+ byte bootFile;
+ [MarshalAs(UnmanagedType.U1)]
+ byte unknown02 = 0xFF;
+ [MarshalAs(UnmanagedType.U1)]
+ byte unknown03 = 0xFF;
+ [MarshalAs(UnmanagedType.U1)]
+ byte unknown04 = 0xFF;
+ [MarshalAs(UnmanagedType.U1)]
+ byte unknown05 = 0xFF;
+ [MarshalAs(UnmanagedType.U1)]
+ byte unknown06 = 0xFF;
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ byte[] manufacturingDate;
+ public DateTime ManufacturingDate
+ {
+ get
+ {
+ try
+ {
+ return new DateTime(
+ ((manufacturingDate[0] & 0x0F) + ((manufacturingDate[0] >> 4) & 0x0F) * 10) + 1925,
+ ((manufacturingDate[1] & 0x0F) + ((manufacturingDate[1] >> 4) & 0x0F) * 10),
+ ((manufacturingDate[2] & 0x0F) + ((manufacturingDate[2] >> 4) & 0x0F) * 10)
+ );
+ }
+ catch
+ {
+ return new DateTime();
+ }
+ }
+ set
+ {
+ manufacturingDate = new byte[]
+ {
+ (byte)(((value.Year - 1925) % 10) | (((value.Year - 1925) / 10) << 4)),
+ (byte)(((value.Month) % 10) | (((value.Month) / 10) << 4)),
+ (byte)(((value.Day) % 10) | (((value.Day) / 10) << 4))
+ };
+ }
+ }
+
+ [MarshalAs(UnmanagedType.U1)]
+ // $49 = Japan
+ byte countryCode = 0x49;
+ public byte CountryCode { get => countryCode; set => countryCode = value; }
+
+ [MarshalAs(UnmanagedType.U1)]
+ // Raw byte: $61. Speculative: Region code?
+ byte unknown07 = 0x61;
+ [MarshalAs(UnmanagedType.U1)]
+ // Raw byte: $00. Speculative: Location/site?
+ byte unknown08 = 0x00;
+ [MarshalAs(UnmanagedType.U1)]
+ // Raw byte: $00
+ byte unknown09 = 0x00;
+ [MarshalAs(UnmanagedType.U1)]
+ // Raw byte: $02
+ // Speculative: some kind of game information representation?
+ byte unknown10 = 0x02;
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ // It's speculated this refers to the date the disk was formatted and rewritten by something like a Disk Writer kiosk.
+ // In the case of an original (non-copied) disk, this should be the same as Manufacturing date.
+ byte[] rewrittenDate;
+ public DateTime RewrittenDate
+ {
+ get
+ {
+ try
+ {
+ return new DateTime(
+ ((rewrittenDate[0] & 0x0F) + ((rewrittenDate[0] >> 4) & 0x0F) * 10) + 1925,
+ ((rewrittenDate[1] & 0x0F) + ((rewrittenDate[1] >> 4) & 0x0F) * 10),
+ ((rewrittenDate[2] & 0x0F) + ((rewrittenDate[2] >> 4) & 0x0F) * 10)
+ );
+ }
+ catch
+ {
+ return new DateTime();
+ }
+ }
+ set
+ {
+ rewrittenDate = new byte[]
+ {
+ (byte)(((value.Year - 1925) % 10) | (((value.Year - 1925) / 10) << 4)),
+ (byte)(((value.Month) % 10) | (((value.Month) / 10) << 4)),
+ (byte)(((value.Day) % 10) | (((value.Day) / 10) << 4))
+ };
+ }
+ }
+
+ [MarshalAs(UnmanagedType.U1)]
+ byte unknown11 = 0x00;
+ [MarshalAs(UnmanagedType.U1)]
+ // Raw byte: $80
+ byte unknown12 = 0x80;
+ [MarshalAs(UnmanagedType.U2)]
+
+ ushort diskWriterSerialNumber;
+ public ushort DiskWriterSerialNumber { get => diskWriterSerialNumber; set => diskWriterSerialNumber = value; }
+
+ [MarshalAs(UnmanagedType.U1)]
+ // Raw byte: $07
+ byte unknown13 = 0x07;
+
+ [MarshalAs(UnmanagedType.U1)]
+ // Value stored in BCD format. $00 = Original (no copies).
+ byte diskRewriteCount = 0x00;
+ public byte DiskRewriteCount
+ {
+ get
+ {
+ return (byte)((diskRewriteCount & 0x0F) + ((diskRewriteCount >> 4) & 0x0F) * 10);
+ }
+ set
+ {
+ diskRewriteCount = (byte)(((value) % 10) | (((value) / 10) << 4));
+ }
+ }
+
+ [MarshalAs(UnmanagedType.U1)]
+ // $00 = Side A, $01 = Side B
+ byte actualDiskSide = 0x00;
+ public DiskSizes ActualDiskSide { get => (DiskSizes)actualDiskSide; set => actualDiskSide = (byte)value; }
+
+ [MarshalAs(UnmanagedType.U1)]
+ byte unknown14 = 0x00;
+
+ [MarshalAs(UnmanagedType.U1)]
+ byte price = 0x00;
+ public byte Price { get => price; set => price = value; }
+
+ [MarshalAs(UnmanagedType.U1)]
+ private bool crcOk;
+ public bool CrcOk { get => crcOk; set => crcOk = value; }
+
+ [MarshalAs(UnmanagedType.U1)]
+ private bool endOfHeadMeet;
+ public bool EndOfHeadMeet { get => endOfHeadMeet; set => endOfHeadMeet = value; }
+
+ public static FdsDiskInfoBlock FromBytes(byte[] rawData, int position = 0)
+ {
+ int rawsize = Marshal.SizeOf(typeof(FdsDiskInfoBlock));
+ if (rawsize > rawData.Length - position)
+ {
+ if (rawsize <= rawData.Length - position + 2)
+ {
+ var newRawData = new byte[rawsize];
+ Array.Copy(rawData, position, newRawData, 0, rawsize - 2);
+ rawData = newRawData;
+ position = 0;
+ }
+ else
+ {
+ throw new ArgumentException("Not enough data to fill FdsDiskInfoBlock class. Array length from position: " + (rawData.Length - position) + ", Struct length: " + rawsize);
+ }
+ }
+ IntPtr buffer = Marshal.AllocHGlobal(rawsize);
+ Marshal.Copy(rawData, position, buffer, rawsize);
+ FdsDiskInfoBlock retobj = (FdsDiskInfoBlock)Marshal.PtrToStructure(buffer, typeof(FdsDiskInfoBlock));
+ Marshal.FreeHGlobal(buffer);
+ if (retobj.blockType != 1)
+ throw new InvalidDataException("Invalid block type");
+ return retobj;
+ }
+
+ public byte[] ToBytes()
+ {
+ int rawSize = Marshal.SizeOf(this);
+ IntPtr buffer = Marshal.AllocHGlobal(rawSize);
+ Marshal.StructureToPtr(this, buffer, false);
+ byte[] rawDatas = new byte[rawSize - 2];
+ Marshal.Copy(buffer, rawDatas, 0, rawSize - 2);
+ Marshal.FreeHGlobal(buffer);
+ return rawDatas;
+ }
+ }
+}
diff --git a/FdsFile.cs b/FdsFile.cs
new file mode 100644
index 0000000..ada4a2d
--- /dev/null
+++ b/FdsFile.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace com.clusterrr.Famicom.Containers
+{
+ public class FdsFile
+ {
+ private FdsFileHeaderBlock headerBlock;
+ private FdsFileDataBlock dataBlock;
+
+ public byte FileNumber { get => headerBlock.FileNumber; set => headerBlock.FileNumber = value; }
+ public byte FileIndicateCode { get => headerBlock.FileIndicateCode; set => headerBlock.FileIndicateCode = value; }
+ public string FileName { get => headerBlock.FileName; set => headerBlock.FileName = value; }
+ public ushort FileAddress { get => headerBlock.FileAddress; set => headerBlock.FileAddress = value; }
+ public ushort FileSize { get => (ushort)dataBlock.Data.Count(); }
+ public FdsFileHeaderBlock.Kind FileKind { get => headerBlock.FileKind; set => headerBlock.FileKind = value; }
+ public IEnumerable<byte> Data
+ {
+ get => dataBlock.Data;
+ set
+ {
+ dataBlock.Data = value;
+ headerBlock.FileSize = (ushort)dataBlock.Data.Count();
+ }
+ }
+
+ public FdsFile(FdsFileHeaderBlock headerBlock, FdsFileDataBlock dataBlock)
+ {
+ this.headerBlock = headerBlock;
+ this.dataBlock = dataBlock;
+ headerBlock.FileSize = (ushort)dataBlock.Data.Count();
+ }
+
+ public FdsFile()
+ {
+ this.headerBlock = new FdsFileHeaderBlock();
+ this.dataBlock = new FdsFileDataBlock();
+ headerBlock.FileSize = (ushort)dataBlock.Data.Count();
+ }
+
+ public byte[] ToBytes() => Enumerable.Concat(headerBlock.ToBytes(), dataBlock.ToBytes()).ToArray();
+ }
+}
diff --git a/FdsFileAmountBlock.cs b/FdsFileAmountBlock.cs
new file mode 100644
index 0000000..a428f1d
--- /dev/null
+++ b/FdsFileAmountBlock.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace com.clusterrr.Famicom.Containers
+{
+ public class FdsFileAmountBlock : IFdsBlock
+ {
+ private byte blockType = 2;
+
+ private byte fileAmount;
+ public byte FileAmount { get => fileAmount; set => value = fileAmount; }
+
+ public bool CrcOk { get; set; }
+
+ public bool EndOfHeadMeet { get; set; }
+
+ public static FdsFileAmountBlock FromBytes(byte[] rawData, int position = 0)
+ {
+ var retobj = new FdsFileAmountBlock();
+ retobj.blockType = rawData[position];
+ if (retobj.blockType != 2)
+ throw new InvalidDataException("Invalid block type");
+ retobj.fileAmount = rawData[position + 1];
+ return retobj;
+ }
+
+ public byte[] ToBytes()
+ {
+ return new byte[] { blockType, fileAmount };
+ }
+ }
+}
diff --git a/FdsFileDataBlock.cs b/FdsFileDataBlock.cs
new file mode 100644
index 0000000..5d54937
--- /dev/null
+++ b/FdsFileDataBlock.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace com.clusterrr.Famicom.Containers
+{
+ public class FdsFileDataBlock : IFdsBlock
+ {
+ private byte blockType = 4;
+
+ private byte[] data = new byte[0];
+ public IEnumerable<byte> Data
+ {
+ get => Array.AsReadOnly(data);
+ set => data = value.ToArray();
+ }
+
+ public bool CrcOk { get; set; }
+
+ public bool EndOfHeadMeet { get; set; }
+
+ public static FdsFileDataBlock FromBytes(byte[] rawData, int position = 0, int size = -1)
+ {
+ var retobj = new FdsFileDataBlock();
+ retobj.blockType = rawData[position];
+ if (retobj.blockType != 4)
+ throw new InvalidDataException("Invalid block type");
+ retobj.data = new byte[size < 0 ? rawData.Length - position : size];
+ Array.Copy(rawData, position, retobj.data, 0, retobj.data.Length);
+ return retobj;
+ }
+
+ public byte[] ToBytes()
+ {
+ var result = new List<byte>();
+ result.Add(blockType);
+ result.AddRange(Data);
+ return result.ToArray();
+ }
+ }
+}
diff --git a/FdsFileHeaderBlock.cs b/FdsFileHeaderBlock.cs
new file mode 100644
index 0000000..0c5926e
--- /dev/null
+++ b/FdsFileHeaderBlock.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace com.clusterrr.Famicom.Containers
+{
+ [StructLayout(LayoutKind.Sequential, Size = 18, Pack = 1, CharSet = CharSet.Ansi)]
+ public class FdsFileHeaderBlock : IFdsBlock
+ {
+ public enum Kind
+ {
+ Program = 0,
+ Character = 1,
+ NameTable = 2
+ }
+
+ [MarshalAs(UnmanagedType.U1)]
+ private byte blockType = 3;
+
+ [MarshalAs(UnmanagedType.U1)]
+ private byte fileNumber;
+ public byte FileNumber { get => fileNumber; set => fileNumber = value; }
+
+ [MarshalAs(UnmanagedType.U1)]
+ // ID specified at disk-read function call
+ private byte fileIndicateCode;
+ public byte FileIndicateCode { get => fileIndicateCode; set => fileIndicateCode = value; }
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
+ private char[] fileName;
+ public string FileName { get => new string(fileName).Trim(new char[] { '\0', ' ' }); set => fileName = value.PadRight(0).ToCharArray(); }
+
+ [MarshalAs(UnmanagedType.U2)]
+ // the destination address when loading
+ private ushort fileAddress;
+ public ushort FileAddress { get => fileAddress; set => fileAddress = value; }
+
+ [MarshalAs(UnmanagedType.U2)]
+ private ushort fileSize;
+ public ushort FileSize { get => fileSize; set => fileSize = value; }
+
+ [MarshalAs(UnmanagedType.U1)]
+ private byte fileKind;
+ public Kind FileKind { get => (Kind)fileKind; set => fileKind = (byte)value; }
+
+ [MarshalAs(UnmanagedType.U1)]
+ private bool crcOk;
+ public bool CrcOk { get => crcOk; set => crcOk = value; }
+
+ [MarshalAs(UnmanagedType.U1)]
+ private bool endOfHeadMeet;
+ public bool EndOfHeadMeet { get => endOfHeadMeet; set => endOfHeadMeet = value; }
+
+ public static FdsFileHeaderBlock FromBytes(byte[] rawData, int position = 0)
+ {
+ int rawsize = Marshal.SizeOf(typeof(FdsFileHeaderBlock));
+ if (rawsize > rawData.Length - position)
+ {
+ if (rawsize <= rawData.Length - position + 2)
+ {
+ var newRawData = new byte[rawsize];
+ Array.Copy(rawData, position, newRawData, 0, rawsize - 2);
+ rawData = newRawData;
+ position = 0;
+ }
+ else
+ {
+ throw new ArgumentException("Not enough data to fill FdsFileHeaderBlock class. Array length from position: " + (rawData.Length - position) + ", Struct length: " + rawsize);
+ }
+ }
+ IntPtr buffer = Marshal.AllocHGlobal(rawsize);
+ Marshal.Copy(rawData, position, buffer, rawsize);
+ FdsFileHeaderBlock retobj = (FdsFileHeaderBlock)Marshal.PtrToStructure(buffer, typeof(FdsFileHeaderBlock));
+ Marshal.FreeHGlobal(buffer);
+ if (retobj.blockType != 3)
+ throw new InvalidDataException("Invalid block type");
+ return retobj;
+ }
+
+ public byte[] ToBytes()
+ {
+ int rawSize = Marshal.SizeOf(this);
+ IntPtr buffer = Marshal.AllocHGlobal(rawSize);
+ Marshal.StructureToPtr(this, buffer, false);
+ byte[] rawDatas = new byte[rawSize - 2];
+ Marshal.Copy(buffer, rawDatas, 0, rawSize - 2);
+ Marshal.FreeHGlobal(buffer);
+ return rawDatas;
+ }
+ }
+}
diff --git a/IFdsBlock.cs b/IFdsBlock.cs
new file mode 100644
index 0000000..08143d3
--- /dev/null
+++ b/IFdsBlock.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace com.clusterrr.Famicom.Containers
+{
+ public interface IFdsBlock
+ {
+ bool CrcOk { get; set; }
+ bool EndOfHeadMeet { get; set; }
+ byte[] ToBytes();
+ }
+}
diff --git a/NesContainers.csproj b/NesContainers.csproj
index d2c9da2..3cb3ff4 100644
--- a/NesContainers.csproj
+++ b/NesContainers.csproj
@@ -43,6 +43,12 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Crc32Calculator.cs" />
+ <Compile Include="FdsFile.cs" />
+ <Compile Include="IFdsBlock.cs" />
+ <Compile Include="FdsDiskInfoBlock.cs" />
+ <Compile Include="FdsFileAmountBlock.cs" />
+ <Compile Include="FdsFileDataBlock.cs" />
+ <Compile Include="FdsFileHeaderBlock.cs" />
<Compile Include="NesFile.cs" />
<Compile Include="NesHeaderFixer.cs" />
<Compile Include="UnifFile.cs" />
diff --git a/NesFile.cs b/NesFile.cs
index 6f77e9c..2620995 100644
--- a/NesFile.cs
+++ b/NesFile.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Security.Cryptography;
namespace com.clusterrr.Famicom.Containers
@@ -13,11 +14,11 @@ namespace com.clusterrr.Famicom.Containers
/// <summary>
/// PRG data
/// </summary>
- public byte[] PRG { get => prg; set => prg = value; }
+ public IEnumerable<byte> PRG { get => Array.AsReadOnly(prg); set => prg = value.ToArray(); }
/// <summary>
/// CHR data (can be null if none)
/// </summary>
- public byte[] CHR { get => chr; set => chr = value; }
+ public IEnumerable<byte> CHR { get => Array.AsReadOnly(chr); set => chr = value.ToArray(); }
/// <summary>
/// Trainer (can be null if none)
/// </summary>
@@ -654,12 +655,12 @@ namespace com.clusterrr.Famicom.Containers
offset += (uint)Trainer.Length;
}
- PRG = new byte[prgSize];
- Array.Copy(data, offset, PRG, 0, Math.Max(0, Math.Min(prgSize, data.Length - offset))); // Ignore end for some bad ROMs
+ prg = new byte[prgSize];
+ Array.Copy(data, offset, prg, 0, Math.Max(0, Math.Min(prgSize, data.Length - offset))); // Ignore end for some bad ROMs
offset += prgSize;
- CHR = new byte[chrSize];
- Array.Copy(data, offset, CHR, 0, Math.Max(0, Math.Min(chrSize, data.Length - offset)));
+ chr = new byte[chrSize];
+ Array.Copy(data, offset, chr, 0, Math.Max(0, Math.Min(chrSize, data.Length - offset)));
offset += chrSize;
if (MiscellaneousROMsCount > 0)
@@ -686,7 +687,7 @@ namespace com.clusterrr.Famicom.Containers
/// Returns iNES data (header + PRG + CHR)
/// </summary>
/// <returns>iNES data</returns>
- public byte[] GetINes()
+ public byte[] ToBytes()
{
var data = new List<byte>();
var header = new byte[16];
@@ -694,17 +695,17 @@ namespace com.clusterrr.Famicom.Containers
header[1] = (byte)'E';
header[2] = (byte)'S';
header[3] = 0x1A;
- if (PRG == null) PRG = new byte[0];
- if (CHR == null) CHR = new byte[0];
- if ((PRG.Length % 0x4000) != 0)
+ if (prg == null) prg = new byte[0];
+ if (chr == null) chr = new byte[0];
+ if ((prg.Length % 0x4000) != 0)
{
- var padding = 0x4000 - (PRG.Length % 4000);
+ var padding = 0x4000 - (prg.Length % 4000);
if (padding > 0)
Array.Resize(ref prg, prg.Length + padding);
}
- if ((CHR.Length % 0x2000) != 0)
+ if ((chr.Length % 0x2000) != 0)
{
- var padding = 0x2000 - (CHR.Length % 2000);
+ var padding = 0x2000 - (chr.Length % 2000);
if (padding > 0)
Array.Resize(ref chr, chr.Length + padding);
}
@@ -716,12 +717,12 @@ namespace com.clusterrr.Famicom.Containers
throw new InvalidDataException("Mapper > 255 supported by NES 2.0 only");
if (Submapper != 0)
throw new InvalidDataException("Submapper supported by NES 2.0 only");
- var length16k = PRG.Length / 0x4000;
+ var length16k = prg.Length / 0x4000;
if (length16k > 0xFF) throw new ArgumentOutOfRangeException("PRG size is too big for iNES, use NES 2.0 instead");
- header[4] = (byte)(PRG.Length / 0x4000);
- var length8k = CHR.Length / 0x2000;
+ header[4] = (byte)(prg.Length / 0x4000);
+ var length8k = chr.Length / 0x2000;
if (length8k > 0xFF) throw new ArgumentOutOfRangeException("CHR size is too big for iNES, use NES 2.0 instead");
- header[5] = (byte)(CHR.Length / 0x2000);
+ header[5] = (byte)(CHR.Count() / 0x2000);
// Hard-wired nametable mirroring type
if (Mirroring == MirroringType.Vertical)
header[6] |= 1;
@@ -744,12 +745,12 @@ namespace com.clusterrr.Famicom.Containers
data.AddRange(header);
if (Trainer != null)
data.AddRange(Trainer);
- data.AddRange(PRG);
- data.AddRange(CHR);
+ data.AddRange(prg);
+ data.AddRange(chr);
}
else if (Version == iNesVersion.NES20)
{
- var length16k = PRG.Length / 0x4000;
+ var length16k = prg.Length / 0x4000;
if (length16k <= 0xEFF)
{
header[4] = (byte)(length16k & 0xFF);
@@ -757,13 +758,13 @@ namespace com.clusterrr.Famicom.Containers
}
else
{
- (long padding, int exponent, int multiplier) = CalculateExponent(PRG.Length);
+ (long padding, int exponent, int multiplier) = CalculateExponent(prg.Length);
if (padding > 0)
Array.Resize(ref prg, (int)(prg.Length + padding));
header[4] = (byte)((exponent << 2) | (multiplier & 3));
header[9] |= 0x0F;
}
- var length8k = CHR.Length / 0x2000;
+ var length8k = CHR.Count() / 0x2000;
if (length8k <= 0xEFF)
{
header[5] = (byte)(length8k & 0xFF);
@@ -771,7 +772,7 @@ namespace com.clusterrr.Famicom.Containers
}
else
{
- (long padding, int exponent, int multiplier) = CalculateExponent(CHR.Length);
+ (long padding, int exponent, int multiplier) = CalculateExponent(CHR.Count());
if (padding > 0)
Array.Resize(ref chr, (int)(chr.Length + padding));
header[5] = (byte)((exponent << 2) | (multiplier & 3));
@@ -837,8 +838,8 @@ namespace com.clusterrr.Famicom.Containers
data.AddRange(header);
if (Trainer != null)
data.AddRange(Trainer);
- data.AddRange(PRG);
- data.AddRange(CHR);
+ data.AddRange(prg);
+ data.AddRange(chr);
if (MiscellaneousROMsCount > 0 || (MiscellaneousROM != null && MiscellaneousROM.Length > 0))
{
if (MiscellaneousROMsCount == 0)
@@ -898,7 +899,7 @@ namespace com.clusterrr.Famicom.Containers
/// <param name="fileName">Target filename</param>
public void Save(string fileName)
{
- File.WriteAllBytes(fileName, GetINes());
+ File.WriteAllBytes(fileName, ToBytes());
}
/// <summary>
@@ -907,11 +908,11 @@ namespace com.clusterrr.Famicom.Containers
public byte[] CalculateMD5()
{
var md5 = MD5.Create();
- if (PRG == null) PRG = new byte[0];
- if (CHR == null) CHR = new byte[0];
- var alldata = new byte[PRG.Length + CHR.Length];
- Array.Copy(PRG, 0, alldata, 0, PRG.Length);
- Array.Copy(CHR, 0, alldata, PRG.Length, CHR.Length);
+ if (prg == null) prg = new byte[0];
+ if (chr == null) chr = new byte[0];
+ var alldata = new byte[prg.Length + chr.Length];
+ Array.Copy(prg, 0, alldata, 0, prg.Length);
+ Array.Copy(chr, 0, alldata, prg.Length, chr.Count());
return md5.ComputeHash(alldata);
}
@@ -920,11 +921,11 @@ namespace com.clusterrr.Famicom.Containers
/// </summary>
public uint CalculateCRC32()
{
- if (PRG == null) PRG = new byte[0];
- if (CHR == null) CHR = new byte[0];
- var alldata = new byte[PRG.Length + CHR.Length];
- Array.Copy(PRG, 0, alldata, 0, PRG.Length);
- Array.Copy(CHR, 0, alldata, PRG.Length, CHR.Length);
+ if (prg == null) prg = new byte[0];
+ if (chr == null) chr = new byte[0];
+ var alldata = new byte[prg.Length + chr.Length];
+ Array.Copy(prg, 0, alldata, 0, prg.Length);
+ Array.Copy(chr, 0, alldata, prg.Length, chr.Length);
return Crc32Calculator.CalculateCRC32(alldata);
}
}
diff --git a/NesHeaderFixer.cs b/NesHeaderFixer.cs
index 997388a..03d4d35 100644
--- a/NesHeaderFixer.cs
+++ b/NesHeaderFixer.cs
@@ -36,7 +36,7 @@ namespace com.clusterrr.Famicom.Containers.HeaderFixer
if (mapper >= 0)
{
// no CHR
- if (((mapper & 0x800) != 0) && (nes.CHR?.Length ?? 0) > 0)
+ if (((mapper & 0x800) != 0) && (nes.CHR?.Count() ?? 0) > 0)
{
nes.CHR = new byte[0];
fixType |= NesFixType.NoChr;