[Aaru.Images] Reformat and cleanup.

This commit is contained in:
2023-10-03 23:34:59 +01:00
parent 6ffde343ce
commit 2cfad87955
432 changed files with 12011 additions and 8261 deletions

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}