mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
[Aaru.Images] Reformat and cleanup.
This commit is contained in:
@@ -20,18 +20,27 @@ public class AtariLynx : IByteAddressableImage
|
||||
Stream _dataStream;
|
||||
ImageInfo _imageInfo;
|
||||
bool _opened;
|
||||
|
||||
#region IByteAddressableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => Authors.NataliaPortillo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Metadata AaruMetadata => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<DumpHardware> DumpHardware => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Format => "Atari Lynx cartridge dump";
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("809A6835-0486-4FD3-BD8B-2EF40C3EF97B");
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageInfo Info => _imageInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Localization.AtariLynx_Name;
|
||||
|
||||
@@ -48,9 +57,9 @@ public class AtariLynx : IByteAddressableImage
|
||||
return false;
|
||||
|
||||
stream.Position = 0;
|
||||
byte[] magicBytes = new byte[4];
|
||||
var magicBytes = new byte[4];
|
||||
stream.EnsureRead(magicBytes, 0, 4);
|
||||
uint magic = BitConverter.ToUInt32(magicBytes, 0);
|
||||
var magic = BitConverter.ToUInt32(magicBytes, 0);
|
||||
|
||||
// "LYNX"
|
||||
return magic == 0x584E594C;
|
||||
@@ -69,14 +78,14 @@ public class AtariLynx : IByteAddressableImage
|
||||
return ErrorNumber.InvalidArgument;
|
||||
|
||||
stream.Position = 0x0;
|
||||
byte[] magicBytes = new byte[4];
|
||||
var magicBytes = new byte[4];
|
||||
stream.EnsureRead(magicBytes, 0, 4);
|
||||
uint magic = BitConverter.ToUInt32(magicBytes, 0);
|
||||
var magic = BitConverter.ToUInt32(magicBytes, 0);
|
||||
|
||||
if(magic != 0x584E594C)
|
||||
return ErrorNumber.InvalidArgument;
|
||||
|
||||
byte[] headerBytes = new byte[64];
|
||||
var headerBytes = new byte[64];
|
||||
stream.Position = 0;
|
||||
stream.EnsureRead(headerBytes, 0, 64);
|
||||
|
||||
@@ -104,7 +113,7 @@ public class AtariLynx : IByteAddressableImage
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.AppendFormat(Localization.Name_0, _imageInfo.MediaTitle).AppendLine();
|
||||
sb.AppendFormat(Localization.Name_0, _imageInfo.MediaTitle).AppendLine();
|
||||
sb.AppendFormat(Localization.Manufacturer_0, _imageInfo.MediaManufacturer).AppendLine();
|
||||
|
||||
sb.AppendFormat(Localization.Bank_zero_size_0_pages_1_bytes, header.Bank0Length, header.Bank0Length * 65536).
|
||||
@@ -123,29 +132,29 @@ public class AtariLynx : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsWriting { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> KnownExtensions => new[]
|
||||
{
|
||||
".lnx"
|
||||
};
|
||||
public IEnumerable<string> KnownExtensions => new[] { ".lnx" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => Array.Empty<MediaTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[]
|
||||
{
|
||||
MediaType.AtariLynxCard
|
||||
};
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[] { MediaType.AtariLynxCard };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions =>
|
||||
Array.Empty<(string name, Type type, string description, object @default)>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => Array.Empty<SectorTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Close()
|
||||
@@ -168,8 +177,8 @@ public class AtariLynx : IByteAddressableImage
|
||||
|
||||
HandyHeader header = new()
|
||||
{
|
||||
Bank0Length = (short)(_data.Length > 4 * 131072 ? 4 * 131072 / 256 : _data.Length / 256),
|
||||
Bank1Length = (short)(_data.Length > 4 * 131072 ? (_data.Length - (4 * 131072)) / 256 : 0),
|
||||
Bank0Length = (short)(_data.Length > 4 * 131072 ? 4 * 131072 / 256 : _data.Length / 256),
|
||||
Bank1Length = (short)(_data.Length > 4 * 131072 ? (_data.Length - 4 * 131072) / 256 : 0),
|
||||
Magic = 0x584E594C,
|
||||
Manufacturer = new byte[16],
|
||||
Name = new byte[32],
|
||||
@@ -185,7 +194,7 @@ public class AtariLynx : IByteAddressableImage
|
||||
byte[] headerBytes = Marshal.StructureToByteArrayBigEndian(header);
|
||||
|
||||
_dataStream.Write(headerBytes, 0, headerBytes.Length);
|
||||
_dataStream.Write(_data, 0, _data.Length);
|
||||
_dataStream.Write(_data, 0, _data.Length);
|
||||
_dataStream.Close();
|
||||
|
||||
IsWriting = false;
|
||||
@@ -396,18 +405,21 @@ public class AtariLynx : IByteAddressableImage
|
||||
return ErrorNumber.ReadOnly;
|
||||
}
|
||||
|
||||
bool foundRom = false;
|
||||
var foundRom = false;
|
||||
|
||||
// Sanitize
|
||||
foreach(LinearMemoryDevice map in mappings.Devices)
|
||||
{
|
||||
switch(map.Type)
|
||||
{
|
||||
case LinearMemoryType.ROM when !foundRom:
|
||||
foundRom = true;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.InvalidArgument;
|
||||
default:
|
||||
return ErrorNumber.InvalidArgument;
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot save in this image format anyway
|
||||
return foundRom ? ErrorNumber.NoError : ErrorNumber.InvalidArgument;
|
||||
@@ -450,7 +462,7 @@ public class AtariLynx : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber WriteBytes(byte[] buffer, int offset, int bytesToWrite, out int bytesWritten,
|
||||
bool advance = true) =>
|
||||
bool advance = true) =>
|
||||
WriteBytesAt(Position, buffer, offset, bytesToWrite, out bytesWritten, advance);
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -503,8 +515,13 @@ public class AtariLynx : IByteAddressableImage
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1), SuppressMessage("ReSharper", "MemberCanBePrivate.Local"),
|
||||
SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")]
|
||||
#endregion
|
||||
|
||||
#region Nested type: HandyHeader
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Local")]
|
||||
[SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")]
|
||||
struct HandyHeader
|
||||
{
|
||||
public uint Magic;
|
||||
@@ -519,4 +536,6 @@ public class AtariLynx : IByteAddressableImage
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
|
||||
public byte[] Spare;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -20,18 +20,27 @@ public class GameBoy : IByteAddressableImage
|
||||
Stream _dataStream;
|
||||
ImageInfo _imageInfo;
|
||||
bool _opened;
|
||||
|
||||
#region IByteAddressableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => Authors.NataliaPortillo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Metadata AaruMetadata => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<DumpHardware> DumpHardware => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Format => "Nintendo Game Boy cartridge dump";
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("04AFDB93-587E-413B-9B52-10D4A92966CF");
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageInfo Info => _imageInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Localization.GameBoy_Name;
|
||||
|
||||
@@ -48,9 +57,9 @@ public class GameBoy : IByteAddressableImage
|
||||
return false;
|
||||
|
||||
stream.Position = 0x104;
|
||||
byte[] magicBytes = new byte[8];
|
||||
var magicBytes = new byte[8];
|
||||
stream.EnsureRead(magicBytes, 0, 8);
|
||||
ulong magic = BitConverter.ToUInt64(magicBytes, 0);
|
||||
var magic = BitConverter.ToUInt64(magicBytes, 0);
|
||||
|
||||
return magic == 0x0B000DCC6666EDCE;
|
||||
}
|
||||
@@ -68,9 +77,9 @@ public class GameBoy : IByteAddressableImage
|
||||
return ErrorNumber.InvalidArgument;
|
||||
|
||||
stream.Position = 0x104;
|
||||
byte[] magicBytes = new byte[8];
|
||||
var magicBytes = new byte[8];
|
||||
stream.EnsureRead(magicBytes, 0, 8);
|
||||
ulong magic = BitConverter.ToUInt64(magicBytes, 0);
|
||||
var magic = BitConverter.ToUInt64(magicBytes, 0);
|
||||
|
||||
if(magic != 0x0B000DCC6666EDCE)
|
||||
return ErrorNumber.InvalidArgument;
|
||||
@@ -92,7 +101,7 @@ public class GameBoy : IByteAddressableImage
|
||||
|
||||
Header header = Marshal.ByteArrayToStructureBigEndian<Header>(_data, 0x100, Marshal.SizeOf<Header>());
|
||||
|
||||
byte[] name = new byte[(header.Name[^1] & 0x80) == 0x80 ? 15 : 16];
|
||||
var name = new byte[(header.Name[^1] & 0x80) == 0x80 ? 15 : 16];
|
||||
Array.Copy(header.Name, 0, name, 0, name.Length);
|
||||
|
||||
_imageInfo.MediaTitle = StringHandlers.CToString(name);
|
||||
@@ -134,29 +143,29 @@ public class GameBoy : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsWriting { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> KnownExtensions => new[]
|
||||
{
|
||||
".gb", ".gbc", ".sgb"
|
||||
};
|
||||
public IEnumerable<string> KnownExtensions => new[] { ".gb", ".gbc", ".sgb" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => Array.Empty<MediaTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[]
|
||||
{
|
||||
MediaType.GameBoyGamePak
|
||||
};
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[] { MediaType.GameBoyGamePak };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions =>
|
||||
Array.Empty<(string name, Type type, string description, object @default)>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => Array.Empty<SectorTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Close()
|
||||
@@ -253,8 +262,8 @@ public class GameBoy : IByteAddressableImage
|
||||
|
||||
Header header = Marshal.ByteArrayToStructureBigEndian<Header>(_data, 0x100, Marshal.SizeOf<Header>());
|
||||
|
||||
bool hasMapper = false;
|
||||
bool hasSaveRam = false;
|
||||
var hasMapper = false;
|
||||
var hasSaveRam = false;
|
||||
string mapperManufacturer = null;
|
||||
string mapperName = null;
|
||||
|
||||
@@ -474,7 +483,7 @@ public class GameBoy : IByteAddressableImage
|
||||
if(header.SramSize > 0)
|
||||
hasSaveRam = true;
|
||||
|
||||
int devices = 1;
|
||||
var devices = 1;
|
||||
|
||||
if(hasSaveRam)
|
||||
devices++;
|
||||
@@ -493,6 +502,7 @@ public class GameBoy : IByteAddressableImage
|
||||
};
|
||||
|
||||
if(hasSaveRam)
|
||||
{
|
||||
mappings.Devices[1] = new LinearMemoryDevice
|
||||
{
|
||||
Type = LinearMemoryType.SaveRAM,
|
||||
@@ -502,14 +512,17 @@ public class GameBoy : IByteAddressableImage
|
||||
Length = DecodeSaveRamSize(header.SramSize)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if(hasMapper)
|
||||
{
|
||||
mappings.Devices[^1] = new LinearMemoryDevice
|
||||
{
|
||||
Type = LinearMemoryType.Mapper,
|
||||
Manufacturer = mapperManufacturer,
|
||||
Model = mapperName
|
||||
};
|
||||
}
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
@@ -608,12 +621,13 @@ public class GameBoy : IByteAddressableImage
|
||||
return ErrorNumber.ReadOnly;
|
||||
}
|
||||
|
||||
bool foundRom = false;
|
||||
bool foundSaveRam = false;
|
||||
bool foundMapper = false;
|
||||
var foundRom = false;
|
||||
var foundSaveRam = false;
|
||||
var foundMapper = false;
|
||||
|
||||
// Sanitize
|
||||
foreach(LinearMemoryDevice map in mappings.Devices)
|
||||
{
|
||||
switch(map.Type)
|
||||
{
|
||||
case LinearMemoryType.ROM when !foundRom:
|
||||
@@ -628,8 +642,10 @@ public class GameBoy : IByteAddressableImage
|
||||
foundMapper = true;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.InvalidArgument;
|
||||
default:
|
||||
return ErrorNumber.InvalidArgument;
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot save in this image format anyway
|
||||
return foundRom ? ErrorNumber.NoError : ErrorNumber.InvalidArgument;
|
||||
@@ -672,7 +688,7 @@ public class GameBoy : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber WriteBytes(byte[] buffer, int offset, int bytesToWrite, out int bytesWritten,
|
||||
bool advance = true) =>
|
||||
bool advance = true) =>
|
||||
WriteBytesAt(Position, buffer, offset, bytesToWrite, out bytesWritten, advance);
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -725,294 +741,303 @@ public class GameBoy : IByteAddressableImage
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[SuppressMessage("ReSharper", "StringLiteralTypo")]
|
||||
static string DecodeLicensee(byte headerLicensee, byte[] headerLicenseeNew)
|
||||
{
|
||||
if(headerLicensee != 0x33)
|
||||
{
|
||||
return headerLicensee switch
|
||||
{
|
||||
0x00 => Localization.none_licensee,
|
||||
0x01 => "nintendo",
|
||||
0x08 => "capcom",
|
||||
0x09 => "hot-b",
|
||||
0x0A => "jaleco",
|
||||
0x0B => "coconuts",
|
||||
0x0C => "elite systems",
|
||||
0x13 => "electronic arts",
|
||||
0x18 => "hudsonsoft",
|
||||
0x19 => "itc entertainment",
|
||||
0x1A => "yanoman",
|
||||
0x1D => "clary",
|
||||
0x1F => "virgin",
|
||||
0x20 => "KSS",
|
||||
0x24 => "pcm complete",
|
||||
0x25 => "san-x",
|
||||
0x28 => "kotobuki systems",
|
||||
0x29 => "seta",
|
||||
0x30 => "infogrames",
|
||||
0x31 => "nintendo",
|
||||
0x32 => "bandai",
|
||||
0x33 => Localization.GBC_see_above,
|
||||
0x34 => "konami",
|
||||
0x35 => "hector",
|
||||
0x38 => "Capcom",
|
||||
0x39 => "Banpresto",
|
||||
0x3C => "*entertainment i",
|
||||
0x3E => "gremlin",
|
||||
0x41 => "Ubisoft",
|
||||
0x42 => "Atlus",
|
||||
0x44 => "Malibu",
|
||||
0x46 => "angel",
|
||||
0x47 => "spectrum holoby",
|
||||
0x49 => "irem",
|
||||
0x4A => "virgin",
|
||||
0x4D => "malibu",
|
||||
0x4F => "u.s. gold",
|
||||
0x50 => "absolute",
|
||||
0x51 => "acclaim",
|
||||
0x52 => "activision",
|
||||
0x53 => "american sammy",
|
||||
0x54 => "gametek",
|
||||
0x55 => "park place",
|
||||
0x56 => "ljn",
|
||||
0x57 => "matchbox",
|
||||
0x59 => "milton bradley",
|
||||
0x5A => "mindscape",
|
||||
0x5B => "romstar",
|
||||
0x5C => "naxat soft",
|
||||
0x5D => "tradewest",
|
||||
0x60 => "titus",
|
||||
0x61 => "virgin",
|
||||
0x67 => "ocean",
|
||||
0x69 => "electronic arts",
|
||||
0x6E => "elite systems",
|
||||
0x6F => "electro brain",
|
||||
0x70 => "Infogrammes",
|
||||
0x71 => "Interplay",
|
||||
0x72 => "broderbund",
|
||||
0x73 => "sculptered soft",
|
||||
0x75 => "the sales curve",
|
||||
0x78 => "t*hq",
|
||||
0x79 => "accolade",
|
||||
0x7A => "triffix entertainment",
|
||||
0x7C => "microprose",
|
||||
0x7F => "kemco",
|
||||
0x80 => "misawa entertainment",
|
||||
0x83 => "lozc",
|
||||
0x86 => "tokuma shoten intermedia",
|
||||
0x8B => "bullet-proof software",
|
||||
0x8C => "vic tokai",
|
||||
0x8E => "ape",
|
||||
0x8F => "i'max",
|
||||
0x91 => "chun soft",
|
||||
0x92 => "video system",
|
||||
0x93 => "tsuburava",
|
||||
0x95 => "varie",
|
||||
0x96 => "yonezawa/s'pal",
|
||||
0x97 => "kaneko",
|
||||
0x99 => "arc",
|
||||
0x9A => "nihon bussan",
|
||||
0x9B => "Tecmo",
|
||||
0x9C => "imagineer",
|
||||
0x9D => "Banpresto",
|
||||
0x9F => "nova",
|
||||
0xA1 => "Hori electric",
|
||||
0xA2 => "Bandai",
|
||||
0xA4 => "Konami",
|
||||
0xA6 => "kawada",
|
||||
0xA7 => "takara",
|
||||
0xA9 => "technos japan",
|
||||
0xAA => "broderbund",
|
||||
0xAC => "Toei animation",
|
||||
0xAD => "toho",
|
||||
0xAF => "Namco",
|
||||
0xB0 => "Acclaim",
|
||||
0xB1 => "ascii or nexoft",
|
||||
0xB2 => "Bandai",
|
||||
0xB4 => "Enix",
|
||||
0xB6 => "HAL",
|
||||
0xB7 => "SNK",
|
||||
0xB9 => "pony canyon",
|
||||
0xBA => "*culture brain o",
|
||||
0xBB => "Sunsoft",
|
||||
0xBD => "Sony imagesoft",
|
||||
0xBF => "sammy",
|
||||
0xC0 => "Taito",
|
||||
0xC2 => "Kemco",
|
||||
0xC3 => "Squaresoft",
|
||||
0xC4 => "tokuma shoten intermedia",
|
||||
0xC5 => "data east",
|
||||
0xC6 => "tonkin house",
|
||||
0xC8 => "koei",
|
||||
0xC9 => "ufl",
|
||||
0xCA => "ultra",
|
||||
0xCB => "vap",
|
||||
0xCC => "use",
|
||||
0xCD => "meldac",
|
||||
0xCE => "*pony canyon or",
|
||||
0xCF => "angel",
|
||||
0xD0 => "Taito",
|
||||
0xD1 => "sofel",
|
||||
0xD2 => "quest",
|
||||
0xD3 => "sigma enterprises",
|
||||
0xD4 => "ask kodansha",
|
||||
0xD6 => "naxat soft",
|
||||
0xD7 => "copya systems",
|
||||
0xD9 => "Banpresto",
|
||||
0xDA => "tomy",
|
||||
0xDB => "ljn",
|
||||
0xDD => "ncs",
|
||||
0xDE => "human",
|
||||
0xDF => "altron",
|
||||
0xE0 => "jaleco",
|
||||
0xE1 => "towachiki",
|
||||
0xE2 => "uutaka",
|
||||
0xE3 => "varie",
|
||||
0xE5 => "epoch",
|
||||
0xE7 => "athena",
|
||||
0xE8 => "asmik",
|
||||
0xE9 => "natsume",
|
||||
0xEA => "king records",
|
||||
0xEB => "atlus",
|
||||
0xEC => "Epic/Sony records",
|
||||
0xEE => "igs",
|
||||
0xF0 => "a wave",
|
||||
0xF3 => "extreme entertainment",
|
||||
0xFF => "ljn",
|
||||
_ => Localization.Unknown_licensee
|
||||
};
|
||||
{
|
||||
0x00 => Localization.none_licensee,
|
||||
0x01 => "nintendo",
|
||||
0x08 => "capcom",
|
||||
0x09 => "hot-b",
|
||||
0x0A => "jaleco",
|
||||
0x0B => "coconuts",
|
||||
0x0C => "elite systems",
|
||||
0x13 => "electronic arts",
|
||||
0x18 => "hudsonsoft",
|
||||
0x19 => "itc entertainment",
|
||||
0x1A => "yanoman",
|
||||
0x1D => "clary",
|
||||
0x1F => "virgin",
|
||||
0x20 => "KSS",
|
||||
0x24 => "pcm complete",
|
||||
0x25 => "san-x",
|
||||
0x28 => "kotobuki systems",
|
||||
0x29 => "seta",
|
||||
0x30 => "infogrames",
|
||||
0x31 => "nintendo",
|
||||
0x32 => "bandai",
|
||||
0x33 => Localization.GBC_see_above,
|
||||
0x34 => "konami",
|
||||
0x35 => "hector",
|
||||
0x38 => "Capcom",
|
||||
0x39 => "Banpresto",
|
||||
0x3C => "*entertainment i",
|
||||
0x3E => "gremlin",
|
||||
0x41 => "Ubisoft",
|
||||
0x42 => "Atlus",
|
||||
0x44 => "Malibu",
|
||||
0x46 => "angel",
|
||||
0x47 => "spectrum holoby",
|
||||
0x49 => "irem",
|
||||
0x4A => "virgin",
|
||||
0x4D => "malibu",
|
||||
0x4F => "u.s. gold",
|
||||
0x50 => "absolute",
|
||||
0x51 => "acclaim",
|
||||
0x52 => "activision",
|
||||
0x53 => "american sammy",
|
||||
0x54 => "gametek",
|
||||
0x55 => "park place",
|
||||
0x56 => "ljn",
|
||||
0x57 => "matchbox",
|
||||
0x59 => "milton bradley",
|
||||
0x5A => "mindscape",
|
||||
0x5B => "romstar",
|
||||
0x5C => "naxat soft",
|
||||
0x5D => "tradewest",
|
||||
0x60 => "titus",
|
||||
0x61 => "virgin",
|
||||
0x67 => "ocean",
|
||||
0x69 => "electronic arts",
|
||||
0x6E => "elite systems",
|
||||
0x6F => "electro brain",
|
||||
0x70 => "Infogrammes",
|
||||
0x71 => "Interplay",
|
||||
0x72 => "broderbund",
|
||||
0x73 => "sculptered soft",
|
||||
0x75 => "the sales curve",
|
||||
0x78 => "t*hq",
|
||||
0x79 => "accolade",
|
||||
0x7A => "triffix entertainment",
|
||||
0x7C => "microprose",
|
||||
0x7F => "kemco",
|
||||
0x80 => "misawa entertainment",
|
||||
0x83 => "lozc",
|
||||
0x86 => "tokuma shoten intermedia",
|
||||
0x8B => "bullet-proof software",
|
||||
0x8C => "vic tokai",
|
||||
0x8E => "ape",
|
||||
0x8F => "i'max",
|
||||
0x91 => "chun soft",
|
||||
0x92 => "video system",
|
||||
0x93 => "tsuburava",
|
||||
0x95 => "varie",
|
||||
0x96 => "yonezawa/s'pal",
|
||||
0x97 => "kaneko",
|
||||
0x99 => "arc",
|
||||
0x9A => "nihon bussan",
|
||||
0x9B => "Tecmo",
|
||||
0x9C => "imagineer",
|
||||
0x9D => "Banpresto",
|
||||
0x9F => "nova",
|
||||
0xA1 => "Hori electric",
|
||||
0xA2 => "Bandai",
|
||||
0xA4 => "Konami",
|
||||
0xA6 => "kawada",
|
||||
0xA7 => "takara",
|
||||
0xA9 => "technos japan",
|
||||
0xAA => "broderbund",
|
||||
0xAC => "Toei animation",
|
||||
0xAD => "toho",
|
||||
0xAF => "Namco",
|
||||
0xB0 => "Acclaim",
|
||||
0xB1 => "ascii or nexoft",
|
||||
0xB2 => "Bandai",
|
||||
0xB4 => "Enix",
|
||||
0xB6 => "HAL",
|
||||
0xB7 => "SNK",
|
||||
0xB9 => "pony canyon",
|
||||
0xBA => "*culture brain o",
|
||||
0xBB => "Sunsoft",
|
||||
0xBD => "Sony imagesoft",
|
||||
0xBF => "sammy",
|
||||
0xC0 => "Taito",
|
||||
0xC2 => "Kemco",
|
||||
0xC3 => "Squaresoft",
|
||||
0xC4 => "tokuma shoten intermedia",
|
||||
0xC5 => "data east",
|
||||
0xC6 => "tonkin house",
|
||||
0xC8 => "koei",
|
||||
0xC9 => "ufl",
|
||||
0xCA => "ultra",
|
||||
0xCB => "vap",
|
||||
0xCC => "use",
|
||||
0xCD => "meldac",
|
||||
0xCE => "*pony canyon or",
|
||||
0xCF => "angel",
|
||||
0xD0 => "Taito",
|
||||
0xD1 => "sofel",
|
||||
0xD2 => "quest",
|
||||
0xD3 => "sigma enterprises",
|
||||
0xD4 => "ask kodansha",
|
||||
0xD6 => "naxat soft",
|
||||
0xD7 => "copya systems",
|
||||
0xD9 => "Banpresto",
|
||||
0xDA => "tomy",
|
||||
0xDB => "ljn",
|
||||
0xDD => "ncs",
|
||||
0xDE => "human",
|
||||
0xDF => "altron",
|
||||
0xE0 => "jaleco",
|
||||
0xE1 => "towachiki",
|
||||
0xE2 => "uutaka",
|
||||
0xE3 => "varie",
|
||||
0xE5 => "epoch",
|
||||
0xE7 => "athena",
|
||||
0xE8 => "asmik",
|
||||
0xE9 => "natsume",
|
||||
0xEA => "king records",
|
||||
0xEB => "atlus",
|
||||
0xEC => "Epic/Sony records",
|
||||
0xEE => "igs",
|
||||
0xF0 => "a wave",
|
||||
0xF3 => "extreme entertainment",
|
||||
0xFF => "ljn",
|
||||
_ => Localization.Unknown_licensee
|
||||
};
|
||||
}
|
||||
|
||||
string licenseeNew = StringHandlers.CToString(headerLicenseeNew);
|
||||
|
||||
return licenseeNew switch
|
||||
{
|
||||
"00" => Localization.none_licensee,
|
||||
"01" => "Nintendo R&D1",
|
||||
"08" => "Capcom",
|
||||
"13" => "Electronic Arts",
|
||||
"18" => "Hudson Soft",
|
||||
"19" => "b-ai",
|
||||
"20" => "kss",
|
||||
"22" => "pow",
|
||||
"24" => "PCM Complete",
|
||||
"25" => "san-x",
|
||||
"28" => "Kemco Japan",
|
||||
"29" => "seta",
|
||||
"30" => "Viacom",
|
||||
"31" => "Nintendo",
|
||||
"32" => "Bandai",
|
||||
"33" => "Ocean / Acclaim",
|
||||
"34" => "Konami",
|
||||
"35" => "Hector",
|
||||
"37" => "Taito",
|
||||
"38" => "Hudson",
|
||||
"39" => "Banpresto",
|
||||
"41" => "Ubi Soft",
|
||||
"42" => "Atlus",
|
||||
"44" => "Malibu",
|
||||
"46" => "angel",
|
||||
"47" => "Bullet -Proof",
|
||||
"49" => "irem",
|
||||
"50" => "Absolute",
|
||||
"51" => "Acclaim",
|
||||
"52" => "Activision",
|
||||
"53" => "American sammy",
|
||||
"54" => "Konami",
|
||||
"55" => "Hi tech entertainment",
|
||||
"56" => "LJN",
|
||||
"57" => "Matchbox",
|
||||
"58" => "Mattel",
|
||||
"59" => "Milton Bradley",
|
||||
"60" => "Titus",
|
||||
"61" => "Virgin",
|
||||
"64" => "LucasArts",
|
||||
"67" => "Ocean",
|
||||
"69" => "Electronic Arts",
|
||||
"70" => "Infogrames",
|
||||
"71" => "Interplay",
|
||||
"72" => "Brøderbund",
|
||||
"73" => "sculptured",
|
||||
"75" => "sci",
|
||||
"78" => "THQ",
|
||||
"79" => "Accolade",
|
||||
"80" => "misawa",
|
||||
"83" => "lozc",
|
||||
"86" => "tokuma shoten i",
|
||||
"87" => "tsukuda ori",
|
||||
"91" => "Chunsoft",
|
||||
"92" => "Video system",
|
||||
"93" => "Ocean / Acclaim",
|
||||
"95" => "Varie",
|
||||
"96" => "Yonezawa / s'pal",
|
||||
"97" => "Kaneko",
|
||||
"99" => "Pack in soft",
|
||||
"A4" => "Konami",
|
||||
_ => Localization.Unknown_licensee
|
||||
};
|
||||
{
|
||||
"00" => Localization.none_licensee,
|
||||
"01" => "Nintendo R&D1",
|
||||
"08" => "Capcom",
|
||||
"13" => "Electronic Arts",
|
||||
"18" => "Hudson Soft",
|
||||
"19" => "b-ai",
|
||||
"20" => "kss",
|
||||
"22" => "pow",
|
||||
"24" => "PCM Complete",
|
||||
"25" => "san-x",
|
||||
"28" => "Kemco Japan",
|
||||
"29" => "seta",
|
||||
"30" => "Viacom",
|
||||
"31" => "Nintendo",
|
||||
"32" => "Bandai",
|
||||
"33" => "Ocean / Acclaim",
|
||||
"34" => "Konami",
|
||||
"35" => "Hector",
|
||||
"37" => "Taito",
|
||||
"38" => "Hudson",
|
||||
"39" => "Banpresto",
|
||||
"41" => "Ubi Soft",
|
||||
"42" => "Atlus",
|
||||
"44" => "Malibu",
|
||||
"46" => "angel",
|
||||
"47" => "Bullet -Proof",
|
||||
"49" => "irem",
|
||||
"50" => "Absolute",
|
||||
"51" => "Acclaim",
|
||||
"52" => "Activision",
|
||||
"53" => "American sammy",
|
||||
"54" => "Konami",
|
||||
"55" => "Hi tech entertainment",
|
||||
"56" => "LJN",
|
||||
"57" => "Matchbox",
|
||||
"58" => "Mattel",
|
||||
"59" => "Milton Bradley",
|
||||
"60" => "Titus",
|
||||
"61" => "Virgin",
|
||||
"64" => "LucasArts",
|
||||
"67" => "Ocean",
|
||||
"69" => "Electronic Arts",
|
||||
"70" => "Infogrames",
|
||||
"71" => "Interplay",
|
||||
"72" => "Brøderbund",
|
||||
"73" => "sculptured",
|
||||
"75" => "sci",
|
||||
"78" => "THQ",
|
||||
"79" => "Accolade",
|
||||
"80" => "misawa",
|
||||
"83" => "lozc",
|
||||
"86" => "tokuma shoten i",
|
||||
"87" => "tsukuda ori",
|
||||
"91" => "Chunsoft",
|
||||
"92" => "Video system",
|
||||
"93" => "Ocean / Acclaim",
|
||||
"95" => "Varie",
|
||||
"96" => "Yonezawa / s'pal",
|
||||
"97" => "Kaneko",
|
||||
"99" => "Pack in soft",
|
||||
"A4" => "Konami",
|
||||
_ => Localization.Unknown_licensee
|
||||
};
|
||||
}
|
||||
|
||||
static uint DecodeRomSize(byte headerRomType) => headerRomType switch
|
||||
{
|
||||
0 => 32768,
|
||||
1 => 65536,
|
||||
2 => 131072,
|
||||
3 => 262144,
|
||||
4 => 524288,
|
||||
5 => 1048576,
|
||||
6 => 2097152,
|
||||
7 => 4194304,
|
||||
8 => 8388608,
|
||||
0x52 => 1179648,
|
||||
0x53 => 1310720,
|
||||
0x54 => 1572864,
|
||||
_ => 0
|
||||
};
|
||||
{
|
||||
0 => 32768,
|
||||
1 => 65536,
|
||||
2 => 131072,
|
||||
3 => 262144,
|
||||
4 => 524288,
|
||||
5 => 1048576,
|
||||
6 => 2097152,
|
||||
7 => 4194304,
|
||||
8 => 8388608,
|
||||
0x52 => 1179648,
|
||||
0x53 => 1310720,
|
||||
0x54 => 1572864,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
static uint DecodeSaveRamSize(byte headerRamType) => headerRamType switch
|
||||
{
|
||||
0 => 0,
|
||||
1 => 2048,
|
||||
2 => 8192,
|
||||
3 => 32768,
|
||||
4 => 131072,
|
||||
5 => 65536,
|
||||
_ => 0
|
||||
};
|
||||
{
|
||||
0 => 0,
|
||||
1 => 2048,
|
||||
2 => 8192,
|
||||
3 => 32768,
|
||||
4 => 131072,
|
||||
5 => 65536,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
static string DecodeCartridgeType(byte headerRomType) => headerRomType switch
|
||||
{
|
||||
0x00 => Localization.ROM_only,
|
||||
0x01 => Localization.ROM_and_MBC1,
|
||||
0x02 => Localization.ROM_MBC1_and_RAM,
|
||||
0x03 => Localization.ROM_MBC1_RAM_and_battery,
|
||||
0x05 => Localization.ROM_and_MBC2,
|
||||
0x06 => Localization.ROM_MBC2_and_battery,
|
||||
0x08 => Localization.ROM_and_RAM,
|
||||
0x09 => Localization.ROM_RAM_and_battery,
|
||||
0x0B => Localization.ROM_and_MMM01,
|
||||
0x0C => Localization.ROM_MMM01_and_RAM,
|
||||
0x0D => Localization.ROM_MMM01_RAM_and_battery,
|
||||
0x0F => Localization.ROM_MBC3_timer_and_battery,
|
||||
0x10 => Localization.ROM_MBC3_RAM_timer_and_battery,
|
||||
0x11 => Localization.ROM_and_MBC3,
|
||||
0x12 => Localization.ROM_MBC3_and_RAM,
|
||||
0x13 => Localization.ROM_MBC3_RAM_and_battery,
|
||||
0x19 => Localization.ROM_and_MBC5,
|
||||
0x1A => Localization.ROM_MBC5_and_RAM,
|
||||
0x1B => Localization.ROM_MBC5_RAM_and_battery,
|
||||
0x1C => Localization.ROM_MBC5_and_vibration_motor,
|
||||
0x1D => Localization.ROM_MBC5_RAM_and_vibration_motor,
|
||||
0x1E => Localization.ROM_MBC5_RAM_battery_and_vibration_motor,
|
||||
0x20 => Localization.ROM_and_MBC6,
|
||||
0x22 => Localization.ROM_MBC7_RAM_battery_light_sensor_and_vibration_motor,
|
||||
0xFC => Localization.Pocket_Camera,
|
||||
0xFD => Localization.ROM_and_TAMA5,
|
||||
0xFE => Localization.ROM_and_HuC_3,
|
||||
0xFF => Localization.ROM_and_HuC_1,
|
||||
_ => Localization.Unknown_cartridge_type
|
||||
};
|
||||
{
|
||||
0x00 => Localization.ROM_only,
|
||||
0x01 => Localization.ROM_and_MBC1,
|
||||
0x02 => Localization.ROM_MBC1_and_RAM,
|
||||
0x03 => Localization.ROM_MBC1_RAM_and_battery,
|
||||
0x05 => Localization.ROM_and_MBC2,
|
||||
0x06 => Localization.ROM_MBC2_and_battery,
|
||||
0x08 => Localization.ROM_and_RAM,
|
||||
0x09 => Localization.ROM_RAM_and_battery,
|
||||
0x0B => Localization.ROM_and_MMM01,
|
||||
0x0C => Localization.ROM_MMM01_and_RAM,
|
||||
0x0D => Localization.ROM_MMM01_RAM_and_battery,
|
||||
0x0F => Localization.ROM_MBC3_timer_and_battery,
|
||||
0x10 => Localization.ROM_MBC3_RAM_timer_and_battery,
|
||||
0x11 => Localization.ROM_and_MBC3,
|
||||
0x12 => Localization.ROM_MBC3_and_RAM,
|
||||
0x13 => Localization.ROM_MBC3_RAM_and_battery,
|
||||
0x19 => Localization.ROM_and_MBC5,
|
||||
0x1A => Localization.ROM_MBC5_and_RAM,
|
||||
0x1B => Localization.ROM_MBC5_RAM_and_battery,
|
||||
0x1C => Localization.ROM_MBC5_and_vibration_motor,
|
||||
0x1D => Localization.ROM_MBC5_RAM_and_vibration_motor,
|
||||
0x1E => Localization.
|
||||
ROM_MBC5_RAM_battery_and_vibration_motor,
|
||||
0x20 => Localization.ROM_and_MBC6,
|
||||
0x22 => Localization.
|
||||
ROM_MBC7_RAM_battery_light_sensor_and_vibration_motor,
|
||||
0xFC => Localization.Pocket_Camera,
|
||||
0xFD => Localization.ROM_and_TAMA5,
|
||||
0xFE => Localization.ROM_and_HuC_3,
|
||||
0xFF => Localization.ROM_and_HuC_1,
|
||||
_ => Localization.Unknown_cartridge_type
|
||||
};
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1), SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")]
|
||||
#region Nested type: Header
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")]
|
||||
struct Header
|
||||
{
|
||||
/// <summary>Usually 0x00 (NOP)</summary>
|
||||
@@ -1049,4 +1074,6 @@ public class GameBoy : IByteAddressableImage
|
||||
/// <summary>Cartridge checksum</summary>
|
||||
public ushort Checksum;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -20,18 +20,27 @@ public class GameBoyAdvance : IByteAddressableImage
|
||||
Stream _dataStream;
|
||||
ImageInfo _imageInfo;
|
||||
bool _opened;
|
||||
|
||||
#region IByteAddressableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => Authors.NataliaPortillo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Metadata AaruMetadata => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<DumpHardware> DumpHardware => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Format => "Nintendo Game Boy Advance cartridge dump";
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("0040DDEB-3902-4402-9028-62915C5AA81F");
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageInfo Info => _imageInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Localization.GameBoyAdvance_Name;
|
||||
|
||||
@@ -48,9 +57,9 @@ public class GameBoyAdvance : IByteAddressableImage
|
||||
return false;
|
||||
|
||||
stream.Position = 4;
|
||||
byte[] magicBytes = new byte[8];
|
||||
var magicBytes = new byte[8];
|
||||
stream.EnsureRead(magicBytes, 0, 8);
|
||||
ulong magic = BitConverter.ToUInt64(magicBytes, 0);
|
||||
var magic = BitConverter.ToUInt64(magicBytes, 0);
|
||||
|
||||
return magic == 0x21A29A6951AEFF24;
|
||||
}
|
||||
@@ -68,9 +77,9 @@ public class GameBoyAdvance : IByteAddressableImage
|
||||
return ErrorNumber.InvalidArgument;
|
||||
|
||||
stream.Position = 4;
|
||||
byte[] magicBytes = new byte[8];
|
||||
var magicBytes = new byte[8];
|
||||
stream.EnsureRead(magicBytes, 0, 8);
|
||||
ulong magic = BitConverter.ToUInt64(magicBytes, 0);
|
||||
var magic = BitConverter.ToUInt64(magicBytes, 0);
|
||||
|
||||
if(magic != 0x21A29A6951AEFF24)
|
||||
return ErrorNumber.InvalidArgument;
|
||||
@@ -97,12 +106,12 @@ public class GameBoyAdvance : IByteAddressableImage
|
||||
|
||||
sb.AppendFormat(Localization.Name_0, _imageInfo.MediaTitle).AppendLine();
|
||||
|
||||
sb.AppendFormat(Localization.Device_type_0, header.DeviceType).AppendLine();
|
||||
sb.AppendFormat(Localization.Console_type_0, header.UnitCode).AppendLine();
|
||||
sb.AppendFormat(Localization.Device_type_0, header.DeviceType).AppendLine();
|
||||
sb.AppendFormat(Localization.Console_type_0, header.UnitCode).AppendLine();
|
||||
sb.AppendFormat(Localization.Product_code_AGB_0, StringHandlers.CToString(header.Code)).AppendLine();
|
||||
sb.AppendFormat(Localization.Maker_code_0, StringHandlers.CToString(header.Maker)).AppendLine();
|
||||
sb.AppendFormat(Localization.Revision_0, header.Revision).AppendLine();
|
||||
sb.AppendFormat(Localization.Header_checksum_0, header.ComplementCheck).AppendLine();
|
||||
sb.AppendFormat(Localization.Maker_code_0, StringHandlers.CToString(header.Maker)).AppendLine();
|
||||
sb.AppendFormat(Localization.Revision_0, header.Revision).AppendLine();
|
||||
sb.AppendFormat(Localization.Header_checksum_0, header.ComplementCheck).AppendLine();
|
||||
|
||||
_imageInfo.Comments = sb.ToString();
|
||||
_opened = true;
|
||||
@@ -112,29 +121,29 @@ public class GameBoyAdvance : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsWriting { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> KnownExtensions => new[]
|
||||
{
|
||||
".gba"
|
||||
};
|
||||
public IEnumerable<string> KnownExtensions => new[] { ".gba" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => Array.Empty<MediaTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[]
|
||||
{
|
||||
MediaType.GameBoyAdvanceGamePak
|
||||
};
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[] { MediaType.GameBoyAdvanceGamePak };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions =>
|
||||
Array.Empty<(string name, Type type, string description, object @default)>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => Array.Empty<SectorTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Close()
|
||||
@@ -342,11 +351,12 @@ public class GameBoyAdvance : IByteAddressableImage
|
||||
return ErrorNumber.ReadOnly;
|
||||
}
|
||||
|
||||
bool foundRom = false;
|
||||
bool foundSaveRam = false;
|
||||
var foundRom = false;
|
||||
var foundSaveRam = false;
|
||||
|
||||
// Sanitize
|
||||
foreach(LinearMemoryDevice map in mappings.Devices)
|
||||
{
|
||||
switch(map.Type)
|
||||
{
|
||||
case LinearMemoryType.ROM when !foundRom:
|
||||
@@ -357,8 +367,10 @@ public class GameBoyAdvance : IByteAddressableImage
|
||||
foundSaveRam = true;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.InvalidArgument;
|
||||
default:
|
||||
return ErrorNumber.InvalidArgument;
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot save in this image format anyway
|
||||
return foundRom ? ErrorNumber.NoError : ErrorNumber.InvalidArgument;
|
||||
@@ -401,7 +413,7 @@ public class GameBoyAdvance : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber WriteBytes(byte[] buffer, int offset, int bytesToWrite, out int bytesWritten,
|
||||
bool advance = true) =>
|
||||
bool advance = true) =>
|
||||
WriteBytesAt(Position, buffer, offset, bytesToWrite, out bytesWritten, advance);
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -454,8 +466,13 @@ public class GameBoyAdvance : IByteAddressableImage
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1), SuppressMessage("ReSharper", "MemberCanBePrivate.Local"),
|
||||
SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")]
|
||||
#endregion
|
||||
|
||||
#region Nested type: Header
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Local")]
|
||||
[SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")]
|
||||
struct Header
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||
@@ -478,4 +495,6 @@ public class GameBoyAdvance : IByteAddressableImage
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
||||
public byte[] Reserved2;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -22,18 +22,27 @@ public class MasterSystem : IByteAddressableImage
|
||||
ImageInfo _imageInfo;
|
||||
bool _opened;
|
||||
int _romSize;
|
||||
|
||||
#region IByteAddressableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => Authors.NataliaPortillo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Metadata AaruMetadata => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<DumpHardware> DumpHardware => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Format => _gameGear ? "Sega Game Gear cartridge dump" : "Sega Master System cartridge dump";
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("B0C02927-890D-41D0-8E95-C5D9A2A74131");
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageInfo Info => _imageInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Localization.MasterSystem_Name;
|
||||
|
||||
@@ -50,9 +59,9 @@ public class MasterSystem : IByteAddressableImage
|
||||
return false;
|
||||
|
||||
stream.Position = 0x7ff0;
|
||||
byte[] magicBytes = new byte[8];
|
||||
var magicBytes = new byte[8];
|
||||
stream.EnsureRead(magicBytes, 0, 8);
|
||||
ulong magic = BitConverter.ToUInt64(magicBytes, 0);
|
||||
var magic = BitConverter.ToUInt64(magicBytes, 0);
|
||||
|
||||
if(magic == 0x4147455320524D54)
|
||||
return true;
|
||||
@@ -85,12 +94,12 @@ public class MasterSystem : IByteAddressableImage
|
||||
if(stream.Length % 8192 != 0)
|
||||
return ErrorNumber.InvalidArgument;
|
||||
|
||||
int headerPosition = 0;
|
||||
var headerPosition = 0;
|
||||
|
||||
stream.Position = 0x7ff0;
|
||||
byte[] magicBytes = new byte[8];
|
||||
var magicBytes = new byte[8];
|
||||
stream.EnsureRead(magicBytes, 0, 8);
|
||||
ulong magic = BitConverter.ToUInt64(magicBytes, 0);
|
||||
var magic = BitConverter.ToUInt64(magicBytes, 0);
|
||||
|
||||
if(magic != 0x0B000DCC6666EDCE)
|
||||
headerPosition = 0x7ff0;
|
||||
@@ -135,9 +144,9 @@ public class MasterSystem : IByteAddressableImage
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
int productCode = (header.ProductCode[0] & 0xF) + ((header.ProductCode[0] & 0xF0) * 10) +
|
||||
((header.ProductCode[1] & 0xF) * 100) + ((header.ProductCode[1] & 0xF0) * 1000) +
|
||||
(((header.VersionAndProduct & 0xF0) >> 4) * 10000);
|
||||
int productCode = (header.ProductCode[0] & 0xF) + (header.ProductCode[0] & 0xF0) * 10 +
|
||||
(header.ProductCode[1] & 0xF) * 100 + (header.ProductCode[1] & 0xF0) * 1000 +
|
||||
((header.VersionAndProduct & 0xF0) >> 4) * 10000;
|
||||
|
||||
sb.AppendFormat(Localization.Product_code_0, productCode).AppendLine();
|
||||
|
||||
@@ -187,24 +196,24 @@ public class MasterSystem : IByteAddressableImage
|
||||
int sizeCode = header.SizeAndRegion & 0xF;
|
||||
|
||||
_romSize = sizeCode switch
|
||||
{
|
||||
0 => 262144,
|
||||
1 => 524288,
|
||||
2 => 1048576,
|
||||
0xA => 8192,
|
||||
0xB => 16384,
|
||||
0xC => 32768,
|
||||
0xD => 49152,
|
||||
0xE => 65536,
|
||||
0xF => 131072,
|
||||
_ => 0
|
||||
};
|
||||
{
|
||||
0 => 262144,
|
||||
1 => 524288,
|
||||
2 => 1048576,
|
||||
0xA => 8192,
|
||||
0xB => 16384,
|
||||
0xC => 32768,
|
||||
0xD => 49152,
|
||||
0xE => 65536,
|
||||
0xF => 131072,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
sb.AppendFormat(Localization.Region_0, region).AppendLine();
|
||||
sb.AppendFormat(Localization.Region_0, region).AppendLine();
|
||||
sb.AppendFormat(Localization.Cartridge_type_0, cartType).AppendLine();
|
||||
sb.AppendFormat(Localization.ROM_size_0_bytes, _romSize).AppendLine();
|
||||
sb.AppendFormat(Localization.Revision_0, header.VersionAndProduct & 0xF).AppendLine();
|
||||
sb.AppendFormat(Localization.Checksum_0_X4, header.Checksum).AppendLine();
|
||||
sb.AppendFormat(Localization.Revision_0, header.VersionAndProduct & 0xF).AppendLine();
|
||||
sb.AppendFormat(Localization.Checksum_0_X4, header.Checksum).AppendLine();
|
||||
|
||||
_imageInfo.Comments = sb.ToString();
|
||||
_opened = true;
|
||||
@@ -214,29 +223,32 @@ public class MasterSystem : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsWriting { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> KnownExtensions => new[]
|
||||
{
|
||||
".sms", ".gg"
|
||||
};
|
||||
public IEnumerable<string> KnownExtensions => new[] { ".sms", ".gg" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => Array.Empty<MediaTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[]
|
||||
{
|
||||
MediaType.MasterSystemCartridge, MediaType.GameGearCartridge
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions =>
|
||||
Array.Empty<(string name, Type type, string description, object @default)>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => Array.Empty<SectorTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Close()
|
||||
@@ -444,18 +456,21 @@ public class MasterSystem : IByteAddressableImage
|
||||
return ErrorNumber.ReadOnly;
|
||||
}
|
||||
|
||||
bool foundRom = false;
|
||||
var foundRom = false;
|
||||
|
||||
// Sanitize
|
||||
foreach(LinearMemoryDevice map in mappings.Devices)
|
||||
{
|
||||
switch(map.Type)
|
||||
{
|
||||
case LinearMemoryType.ROM when !foundRom:
|
||||
foundRom = true;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.InvalidArgument;
|
||||
default:
|
||||
return ErrorNumber.InvalidArgument;
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot save in this image format anyway
|
||||
return foundRom ? ErrorNumber.NoError : ErrorNumber.InvalidArgument;
|
||||
@@ -498,7 +513,7 @@ public class MasterSystem : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber WriteBytes(byte[] buffer, int offset, int bytesToWrite, out int bytesWritten,
|
||||
bool advance = true) =>
|
||||
bool advance = true) =>
|
||||
WriteBytesAt(Position, buffer, offset, bytesToWrite, out bytesWritten, advance);
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -551,8 +566,13 @@ public class MasterSystem : IByteAddressableImage
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1), SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local"),
|
||||
SuppressMessage("ReSharper", "MemberCanBePrivate.Local")]
|
||||
#endregion
|
||||
|
||||
#region Nested type: Header
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Local")]
|
||||
struct Header
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
||||
@@ -564,4 +584,6 @@ public class MasterSystem : IByteAddressableImage
|
||||
public byte VersionAndProduct;
|
||||
public byte SizeAndRegion;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -35,18 +35,27 @@ public class Nes : IByteAddressableImage
|
||||
int _promLen;
|
||||
byte _submapper;
|
||||
bool _trainer;
|
||||
|
||||
#region IByteAddressableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => Authors.NataliaPortillo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Metadata AaruMetadata => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<DumpHardware> DumpHardware => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Format => _nes20 ? "NES 2.0" : "iNES";
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("D597A3F4-2B1C-441C-8487-0BCABC509302");
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageInfo Info => _imageInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Localization.Nes_Name;
|
||||
|
||||
@@ -63,9 +72,9 @@ public class Nes : IByteAddressableImage
|
||||
return false;
|
||||
|
||||
stream.Position = 0;
|
||||
byte[] magicBytes = new byte[4];
|
||||
var magicBytes = new byte[4];
|
||||
stream.EnsureRead(magicBytes, 0, 8);
|
||||
uint magic = BitConverter.ToUInt32(magicBytes, 0);
|
||||
var magic = BitConverter.ToUInt32(magicBytes, 0);
|
||||
|
||||
return magic == 0x1A53454E;
|
||||
}
|
||||
@@ -83,9 +92,9 @@ public class Nes : IByteAddressableImage
|
||||
return ErrorNumber.InvalidArgument;
|
||||
|
||||
stream.Position = 0;
|
||||
byte[] header = new byte[16];
|
||||
var header = new byte[16];
|
||||
stream.EnsureRead(header, 0, 8);
|
||||
uint magic = BitConverter.ToUInt32(header, 0);
|
||||
var magic = BitConverter.ToUInt32(header, 0);
|
||||
|
||||
if(magic != 0x1A53454E)
|
||||
return ErrorNumber.InvalidArgument;
|
||||
@@ -105,7 +114,7 @@ public class Nes : IByteAddressableImage
|
||||
NametableMirroring = (header[6] & 0x1) != 0,
|
||||
BatteryPresent = (header[6] & 0x2) != 0,
|
||||
FourScreenMode = (header[6] & 0x8) != 0,
|
||||
Mapper = (ushort)((header[6] >> 4) | (header[7] & 0xF0))
|
||||
Mapper = (ushort)(header[6] >> 4 | header[7] & 0xF0)
|
||||
};
|
||||
|
||||
if((header[7] & 0x1) != 0)
|
||||
@@ -181,7 +190,7 @@ public class Nes : IByteAddressableImage
|
||||
sb.AppendFormat(Localization.PRG_ROM_size_0_bytes, _prgLen).AppendLine();
|
||||
sb.AppendFormat(Localization.CHR_ROM_size_0_bytes, _chrLen).AppendLine();
|
||||
sb.AppendFormat(Localization.Trainer_size_0_bytes, trainerLen).AppendLine();
|
||||
sb.AppendFormat(Localization.Mapper_0, _nesHeaderInfo.Mapper).AppendLine();
|
||||
sb.AppendFormat(Localization.Mapper_0, _nesHeaderInfo.Mapper).AppendLine();
|
||||
|
||||
if(_nesHeaderInfo.BatteryPresent)
|
||||
sb.AppendLine(Localization.Has_battery_backed_RAM);
|
||||
@@ -203,11 +212,12 @@ public class Nes : IByteAddressableImage
|
||||
case NesConsoleType.Playchoice:
|
||||
sb.AppendLine(Localization.PlayChoice_10_game);
|
||||
sb.AppendFormat(Localization.INST_ROM_size_0_bytes, _instRomLen & 0xF).AppendLine();
|
||||
sb.AppendFormat(Localization.PROM_size_0_bytes, _promLen).AppendLine();
|
||||
sb.AppendFormat(Localization.PROM_size_0_bytes, _promLen).AppendLine();
|
||||
|
||||
break;
|
||||
|
||||
case NesConsoleType.Nes: break;
|
||||
case NesConsoleType.Nes:
|
||||
break;
|
||||
case NesConsoleType.Extended:
|
||||
switch(_nesHeaderInfo.ExtendedConsoleType)
|
||||
{
|
||||
@@ -216,11 +226,12 @@ public class Nes : IByteAddressableImage
|
||||
|
||||
break;
|
||||
|
||||
case NesExtendedConsoleType.Normal: break;
|
||||
case NesExtendedConsoleType.Normal:
|
||||
break;
|
||||
case NesExtendedConsoleType.Playchoice:
|
||||
sb.AppendLine(Localization.PlayChoice_10_game);
|
||||
sb.AppendFormat(Localization.INST_ROM_size_0_bytes, _instRomLen & 0xF).AppendLine();
|
||||
sb.AppendFormat(Localization.PROM_size_0_bytes, _promLen).AppendLine();
|
||||
sb.AppendFormat(Localization.PROM_size_0_bytes, _promLen).AppendLine();
|
||||
|
||||
break;
|
||||
case NesExtendedConsoleType.VT01_Monochrome:
|
||||
@@ -262,29 +273,29 @@ public class Nes : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsWriting { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> KnownExtensions => new[]
|
||||
{
|
||||
".nes"
|
||||
};
|
||||
public IEnumerable<string> KnownExtensions => new[] { ".nes" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => Array.Empty<MediaTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[]
|
||||
{
|
||||
MediaType.NESGamePak, MediaType.FamicomGamePak
|
||||
};
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[] { MediaType.NESGamePak, MediaType.FamicomGamePak };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions =>
|
||||
Array.Empty<(string name, Type type, string description, object @default)>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => Array.Empty<SectorTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Close()
|
||||
@@ -303,7 +314,7 @@ public class Nes : IByteAddressableImage
|
||||
return false;
|
||||
}
|
||||
|
||||
byte[] header = new byte[16];
|
||||
var header = new byte[16];
|
||||
|
||||
if(_nesHeaderInfo is null)
|
||||
{
|
||||
@@ -323,8 +334,8 @@ public class Nes : IByteAddressableImage
|
||||
header[1] = 0x45;
|
||||
header[2] = 0x53;
|
||||
header[3] = 0x1A;
|
||||
header[4] = (byte)((_prgLen / 16384) & 0xFF);
|
||||
header[5] = (byte)((_chrLen / 8192) & 0xFF);
|
||||
header[4] = (byte)(_prgLen / 16384 & 0xFF);
|
||||
header[5] = (byte)(_chrLen / 8192 & 0xFF);
|
||||
header[6] = (byte)((_nesHeaderInfo.Mapper & 0xF) << 4);
|
||||
|
||||
if(_nesHeaderInfo.FourScreenMode)
|
||||
@@ -339,23 +350,24 @@ public class Nes : IByteAddressableImage
|
||||
if(_nesHeaderInfo.NametableMirroring)
|
||||
header[6] |= 0x1;
|
||||
|
||||
header[7] = (byte)((_mapper & 0xF0) | 0x8);
|
||||
header[7] = (byte)(_mapper & 0xF0 | 0x8);
|
||||
header[7] |= (byte)_nesHeaderInfo.ConsoleType;
|
||||
|
||||
header[8] = (byte)((_nesHeaderInfo.Submapper << 4) | ((_nesHeaderInfo.Mapper & 0xF00) >> 4));
|
||||
header[9] = (byte)((_prgLen / 16384) >> 8);
|
||||
header[9] |= (byte)(((_chrLen / 8192) >> 4) & 0xF);
|
||||
header[8] = (byte)(_nesHeaderInfo.Submapper << 4 | (_nesHeaderInfo.Mapper & 0xF00) >> 4);
|
||||
header[9] = (byte)(_prgLen / 16384 >> 8);
|
||||
header[9] |= (byte)(_chrLen / 8192 >> 4 & 0xF);
|
||||
|
||||
// TODO: PRG-RAM, PRG-NVRAM, CHR-RAM and CHR-NVRAM sizes
|
||||
|
||||
header[12] = (byte)_nesHeaderInfo.TimingMode;
|
||||
|
||||
header[13] = _nesHeaderInfo.ConsoleType switch
|
||||
{
|
||||
NesConsoleType.Vs => (byte)(((int)_nesHeaderInfo.VsHardwareType << 4) | (int)_nesHeaderInfo.VsPpuType),
|
||||
NesConsoleType.Extended => (byte)_nesHeaderInfo.ExtendedConsoleType,
|
||||
_ => header[13]
|
||||
};
|
||||
{
|
||||
NesConsoleType.Vs => (byte)((int)_nesHeaderInfo.VsHardwareType << 4 |
|
||||
(int)_nesHeaderInfo.VsPpuType),
|
||||
NesConsoleType.Extended => (byte)_nesHeaderInfo.ExtendedConsoleType,
|
||||
_ => header[13]
|
||||
};
|
||||
|
||||
header[14] = 0;
|
||||
|
||||
@@ -470,6 +482,7 @@ public class Nes : IByteAddressableImage
|
||||
};
|
||||
|
||||
if(_chrLen > 0)
|
||||
{
|
||||
devices.Add(new LinearMemoryDevice
|
||||
{
|
||||
Type = LinearMemoryType.CharacterROM,
|
||||
@@ -478,14 +491,18 @@ public class Nes : IByteAddressableImage
|
||||
Length = (ulong)_chrLen
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(_trainer)
|
||||
{
|
||||
devices.Add(new LinearMemoryDevice
|
||||
{
|
||||
Type = LinearMemoryType.Trainer
|
||||
});
|
||||
}
|
||||
|
||||
if(_instRomLen > 0)
|
||||
{
|
||||
devices.Add(new LinearMemoryDevice
|
||||
{
|
||||
Type = LinearMemoryType.ROM,
|
||||
@@ -494,8 +511,10 @@ public class Nes : IByteAddressableImage
|
||||
Length = (ulong)_instRomLen
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(_promLen > 0)
|
||||
{
|
||||
devices.Add(new LinearMemoryDevice
|
||||
{
|
||||
Type = LinearMemoryType.ROM,
|
||||
@@ -504,8 +523,10 @@ public class Nes : IByteAddressableImage
|
||||
Length = (ulong)_promLen
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(_prgRamLen > 0)
|
||||
{
|
||||
devices.Add(new LinearMemoryDevice
|
||||
{
|
||||
Type = LinearMemoryType.WorkRAM,
|
||||
@@ -514,8 +535,10 @@ public class Nes : IByteAddressableImage
|
||||
Length = (ulong)_prgRamLen
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(_chrRamLen > 0)
|
||||
{
|
||||
devices.Add(new LinearMemoryDevice
|
||||
{
|
||||
Type = LinearMemoryType.CharacterRAM,
|
||||
@@ -524,8 +547,10 @@ public class Nes : IByteAddressableImage
|
||||
Length = (ulong)_chrRamLen
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(_prgNvramLen > 0)
|
||||
{
|
||||
devices.Add(new LinearMemoryDevice
|
||||
{
|
||||
Type = LinearMemoryType.SaveRAM,
|
||||
@@ -534,8 +559,10 @@ public class Nes : IByteAddressableImage
|
||||
Length = (ulong)_prgNvramLen
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(_chrNvramLen > 0)
|
||||
{
|
||||
devices.Add(new LinearMemoryDevice
|
||||
{
|
||||
Type = LinearMemoryType.CharacterRAM,
|
||||
@@ -544,6 +571,7 @@ public class Nes : IByteAddressableImage
|
||||
Length = (ulong)_chrNvramLen
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ushort mapper = _nesHeaderInfo?.Mapper ?? _mapper;
|
||||
byte submapper = _nesHeaderInfo?.Submapper ?? _submapper;
|
||||
@@ -555,11 +583,13 @@ public class Nes : IByteAddressableImage
|
||||
});
|
||||
|
||||
if(submapper != 0)
|
||||
{
|
||||
devices.Add(new LinearMemoryDevice
|
||||
{
|
||||
Type = LinearMemoryType.Mapper,
|
||||
Description = $"NES Submapper {submapper}"
|
||||
});
|
||||
}
|
||||
|
||||
mappings = new LinearMemoryMap
|
||||
{
|
||||
@@ -663,22 +693,23 @@ public class Nes : IByteAddressableImage
|
||||
return ErrorNumber.ReadOnly;
|
||||
}
|
||||
|
||||
bool foundRom = false;
|
||||
bool foundChrRom = false;
|
||||
bool foundInstRom = false;
|
||||
bool foundProm = false;
|
||||
bool foundRam = false;
|
||||
bool foundChrRam = false;
|
||||
bool foundNvram = false;
|
||||
bool foundChrNvram = false;
|
||||
bool foundMapper = false;
|
||||
bool foundSubMapper = false;
|
||||
var foundRom = false;
|
||||
var foundChrRom = false;
|
||||
var foundInstRom = false;
|
||||
var foundProm = false;
|
||||
var foundRam = false;
|
||||
var foundChrRam = false;
|
||||
var foundNvram = false;
|
||||
var foundChrNvram = false;
|
||||
var foundMapper = false;
|
||||
var foundSubMapper = false;
|
||||
|
||||
Regex regex;
|
||||
Match match;
|
||||
|
||||
// Sanitize
|
||||
foreach(LinearMemoryDevice map in mappings.Devices)
|
||||
{
|
||||
switch(map.Type)
|
||||
{
|
||||
case LinearMemoryType.ROM when !foundRom:
|
||||
@@ -730,6 +761,7 @@ public class Nes : IByteAddressableImage
|
||||
match = regex.Match(map.Description);
|
||||
|
||||
if(match.Success)
|
||||
{
|
||||
if(ushort.TryParse(match.Groups["mapper"].Value, out ushort mapper))
|
||||
{
|
||||
if(_nesHeaderInfo is null)
|
||||
@@ -739,6 +771,7 @@ public class Nes : IByteAddressableImage
|
||||
|
||||
foundMapper = true;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case LinearMemoryType.Mapper when !foundSubMapper:
|
||||
@@ -746,6 +779,7 @@ public class Nes : IByteAddressableImage
|
||||
match = regex.Match(map.Description);
|
||||
|
||||
if(match.Success)
|
||||
{
|
||||
if(byte.TryParse(match.Groups["mapper"].Value, out byte mapper))
|
||||
{
|
||||
if(_nesHeaderInfo is null)
|
||||
@@ -755,10 +789,13 @@ public class Nes : IByteAddressableImage
|
||||
|
||||
foundSubMapper = true;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.InvalidArgument;
|
||||
default:
|
||||
return ErrorNumber.InvalidArgument;
|
||||
}
|
||||
}
|
||||
|
||||
return foundRom && foundMapper ? ErrorNumber.NoError : ErrorNumber.InvalidArgument;
|
||||
}
|
||||
@@ -800,7 +837,7 @@ public class Nes : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber WriteBytes(byte[] buffer, int offset, int bytesToWrite, out int bytesWritten,
|
||||
bool advance = true) =>
|
||||
bool advance = true) =>
|
||||
WriteBytesAt(Position, buffer, offset, bytesToWrite, out bytesWritten, advance);
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -852,4 +889,6 @@ public class Nes : IByteAddressableImage
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -56,22 +56,31 @@ public class Nintendo64 : IByteAddressableImage
|
||||
bool _interleaved;
|
||||
bool _littleEndian;
|
||||
bool _opened;
|
||||
|
||||
#region IByteAddressableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => Authors.NataliaPortillo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Metadata AaruMetadata => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<DumpHardware> DumpHardware => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Format => !_opened
|
||||
? "Nintendo 64 cartridge dump"
|
||||
: _interleaved
|
||||
? "Doctor V64"
|
||||
: "Mr. Backup Z64";
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("EF1B4319-48A0-4EEC-B8E8-D0EA36F8CC92");
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageInfo Info => _imageInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Localization.Nintendo64_Name;
|
||||
|
||||
@@ -88,9 +97,9 @@ public class Nintendo64 : IByteAddressableImage
|
||||
return false;
|
||||
|
||||
stream.Position = 0;
|
||||
byte[] magicBytes = new byte[4];
|
||||
var magicBytes = new byte[4];
|
||||
stream.EnsureRead(magicBytes, 0, 4);
|
||||
uint magic = BitConverter.ToUInt32(magicBytes, 0);
|
||||
var magic = BitConverter.ToUInt32(magicBytes, 0);
|
||||
|
||||
switch(magic)
|
||||
{
|
||||
@@ -101,8 +110,10 @@ public class Nintendo64 : IByteAddressableImage
|
||||
case 0x12408037:
|
||||
case 0x12418037:
|
||||
case 0x37804012:
|
||||
case 0x37804112: return true;
|
||||
default: return false;
|
||||
case 0x37804112:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,9 +130,9 @@ public class Nintendo64 : IByteAddressableImage
|
||||
return ErrorNumber.InvalidArgument;
|
||||
|
||||
stream.Position = 0;
|
||||
byte[] magicBytes = new byte[4];
|
||||
var magicBytes = new byte[4];
|
||||
stream.EnsureRead(magicBytes, 0, 4);
|
||||
uint magic = BitConverter.ToUInt32(magicBytes, 0);
|
||||
var magic = BitConverter.ToUInt32(magicBytes, 0);
|
||||
|
||||
switch(magic)
|
||||
{
|
||||
@@ -149,7 +160,8 @@ public class Nintendo64 : IByteAddressableImage
|
||||
_littleEndian = false;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.InvalidArgument;
|
||||
default:
|
||||
return ErrorNumber.InvalidArgument;
|
||||
}
|
||||
|
||||
_data = new byte[imageFilter.DataForkLength];
|
||||
@@ -169,9 +181,9 @@ public class Nintendo64 : IByteAddressableImage
|
||||
|
||||
if(_littleEndian)
|
||||
{
|
||||
byte[] tmp = new byte[_data.Length];
|
||||
var tmp = new byte[_data.Length];
|
||||
|
||||
for(int i = 0; i < _data.Length; i += 4)
|
||||
for(var i = 0; i < _data.Length; i += 4)
|
||||
{
|
||||
tmp[i] = _data[i + 3];
|
||||
tmp[i + 1] = _data[i + 2];
|
||||
@@ -184,9 +196,9 @@ public class Nintendo64 : IByteAddressableImage
|
||||
|
||||
if(_interleaved)
|
||||
{
|
||||
byte[] tmp = new byte[_data.Length];
|
||||
var tmp = new byte[_data.Length];
|
||||
|
||||
for(int i = 0; i < _data.Length; i += 2)
|
||||
for(var i = 0; i < _data.Length; i += 2)
|
||||
{
|
||||
tmp[i] = _data[i + 1];
|
||||
tmp[i + 1] = _data[i];
|
||||
@@ -208,17 +220,17 @@ public class Nintendo64 : IByteAddressableImage
|
||||
}
|
||||
|
||||
_imageInfo.MediaPartNumber = StringHandlers.SpacePaddedToString(header.CartridgeId, encoding);
|
||||
_imageInfo.MediaTitle = StringHandlers.SpacePaddedToString(header.Name, encoding);
|
||||
_imageInfo.MediaTitle = StringHandlers.SpacePaddedToString(header.Name, encoding);
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.AppendFormat(Localization.Name_0, _imageInfo.MediaTitle).AppendLine();
|
||||
sb.AppendFormat(Localization.Region_0, DecodeCountryCode(header.CountryCode)).AppendLine();
|
||||
sb.AppendFormat(Localization.Cartridge_ID_0, _imageInfo.MediaPartNumber).AppendLine();
|
||||
sb.AppendFormat(Localization.Name_0, _imageInfo.MediaTitle).AppendLine();
|
||||
sb.AppendFormat(Localization.Region_0, DecodeCountryCode(header.CountryCode)).AppendLine();
|
||||
sb.AppendFormat(Localization.Cartridge_ID_0, _imageInfo.MediaPartNumber).AppendLine();
|
||||
sb.AppendFormat(Localization.Cartridge_type_0, (char)header.CartridgeType).AppendLine();
|
||||
sb.AppendFormat(Localization.Version_0_1, (header.Version / 10) + 1, header.Version % 10).AppendLine();
|
||||
sb.AppendFormat(Localization.CRC1_0, header.Crc1).AppendLine();
|
||||
sb.AppendFormat(Localization.CRC2_0, header.Crc2).AppendLine();
|
||||
sb.AppendFormat(Localization.Version_0_1, header.Version / 10 + 1, header.Version % 10).AppendLine();
|
||||
sb.AppendFormat(Localization.CRC1_0, header.Crc1).AppendLine();
|
||||
sb.AppendFormat(Localization.CRC2_0, header.Crc2).AppendLine();
|
||||
|
||||
_imageInfo.Comments = sb.ToString();
|
||||
_opened = true;
|
||||
@@ -669,11 +681,12 @@ public class Nintendo64 : IByteAddressableImage
|
||||
return ErrorNumber.ReadOnly;
|
||||
}
|
||||
|
||||
bool foundRom = false;
|
||||
bool foundSaveRam = false;
|
||||
var foundRom = false;
|
||||
var foundSaveRam = false;
|
||||
|
||||
// Sanitize
|
||||
foreach(LinearMemoryDevice map in mappings.Devices)
|
||||
{
|
||||
switch(map.Type)
|
||||
{
|
||||
case LinearMemoryType.ROM when !foundRom:
|
||||
@@ -686,8 +699,10 @@ public class Nintendo64 : IByteAddressableImage
|
||||
foundSaveRam = true;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.InvalidArgument;
|
||||
default:
|
||||
return ErrorNumber.InvalidArgument;
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot save in this image format anyway
|
||||
return foundRom ? ErrorNumber.NoError : ErrorNumber.InvalidArgument;
|
||||
@@ -730,7 +745,7 @@ public class Nintendo64 : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber WriteBytes(byte[] buffer, int offset, int bytesToWrite, out int bytesWritten,
|
||||
bool advance = true) =>
|
||||
bool advance = true) =>
|
||||
WriteBytesAt(Position, buffer, offset, bytesToWrite, out bytesWritten, advance);
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -785,29 +800,29 @@ public class Nintendo64 : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsWriting { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> KnownExtensions => new[]
|
||||
{
|
||||
".n64", ".v64", ".z64"
|
||||
};
|
||||
public IEnumerable<string> KnownExtensions => new[] { ".n64", ".v64", ".z64" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => Array.Empty<MediaTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[]
|
||||
{
|
||||
MediaType.N64GamePak
|
||||
};
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[] { MediaType.N64GamePak };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions =>
|
||||
Array.Empty<(string name, Type type, string description, object @default)>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => Array.Empty<SectorTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Close()
|
||||
@@ -828,9 +843,9 @@ public class Nintendo64 : IByteAddressableImage
|
||||
|
||||
if(_interleaved)
|
||||
{
|
||||
byte[] tmp = new byte[_data.Length];
|
||||
var tmp = new byte[_data.Length];
|
||||
|
||||
for(int i = 0; i < _data.Length; i += 2)
|
||||
for(var i = 0; i < _data.Length; i += 2)
|
||||
{
|
||||
tmp[i] = _data[i + 1];
|
||||
tmp[i + 1] = _data[i];
|
||||
@@ -858,32 +873,37 @@ public class Nintendo64 : IByteAddressableImage
|
||||
/// <inheritdoc />
|
||||
public bool SetImageInfo(ImageInfo imageInfo) => true;
|
||||
|
||||
static string DecodeCountryCode(byte countryCode) => countryCode switch
|
||||
{
|
||||
0x37 => Localization.Beta,
|
||||
0x41 => Localization.Asia_NTSC,
|
||||
0x42 => Localization.Brazil,
|
||||
0x43 => Localization.China,
|
||||
0x44 => Localization.Germany,
|
||||
0x45 => Localization.North_America,
|
||||
0x46 => Localization.France,
|
||||
0x47 => Localization.Gateway_64_NTSC,
|
||||
0x48 => Localization.Netherlands,
|
||||
0x49 => Localization.Italy,
|
||||
0x4A => Localization.Japan,
|
||||
0x4B => Localization.Korea,
|
||||
0x4C => Localization.Gateway_64_PAL,
|
||||
0x4E => Localization.Canada,
|
||||
0x50 => Localization.Europe,
|
||||
0x53 => Localization.Spain,
|
||||
0x55 => Localization.Australia,
|
||||
0x57 => Localization.Scandinavia,
|
||||
0x58 => Localization.Europe,
|
||||
0x59 => Localization.Europe,
|
||||
_ => Localization.Unknown_country
|
||||
};
|
||||
#endregion
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1), SuppressMessage("ReSharper", "MemberCanBePrivate.Local")]
|
||||
static string DecodeCountryCode(byte countryCode) => countryCode switch
|
||||
{
|
||||
0x37 => Localization.Beta,
|
||||
0x41 => Localization.Asia_NTSC,
|
||||
0x42 => Localization.Brazil,
|
||||
0x43 => Localization.China,
|
||||
0x44 => Localization.Germany,
|
||||
0x45 => Localization.North_America,
|
||||
0x46 => Localization.France,
|
||||
0x47 => Localization.Gateway_64_NTSC,
|
||||
0x48 => Localization.Netherlands,
|
||||
0x49 => Localization.Italy,
|
||||
0x4A => Localization.Japan,
|
||||
0x4B => Localization.Korea,
|
||||
0x4C => Localization.Gateway_64_PAL,
|
||||
0x4E => Localization.Canada,
|
||||
0x50 => Localization.Europe,
|
||||
0x53 => Localization.Spain,
|
||||
0x55 => Localization.Australia,
|
||||
0x57 => Localization.Scandinavia,
|
||||
0x58 => Localization.Europe,
|
||||
0x59 => Localization.Europe,
|
||||
_ => Localization.Unknown_country
|
||||
};
|
||||
|
||||
#region Nested type: Header
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Local")]
|
||||
struct Header
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
||||
@@ -908,4 +928,6 @@ public class Nintendo64 : IByteAddressableImage
|
||||
public readonly byte CountryCode;
|
||||
public readonly byte Version;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -57,12 +57,17 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
bool _opened;
|
||||
bool _smd;
|
||||
|
||||
#region IByteAddressableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => Authors.NataliaPortillo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Metadata AaruMetadata => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<DumpHardware> DumpHardware => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Format => !_opened
|
||||
? "Mega Drive cartridge dump"
|
||||
@@ -71,10 +76,13 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
: _interleaved
|
||||
? "Multi Game Doctor 2"
|
||||
: "Magicom";
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("7B1CE2E7-3BC4-4283-BFA4-F292D646DF15");
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageInfo Info => _imageInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Localization.SegaMegaDrive_Name;
|
||||
|
||||
@@ -90,7 +98,7 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
if(stream.Length % 512 != 0)
|
||||
return false;
|
||||
|
||||
byte[] buffer = new byte[4];
|
||||
var buffer = new byte[4];
|
||||
|
||||
stream.Position = 256;
|
||||
stream.EnsureRead(buffer, 0, 4);
|
||||
@@ -106,7 +114,7 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
if(buffer[0] == 0x45 &&
|
||||
buffer[1] == 0x41)
|
||||
{
|
||||
stream.Position = (stream.Length / 2) + 256;
|
||||
stream.Position = stream.Length / 2 + 256;
|
||||
stream.EnsureRead(buffer, 0, 2);
|
||||
|
||||
// SG
|
||||
@@ -142,7 +150,7 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
if(stream.Length % 512 != 0)
|
||||
return ErrorNumber.InvalidArgument;
|
||||
|
||||
byte[] buffer = new byte[4];
|
||||
var buffer = new byte[4];
|
||||
|
||||
stream.Position = 256;
|
||||
stream.EnsureRead(buffer, 0, 4);
|
||||
@@ -154,7 +162,7 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
if(buffer[0] == 0x45 &&
|
||||
buffer[1] == 0x41)
|
||||
{
|
||||
stream.Position = (stream.Length / 2) + 256;
|
||||
stream.Position = stream.Length / 2 + 256;
|
||||
stream.EnsureRead(buffer, 0, 2);
|
||||
|
||||
// SG
|
||||
@@ -195,18 +203,18 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
// Interleaves every 16KiB
|
||||
if(_smd)
|
||||
{
|
||||
byte[] tmp = new byte[_data.Length];
|
||||
byte[] bankIn = new byte[16384];
|
||||
byte[] bankOut = new byte[16384];
|
||||
var tmp = new byte[_data.Length];
|
||||
var bankIn = new byte[16384];
|
||||
var bankOut = new byte[16384];
|
||||
|
||||
for(int b = 0; b < _data.Length / 16384; b++)
|
||||
for(var b = 0; b < _data.Length / 16384; b++)
|
||||
{
|
||||
Array.Copy(_data, b * 16384, bankIn, 0, 16384);
|
||||
|
||||
for(int i = 0; i < 8192; i++)
|
||||
for(var i = 0; i < 8192; i++)
|
||||
{
|
||||
bankOut[(i * 2) + 1] = bankIn[i];
|
||||
bankOut[i * 2] = bankIn[i + 8192];
|
||||
bankOut[i * 2 + 1] = bankIn[i];
|
||||
bankOut[i * 2] = bankIn[i + 8192];
|
||||
}
|
||||
|
||||
Array.Copy(bankOut, 0, tmp, b * 16384, 16384);
|
||||
@@ -216,13 +224,13 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
}
|
||||
else if(_interleaved)
|
||||
{
|
||||
byte[] tmp = new byte[_data.Length];
|
||||
int half = _data.Length / 2;
|
||||
var tmp = new byte[_data.Length];
|
||||
int half = _data.Length / 2;
|
||||
|
||||
for(int i = 0; i < half; i++)
|
||||
for(var i = 0; i < half; i++)
|
||||
{
|
||||
tmp[i * 2] = _data[i];
|
||||
tmp[(i * 2) + 1] = _data[i + half];
|
||||
tmp[i * 2] = _data[i];
|
||||
tmp[i * 2 + 1] = _data[i + half];
|
||||
}
|
||||
|
||||
_data = tmp;
|
||||
@@ -310,7 +318,8 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
|
||||
sb.AppendFormat(Localization.Extra_RAM_starts_at_0_and_ends_at_1_2_bytes, header.ExtraRamStart,
|
||||
header.ExtraRamEnd,
|
||||
(header.ExtraRamType & 0x10) == 0x10 ? (header.ExtraRamEnd - header.ExtraRamStart + 2) / 2
|
||||
(header.ExtraRamType & 0x10) == 0x10
|
||||
? (header.ExtraRamEnd - header.ExtraRamStart + 2) / 2
|
||||
: header.ExtraRamEnd - header.ExtraRamStart + 1).AppendLine();
|
||||
}
|
||||
else
|
||||
@@ -327,15 +336,15 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
_imageInfo.ImageSize = (ulong)stream.Length;
|
||||
_imageInfo.LastModificationTime = imageFilter.LastWriteTime;
|
||||
_imageInfo.CreationTime = imageFilter.CreationTime;
|
||||
_imageInfo.MediaPartNumber = StringHandlers.SpacePaddedToString(header.SerialNumber, encoding);
|
||||
_imageInfo.MediaPartNumber = StringHandlers.SpacePaddedToString(header.SerialNumber, encoding);
|
||||
_imageInfo.MediaTitle = StringHandlers.SpacePaddedToString(header.DomesticTitle, encoding);
|
||||
|
||||
_imageInfo.MediaType = StringHandlers.SpacePaddedToString(header.SystemType, encoding) switch
|
||||
{
|
||||
"SEGA 32X" => MediaType._32XCartridge,
|
||||
"SEGA PICO" => MediaType.SegaPicoCartridge,
|
||||
_ => MediaType.MegaDriveCartridge
|
||||
};
|
||||
{
|
||||
"SEGA 32X" => MediaType._32XCartridge,
|
||||
"SEGA PICO" => MediaType.SegaPicoCartridge,
|
||||
_ => MediaType.MegaDriveCartridge
|
||||
};
|
||||
|
||||
_imageInfo.Sectors = (ulong)_data.Length;
|
||||
_imageInfo.MetadataMediaType = MetadataMediaType.LinearMedia;
|
||||
@@ -348,29 +357,32 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsWriting { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> KnownExtensions => new[]
|
||||
{
|
||||
".smd", ".md", ".32x"
|
||||
};
|
||||
public IEnumerable<string> KnownExtensions => new[] { ".smd", ".md", ".32x" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => Array.Empty<MediaTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[]
|
||||
{
|
||||
MediaType._32XCartridge, MediaType.MegaDriveCartridge, MediaType.SegaPicoCartridge
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions =>
|
||||
Array.Empty<(string name, Type type, string description, object @default)>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => Array.Empty<SectorTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Close()
|
||||
@@ -391,13 +403,13 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
|
||||
if(_interleaved)
|
||||
{
|
||||
byte[] tmp = new byte[_data.Length];
|
||||
int half = _data.Length / 2;
|
||||
var tmp = new byte[_data.Length];
|
||||
int half = _data.Length / 2;
|
||||
|
||||
for(int i = 0; i < half; i++)
|
||||
for(var i = 0; i < half; i++)
|
||||
{
|
||||
tmp[i] = _data[i * 2];
|
||||
tmp[i + half] = _data[(i * 2) + 1];
|
||||
tmp[i + half] = _data[i * 2 + 1];
|
||||
}
|
||||
|
||||
_data = tmp;
|
||||
@@ -419,18 +431,18 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
|
||||
_dataStream.Write(smdHeader, 0, smdHeader.Length);
|
||||
|
||||
byte[] tmp = new byte[_data.Length];
|
||||
byte[] bankIn = new byte[16384];
|
||||
byte[] bankOut = new byte[16384];
|
||||
var tmp = new byte[_data.Length];
|
||||
var bankIn = new byte[16384];
|
||||
var bankOut = new byte[16384];
|
||||
|
||||
for(int b = 0; b < _data.Length / 16384; b++)
|
||||
for(var b = 0; b < _data.Length / 16384; b++)
|
||||
{
|
||||
Array.Copy(_data, b * 16384, bankIn, 0, 16384);
|
||||
|
||||
for(int i = 0; i < 8192; i++)
|
||||
for(var i = 0; i < 8192; i++)
|
||||
{
|
||||
bankOut[i] = bankIn[(i * 2) + 1];
|
||||
bankOut[i + 8192] = bankIn[i * 2];
|
||||
bankOut[i] = bankIn[i * 2 + 1];
|
||||
bankOut[i + 8192] = bankIn[i * 2];
|
||||
}
|
||||
|
||||
Array.Copy(bankOut, 0, tmp, b * 16384, 16384);
|
||||
@@ -723,11 +735,12 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
return ErrorNumber.ReadOnly;
|
||||
}
|
||||
|
||||
bool foundRom = false;
|
||||
bool foundSaveRam = false;
|
||||
var foundRom = false;
|
||||
var foundSaveRam = false;
|
||||
|
||||
// Sanitize
|
||||
foreach(LinearMemoryDevice map in mappings.Devices)
|
||||
{
|
||||
switch(map.Type)
|
||||
{
|
||||
case LinearMemoryType.ROM when !foundRom:
|
||||
@@ -738,8 +751,10 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
foundSaveRam = true;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.InvalidArgument;
|
||||
default:
|
||||
return ErrorNumber.InvalidArgument;
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot save in this image format anyway
|
||||
return foundRom ? ErrorNumber.NoError : ErrorNumber.InvalidArgument;
|
||||
@@ -782,7 +797,7 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber WriteBytes(byte[] buffer, int offset, int bytesToWrite, out int bytesWritten,
|
||||
bool advance = true) =>
|
||||
bool advance = true) =>
|
||||
WriteBytesAt(Position, buffer, offset, bytesToWrite, out bytesWritten, advance);
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -835,8 +850,13 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1), SuppressMessage("ReSharper", "MemberCanBePrivate.Local"),
|
||||
SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")]
|
||||
#endregion
|
||||
|
||||
#region Nested type: SegaHeader
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Local")]
|
||||
[SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")]
|
||||
struct SegaHeader
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)]
|
||||
@@ -873,8 +893,13 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
public byte[] Padding3;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1), SuppressMessage("ReSharper", "MemberCanBePrivate.Local"),
|
||||
SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")]
|
||||
#endregion
|
||||
|
||||
#region Nested type: SuperMagicDriveHeader
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Local")]
|
||||
[SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")]
|
||||
struct SuperMagicDriveHeader
|
||||
{
|
||||
/// <summary>16 KiB pages</summary>
|
||||
@@ -894,4 +919,6 @@ public class SegaMegaDrive : IByteAddressableImage
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 501)]
|
||||
public byte[] Empty;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -21,8 +21,12 @@ public class SuperNintendo : IByteAddressableImage
|
||||
Header _header;
|
||||
ImageInfo _imageInfo;
|
||||
bool _opened;
|
||||
|
||||
#region IByteAddressableImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageInfo Info => _imageInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Localization.SuperNintendo_Name;
|
||||
|
||||
@@ -56,7 +60,7 @@ public class SuperNintendo : IByteAddressableImage
|
||||
return false;
|
||||
|
||||
Header header;
|
||||
byte[] headerBytes = new byte[48];
|
||||
var headerBytes = new byte[48];
|
||||
|
||||
switch(stream.Length)
|
||||
{
|
||||
@@ -110,8 +114,8 @@ public class SuperNintendo : IByteAddressableImage
|
||||
if(stream.Length % 32768 != 0)
|
||||
return ErrorNumber.InvalidArgument;
|
||||
|
||||
bool found = false;
|
||||
byte[] headerBytes = new byte[48];
|
||||
var found = false;
|
||||
var headerBytes = new byte[48];
|
||||
|
||||
switch(stream.Length)
|
||||
{
|
||||
@@ -190,9 +194,9 @@ public class SuperNintendo : IByteAddressableImage
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.AppendFormat(Localization.Name_0, _imageInfo.MediaTitle).AppendLine();
|
||||
sb.AppendFormat(Localization.Name_0, _imageInfo.MediaTitle).AppendLine();
|
||||
sb.AppendFormat(Localization.Manufacturer_0, _imageInfo.MediaManufacturer).AppendLine();
|
||||
sb.AppendFormat(Localization.Region_0, DecodeRegion(_header.Region)).AppendLine();
|
||||
sb.AppendFormat(Localization.Region_0, DecodeRegion(_header.Region)).AppendLine();
|
||||
|
||||
if(_header.OldMakerCode == 0x33)
|
||||
sb.AppendFormat(Localization.Game_code_0, _header.GameCode).AppendLine();
|
||||
@@ -202,7 +206,7 @@ public class SuperNintendo : IByteAddressableImage
|
||||
if(_header.OldMakerCode == 0x33)
|
||||
sb.AppendFormat(Localization.Special_revision_0, _header.SpecialVersion).AppendLine();
|
||||
|
||||
sb.AppendFormat(Localization.Header_checksum_0_X4, _header.Checksum).AppendLine();
|
||||
sb.AppendFormat(Localization.Header_checksum_0_X4, _header.Checksum).AppendLine();
|
||||
sb.AppendFormat(Localization.Header_checksum_complement_0, _header.ChecksumComplement).AppendLine();
|
||||
|
||||
sb.AppendFormat(Localization.ROM_size_0_bytes, (1 << _header.RomSize) * 1024).AppendLine();
|
||||
@@ -216,8 +220,10 @@ public class SuperNintendo : IByteAddressableImage
|
||||
sb.AppendFormat(Localization.Flash_size_0_bytes, (1 << _header.ExpansionFlashSize) * 1024).AppendLine();
|
||||
|
||||
if(_header.ExpansionRamSize > 0)
|
||||
{
|
||||
sb.AppendFormat(Localization.Expansion_RAM_size_0_bytes, (1 << _header.ExpansionRamSize) * 1024).
|
||||
AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
sb.AppendFormat(Localization.Cartridge_type_0, DecodeCartType(_header.Mode)).AppendLine();
|
||||
@@ -234,39 +240,44 @@ public class SuperNintendo : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("DF861EB0-8B9B-4E3F-BF39-9F2E75668F80");
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => Authors.NataliaPortillo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Format => "Super Nintendo Cartridge Dump";
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<DumpHardware> DumpHardware => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Metadata AaruMetadata => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsWriting { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> KnownExtensions => new[]
|
||||
{
|
||||
".sfc"
|
||||
};
|
||||
public IEnumerable<string> KnownExtensions => new[] { ".sfc" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => Array.Empty<MediaTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[]
|
||||
{
|
||||
MediaType.SNESGamePak, MediaType.SNESGamePakUS
|
||||
};
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[] { MediaType.SNESGamePak, MediaType.SNESGamePakUS };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions =>
|
||||
Array.Empty<(string name, Type type, string description, object @default)>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => Array.Empty<SectorTagType>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
uint sectorSize) => Create(path, mediaType, options, (long)sectors) == ErrorNumber.NoError;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Close()
|
||||
@@ -369,7 +380,7 @@ public class SuperNintendo : IByteAddressableImage
|
||||
bool hasFlash = _header is { OldMakerCode: 0x33, ExpansionFlashSize: > 0 };
|
||||
bool hasBattery = chipset is 2 or 5 or 6 or 9 or 0xA;
|
||||
|
||||
int devices = 1;
|
||||
var devices = 1;
|
||||
|
||||
if(hasRam)
|
||||
devices++;
|
||||
@@ -395,8 +406,8 @@ public class SuperNintendo : IByteAddressableImage
|
||||
}
|
||||
};
|
||||
|
||||
int pos = 1;
|
||||
ulong addr = (ulong)_data.Length;
|
||||
var pos = 1;
|
||||
var addr = (ulong)_data.Length;
|
||||
|
||||
if(hasRam)
|
||||
{
|
||||
@@ -431,6 +442,7 @@ public class SuperNintendo : IByteAddressableImage
|
||||
}
|
||||
|
||||
if(hasFlash)
|
||||
{
|
||||
mappings.Devices[pos] = new LinearMemoryDevice
|
||||
{
|
||||
Type = LinearMemoryType.NOR,
|
||||
@@ -440,6 +452,7 @@ public class SuperNintendo : IByteAddressableImage
|
||||
Length = (ulong)(1 << _header.ExpansionRamSize) * 1024
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
@@ -538,13 +551,14 @@ public class SuperNintendo : IByteAddressableImage
|
||||
return ErrorNumber.ReadOnly;
|
||||
}
|
||||
|
||||
bool foundRom = false;
|
||||
bool foundRam = false;
|
||||
bool foundExtraRam = false;
|
||||
bool foundFlash = false;
|
||||
var foundRom = false;
|
||||
var foundRam = false;
|
||||
var foundExtraRam = false;
|
||||
var foundFlash = false;
|
||||
|
||||
// Sanitize
|
||||
foreach(LinearMemoryDevice map in mappings.Devices)
|
||||
{
|
||||
switch(map.Type)
|
||||
{
|
||||
case LinearMemoryType.ROM when !foundRom:
|
||||
@@ -572,8 +586,10 @@ public class SuperNintendo : IByteAddressableImage
|
||||
foundFlash = true;
|
||||
|
||||
break;
|
||||
default: return ErrorNumber.InvalidArgument;
|
||||
default:
|
||||
return ErrorNumber.InvalidArgument;
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot save in this image format anyway
|
||||
return foundRom ? ErrorNumber.NoError : ErrorNumber.InvalidArgument;
|
||||
@@ -616,7 +632,7 @@ public class SuperNintendo : IByteAddressableImage
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber WriteBytes(byte[] buffer, int offset, int bytesToWrite, out int bytesWritten,
|
||||
bool advance = true) =>
|
||||
bool advance = true) =>
|
||||
WriteBytesAt(Position, buffer, offset, bytesToWrite, out bytesWritten, advance);
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -669,47 +685,59 @@ public class SuperNintendo : IByteAddressableImage
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
static string DecodeCoprocessor(byte chipset, byte subtype)
|
||||
{
|
||||
if((chipset & 0xF) < 3)
|
||||
return Localization.None_coprocessor;
|
||||
|
||||
return ((chipset & 0xF0) >> 4) switch
|
||||
{
|
||||
0 => "DSP",
|
||||
1 => "GSU",
|
||||
2 => "OBC1",
|
||||
3 => "SA-1",
|
||||
4 => "S-DD1",
|
||||
5 => "S-RTC",
|
||||
0xE => Localization.Other_coprocessor,
|
||||
0xF => subtype switch
|
||||
{
|
||||
0 => "SPC7110",
|
||||
1 => "ST010/ST011",
|
||||
2 => "ST018",
|
||||
0x10 => "CX4",
|
||||
_ => Localization.Unknown_coprocessor
|
||||
},
|
||||
_ => Localization.Unknown_coprocessor
|
||||
};
|
||||
{
|
||||
0 => "DSP",
|
||||
1 => "GSU",
|
||||
2 => "OBC1",
|
||||
3 => "SA-1",
|
||||
4 => "S-DD1",
|
||||
5 => "S-RTC",
|
||||
0xE => Localization.Other_coprocessor,
|
||||
0xF => subtype switch
|
||||
{
|
||||
0 => "SPC7110",
|
||||
1 => "ST010/ST011",
|
||||
2 => "ST018",
|
||||
0x10 => "CX4",
|
||||
_ => Localization.Unknown_coprocessor
|
||||
},
|
||||
_ => Localization.Unknown_coprocessor
|
||||
};
|
||||
}
|
||||
|
||||
static string DecodeChipset(byte chipset)
|
||||
{
|
||||
switch(chipset & 0xF)
|
||||
{
|
||||
case 0: return Localization.ROM;
|
||||
case 1: return Localization.ROM_and_RAM;
|
||||
case 2 when (chipset & 0xF0) == 0: return Localization.ROM_RAM_and_battery;
|
||||
case 3: return Localization.ROM_and_coprocessor;
|
||||
case 4: return Localization.ROM_RAM_and_coprocessor;
|
||||
case 0:
|
||||
return Localization.ROM;
|
||||
case 1:
|
||||
return Localization.ROM_and_RAM;
|
||||
case 2 when (chipset & 0xF0) == 0:
|
||||
return Localization.ROM_RAM_and_battery;
|
||||
case 3:
|
||||
return Localization.ROM_and_coprocessor;
|
||||
case 4:
|
||||
return Localization.ROM_RAM_and_coprocessor;
|
||||
case 2:
|
||||
case 5: return Localization.ROM_RAM_battery_and_coprocessor;
|
||||
case 6: return Localization.ROM_battery_and_coprocessor;
|
||||
case 9: return Localization.ROM_RAM_battery_coprocessor_and_RTC;
|
||||
case 0xA: return Localization.ROM_RAM_battery_and_coprocessor;
|
||||
default: return Localization.Unknown_chipset;
|
||||
case 5:
|
||||
return Localization.ROM_RAM_battery_and_coprocessor;
|
||||
case 6:
|
||||
return Localization.ROM_battery_and_coprocessor;
|
||||
case 9:
|
||||
return Localization.ROM_RAM_battery_coprocessor_and_RTC;
|
||||
case 0xA:
|
||||
return Localization.ROM_RAM_battery_and_coprocessor;
|
||||
default:
|
||||
return Localization.Unknown_chipset;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -719,11 +747,14 @@ public class SuperNintendo : IByteAddressableImage
|
||||
{
|
||||
case 0:
|
||||
case 2:
|
||||
case 3: return 32768;
|
||||
case 3:
|
||||
return 32768;
|
||||
case 1:
|
||||
case 5:
|
||||
case 0xA: return 65536;
|
||||
default: return 0;
|
||||
case 0xA:
|
||||
return 65536;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -735,51 +766,58 @@ public class SuperNintendo : IByteAddressableImage
|
||||
{
|
||||
case 0:
|
||||
case 2:
|
||||
case 3: return "LoROM";
|
||||
case 3:
|
||||
return "LoROM";
|
||||
case 1:
|
||||
case 0xA: return "HiROM";
|
||||
case 5: return "ExHiROM";
|
||||
default: return Localization.Unknown_licensee;
|
||||
case 0xA:
|
||||
return "HiROM";
|
||||
case 5:
|
||||
return "ExHiROM";
|
||||
default:
|
||||
return Localization.Unknown_licensee;
|
||||
}
|
||||
}
|
||||
|
||||
static string DecodeRegion(byte headerRegion) => headerRegion switch
|
||||
{
|
||||
0 => Localization.Japan,
|
||||
1 => Localization.USA_and_Canada,
|
||||
2 => Localization.Europe_Oceania_Asia,
|
||||
3 => Localization.Sweden_Scandinavia,
|
||||
4 => Localization.Finland,
|
||||
5 => Localization.Denmark,
|
||||
6 => Localization.France,
|
||||
7 => Localization.Netherlands,
|
||||
8 => Localization.Spain,
|
||||
9 => Localization.Germany_Austria_Switzerland,
|
||||
10 => Localization.Italy,
|
||||
11 => Localization.China_Hong_Kong,
|
||||
12 => Localization.Indonesia,
|
||||
13 => Localization.South_Korea,
|
||||
15 => Localization.Canada,
|
||||
16 => Localization.Brazil,
|
||||
17 => Localization.Australia,
|
||||
_ => Localization.Unknown_licensee
|
||||
};
|
||||
{
|
||||
0 => Localization.Japan,
|
||||
1 => Localization.USA_and_Canada,
|
||||
2 => Localization.Europe_Oceania_Asia,
|
||||
3 => Localization.Sweden_Scandinavia,
|
||||
4 => Localization.Finland,
|
||||
5 => Localization.Denmark,
|
||||
6 => Localization.France,
|
||||
7 => Localization.Netherlands,
|
||||
8 => Localization.Spain,
|
||||
9 => Localization.Germany_Austria_Switzerland,
|
||||
10 => Localization.Italy,
|
||||
11 => Localization.China_Hong_Kong,
|
||||
12 => Localization.Indonesia,
|
||||
13 => Localization.South_Korea,
|
||||
15 => Localization.Canada,
|
||||
16 => Localization.Brazil,
|
||||
17 => Localization.Australia,
|
||||
_ => Localization.Unknown_licensee
|
||||
};
|
||||
|
||||
static string DecodeManufacturer(byte oldMakerCode, string makerCode)
|
||||
{
|
||||
// TODO: Add full table
|
||||
if(oldMakerCode != 0x33)
|
||||
makerCode = $"{((oldMakerCode >> 4) * 36) + (oldMakerCode & 0x0f)}";
|
||||
makerCode = $"{(oldMakerCode >> 4) * 36 + (oldMakerCode & 0x0f)}";
|
||||
|
||||
return makerCode switch
|
||||
{
|
||||
"01" => "Nintendo",
|
||||
_ => Localization.Unknown_manufacturer
|
||||
};
|
||||
{
|
||||
"01" => "Nintendo",
|
||||
_ => Localization.Unknown_manufacturer
|
||||
};
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1), SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local"),
|
||||
SuppressMessage("ReSharper", "MemberCanBePrivate.Local")]
|
||||
#region Nested type: Header
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Local")]
|
||||
struct Header
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2)]
|
||||
@@ -804,4 +842,6 @@ public class SuperNintendo : IByteAddressableImage
|
||||
public ushort ChecksumComplement;
|
||||
public ushort Checksum;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
Reference in New Issue
Block a user