From eb10ea5213b4362d9cc859593a89adab05237765 Mon Sep 17 00:00:00 2001 From: Alexey 'Cluster' Avdyukhin Date: Mon, 30 Nov 2020 17:33:25 +0300 Subject: Much more FDS stuff --- FdsBlockDiskInfo.cs | 71 ++++++++++++++++++++++++++++++++++++++++++--------- FdsBlockFileAmount.cs | 2 ++ FdsBlockFileData.cs | 2 ++ FdsBlockFileHeader.cs | 2 ++ FdsDiskFile.cs | 32 ++++++++++++----------- FdsDiskSide.cs | 40 +++++++++++++++++++++-------- FdsFile.cs | 5 ++-- IFdsBlock.cs | 1 + NesContainers.csproj | 4 +-- UnifFile.cs | 5 ++++ 10 files changed, 123 insertions(+), 41 deletions(-) diff --git a/FdsBlockDiskInfo.cs b/FdsBlockDiskInfo.cs index c208b6b..c9c5b39 100644 --- a/FdsBlockDiskInfo.cs +++ b/FdsBlockDiskInfo.cs @@ -23,7 +23,52 @@ namespace com.clusterrr.Famicom.Containers } public enum Country { - Japan = 0x49 + Japan = 0x49, + } + + public enum Manufacturer + { + Unlicensed = 0x00, + Nintendo = 0x01, + Capcom = 0x08, + Jaleco = 0x0A, + Hudson_Soft = 0x18, + Irem = 0x49, + Gakken = 0x4A, + BulletProof_Software = 0x8B, + PackInVideo = 0x99, + Tecmo = 0x9B, + Imagineer = 0x9C, + Scorpion_Soft = 0xA2, + Konami = 0xA4, + Kawada_Co = 0xA6, + Takara = 0xA7, + Royal_Industries = 0xA8, + Toei_Animation = 0xAC, + Namco = 0xAF, + ASCII_Corporation = 0xB1, + Bandai = 0xB2, + Soft_Pro_Inc = 0xB3, + HAL_Laboratory = 0xB6, + Sunsoft_and_Ask_Co = 0xBB, + Toshiba_EMI = 0xBC, + Taito = 0xC0, + Sunsoft = 0xC1, + Kemco = 0xC2, + Square = 0xC3, + Tokuma_Shoten = 0xC4, + Data_East = 0xC5, + Tonkin_House_and_Tokyo_Shoseki = 0xC6, + East_Cube = 0xC7, + Konami_and_Ultra_and_Palcom = 0xCA, + NTVIC_and_VAP = 0xCB, + Use_Co = 0xCC, + Pony_Canyon_and_FCI = 0xCE, + Sofel = 0xD1, + Bothtec_Inc = 0xD2, + Hiro_Co = 0xDB, + Athena = 0xE7, + Atlus = 0xEB, } [MarshalAs(UnmanagedType.U1)] @@ -44,9 +89,9 @@ namespace com.clusterrr.Famicom.Containers [MarshalAs(UnmanagedType.U1)] private byte manufacturerCode; /// - /// Manufacturer code. $00 = Unlicensed, $01 = Nintendo + /// Manufacturer code. = = 0x00, Unlicensed, = = 0x01, Nintendo /// - public byte ManufacturerCode { get => manufacturerCode; set => manufacturerCode = value; } + public Manufacturer ManufacturerCode { get => (Manufacturer)manufacturerCode; set => manufacturerCode = (byte)value; } [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] char[] gameName; @@ -58,9 +103,9 @@ namespace com.clusterrr.Famicom.Containers [MarshalAs(UnmanagedType.U1)] char gameType; /// - /// $20 = " " — Normal disk - /// $45 = "E" — Event(e.g.Japanese national DiskFax tournaments) - /// $52 = "R" — Reduction in price via advertising + /// = = 0x20, " " — Normal disk + /// = = 0x45, "E" — Event(e.g.Japanese national DiskFax tournaments) + /// = = 0x52, "R" — Reduction in price via advertising /// public char GameType { get => gameType; set => gameType = value; } @@ -88,13 +133,13 @@ namespace com.clusterrr.Famicom.Containers [MarshalAs(UnmanagedType.U1)] byte diskType; /// - /// Disk type. $00 = FMC ("normal card"), $01 = FSC ("card with shutter"). May correlate with FMC and FSC product codes + /// Disk type. = = 0x00, FMC ("normal card"), = = 0x01, FSC ("card with shutter"). May correlate with FMC and FSC product codes /// 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 + // Speculative: = = 0x00, yellow disk, = = 0x01, blue or gold disk, = = 0xFE, white disk, = = 0xFF, blue disk byte unknown01 = 0x00; [MarshalAs(UnmanagedType.U1)] byte bootFile; @@ -147,10 +192,10 @@ namespace com.clusterrr.Famicom.Containers } [MarshalAs(UnmanagedType.U1)] - // $49 = Japan + // = = 0x49, Japan byte countryCode = (byte)Country.Japan; /// - /// Country code. $49 = Japan + /// Country code. = = 0x49, Japan /// public Country CountryCode { get => (Country)countryCode; set => countryCode = (byte)value; } @@ -222,13 +267,13 @@ namespace com.clusterrr.Famicom.Containers [MarshalAs(UnmanagedType.U1)] byte diskRewriteCount = 0x00; /// - /// Disk rewrite count. $00 = Original (no copies) + /// Disk rewrite count. = = 0x00, Original (no copies) /// public byte DiskRewriteCount { get { - return (byte)((diskRewriteCount & 0x0F) + ((diskRewriteCount >> 4) & 0x0F) * 10); + return (diskRewriteCount == 0xFF) ? (byte)0 : (byte)((diskRewriteCount & 0x0F) + ((diskRewriteCount >> 4) & 0x0F) * 10); } set { @@ -267,6 +312,8 @@ namespace com.clusterrr.Famicom.Containers /// public bool EndOfHeadMeet { get => endOfHeadMeet; set => endOfHeadMeet = value; } + public uint Length => 56; + public static FdsBlockDiskInfo FromBytes(byte[] rawData, int position = 0) { int rawsize = Marshal.SizeOf(typeof(FdsBlockDiskInfo)); diff --git a/FdsBlockFileAmount.cs b/FdsBlockFileAmount.cs index 8858151..9ed5163 100644 --- a/FdsBlockFileAmount.cs +++ b/FdsBlockFileAmount.cs @@ -29,6 +29,8 @@ namespace com.clusterrr.Famicom.Containers /// public bool EndOfHeadMeet { get; set; } = false; + public uint Length => 2; + public static FdsBlockFileAmount FromBytes(byte[] rawData, int position = 0) { var retobj = new FdsBlockFileAmount(); diff --git a/FdsBlockFileData.cs b/FdsBlockFileData.cs index 51345bd..c5ab761 100644 --- a/FdsBlockFileData.cs +++ b/FdsBlockFileData.cs @@ -33,6 +33,8 @@ namespace com.clusterrr.Famicom.Containers /// public bool EndOfHeadMeet { get; set; } = false; + public uint Length => (uint)(data.Length + 1); + public static FdsBlockFileData FromBytes(byte[] rawData, int position = 0, int size = -1) { var retobj = new FdsBlockFileData(); diff --git a/FdsBlockFileHeader.cs b/FdsBlockFileHeader.cs index 99c301c..5db2c7f 100644 --- a/FdsBlockFileHeader.cs +++ b/FdsBlockFileHeader.cs @@ -65,6 +65,8 @@ namespace com.clusterrr.Famicom.Containers /// public bool EndOfHeadMeet { get => endOfHeadMeet; set => endOfHeadMeet = value; } + public uint Length => 16; + public static FdsBlockFileHeader FromBytes(byte[] rawData, int position = 0) { int rawsize = Marshal.SizeOf(typeof(FdsBlockFileHeader)); diff --git a/FdsDiskFile.cs b/FdsDiskFile.cs index 3607d83..6ce92b3 100644 --- a/FdsDiskFile.cs +++ b/FdsDiskFile.cs @@ -10,37 +10,39 @@ namespace com.clusterrr.Famicom.Containers { private FdsBlockFileHeader headerBlock; private FdsBlockFileData dataBlock; + public FdsBlockFileHeader HeaderBlock { get => headerBlock; set => headerBlock = value; } + public FdsBlockFileData DataBlock { get => dataBlock; set => dataBlock = value; } - 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 FdsBlockFileHeader.Kind FileKind { get => headerBlock.FileKind; set => headerBlock.FileKind = value; } + 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 FdsBlockFileHeader.Kind FileKind { get => HeaderBlock.FileKind; set => HeaderBlock.FileKind = value; } public IEnumerable Data { - get => dataBlock.Data; + get => DataBlock.Data; set { - dataBlock.Data = value; - headerBlock.FileSize = (ushort)dataBlock.Data.Count(); + DataBlock.Data = value; + HeaderBlock.FileSize = (ushort)DataBlock.Data.Count(); } } public FdsDiskFile(FdsBlockFileHeader headerBlock, FdsBlockFileData dataBlock) { - this.headerBlock = headerBlock; - this.dataBlock = dataBlock; + this.HeaderBlock = headerBlock; + this.DataBlock = dataBlock; headerBlock.FileSize = (ushort)dataBlock.Data.Count(); } public FdsDiskFile() { - this.headerBlock = new FdsBlockFileHeader(); - this.dataBlock = new FdsBlockFileData(); - headerBlock.FileSize = (ushort)dataBlock.Data.Count(); + this.HeaderBlock = new FdsBlockFileHeader(); + this.DataBlock = new FdsBlockFileData(); + HeaderBlock.FileSize = (ushort)DataBlock.Data.Count(); } - public byte[] ToBytes() => Enumerable.Concat(headerBlock.ToBytes(), dataBlock.ToBytes()).ToArray(); + public byte[] ToBytes() => Enumerable.Concat(HeaderBlock.ToBytes(), DataBlock.ToBytes()).ToArray(); } } diff --git a/FdsDiskSide.cs b/FdsDiskSide.cs index 11f16d3..4d1af1f 100644 --- a/FdsDiskSide.cs +++ b/FdsDiskSide.cs @@ -9,12 +9,15 @@ namespace com.clusterrr.Famicom.Containers public class FdsDiskSide { FdsBlockDiskInfo diskInfoBlock; - + /// + /// Disk info block + /// + public FdsBlockDiskInfo DiskInfoBlock { get => diskInfoBlock; } public string DiskVerification { get => diskInfoBlock.DiskVerification; } /// /// Manufacturer code. $00 = Unlicensed, $01 = Nintendo /// - public byte ManufacturerCode { get => diskInfoBlock.ManufacturerCode; set => diskInfoBlock.ManufacturerCode = value; } + public FdsBlockDiskInfo.Manufacturer ManufacturerCode { get => diskInfoBlock.ManufacturerCode; set => diskInfoBlock.ManufacturerCode = value; } /// /// 3-letter ASCII code per game (e.g. ZEL for The Legend of Zelda) /// @@ -125,15 +128,23 @@ namespace com.clusterrr.Famicom.Containers pos += 2; while (pos < data.Length) { - var fileHeaderBlock = FdsBlockFileHeader.FromBytes(data.Skip(pos).Take(16).ToArray()); - if (!fileHeaderBlock.IsValid) - break; - pos += 16; - var fileDataBlock = FdsBlockFileData.FromBytes(data.Skip(pos).Take(fileHeaderBlock.FileSize + 1).ToArray()); - if (!fileDataBlock.IsValid) + try + { + var fileHeaderBlock = FdsBlockFileHeader.FromBytes(data.Skip(pos).Take(16).ToArray()); + if (!fileHeaderBlock.IsValid) + break; + pos += 16; + var fileDataBlock = FdsBlockFileData.FromBytes(data.Skip(pos).Take(fileHeaderBlock.FileSize + 1).ToArray()); + if (!fileDataBlock.IsValid) + break; + pos += fileHeaderBlock.FileSize + 1; + files.Add(new FdsDiskFile(fileHeaderBlock, fileDataBlock)); + } + catch + { + // just break on out of range break; - pos += fileHeaderBlock.FileSize + 1; - files.Add(new FdsDiskFile(fileHeaderBlock, fileDataBlock)); + } } } @@ -143,6 +154,15 @@ namespace com.clusterrr.Famicom.Containers files[i].FileNumber = (byte)i; } + public IEnumerable GetBlocks() + { + var blocks = new List(); + blocks.Add(diskInfoBlock); + blocks.Add(fileAmountBlock); + blocks.AddRange(files.SelectMany(f => new IFdsBlock[] { f.HeaderBlock, f.DataBlock })); + return blocks; + } + public static FdsDiskSide FromBytes(byte[] data) { return new FdsDiskSide(data); diff --git a/FdsFile.cs b/FdsFile.cs index 01e3a68..e374f82 100644 --- a/FdsFile.cs +++ b/FdsFile.cs @@ -26,7 +26,7 @@ namespace com.clusterrr.Famicom.Containers public FdsFile(byte[] data) : this() { - if (data[0] == (byte)'F' && data[1] == (byte)'D' && data[2] == (byte)'S') + if (data[0] == (byte)'F' && data[1] == (byte)'D' && data[2] == (byte)'S' && data[3] == 0x1A) data = data.Skip(16).ToArray(); // skip header for (int i = 0; i < data.Length; i += 65500) { @@ -54,7 +54,8 @@ namespace com.clusterrr.Famicom.Containers header[0] = (byte)'F'; header[1] = (byte)'D'; header[2] = (byte)'S'; - header[3] = (byte)sides.Count(); + header[3] = 0x1A; + header[4] = (byte)sides.Count(); data = Enumerable.Concat(header, data); } return data.ToArray(); diff --git a/IFdsBlock.cs b/IFdsBlock.cs index e8ec78d..6171d65 100644 --- a/IFdsBlock.cs +++ b/IFdsBlock.cs @@ -12,6 +12,7 @@ namespace com.clusterrr.Famicom.Containers bool IsValid { get; } bool CrcOk { get; set; } bool EndOfHeadMeet { get; set; } + uint Length { get; } byte[] ToBytes(); } } diff --git a/NesContainers.csproj b/NesContainers.csproj index 089048c..56b8ae4 100644 --- a/NesContainers.csproj +++ b/NesContainers.csproj @@ -43,9 +43,9 @@ - + - + diff --git a/UnifFile.cs b/UnifFile.cs index 0e9606e..f6d586c 100644 --- a/UnifFile.cs +++ b/UnifFile.cs @@ -54,6 +54,11 @@ namespace com.clusterrr.Famicom.Containers { } + public static UnifFile FromBytes(byte[] data) + { + return new UnifFile(data); + } + /// /// Save UNIF file /// -- cgit v1.2.3