Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ' ***********************************************************************
- ' Author : Elektro.
- ' Based on this 3rd party project:
- ' https://github.com/Zeokat/SNES-ROM-Header-Dumper-CSharp/blob/master/snes_dumper.cs
- ' Modified : 11-June-2015
- ' ***********************************************************************
- ' <copyright file="SnesRom.vb" company="Elektro Studios">
- ' Copyright (c) Elektro Studios. All rights reserved.
- ' </copyright>
- ' ***********************************************************************
- #Region " Usage Examples "
- #Region " Read SNES ROM "
- 'Dim romDump As New SnesRom("C:\ROM.smc")
- '' Or...
- '' Dim romDump As New SnesRom(File.ReadAllBytes("C:\ROM.smc"))
- 'Dim sb As New StringBuilder
- 'With sb
- ' .AppendLine(String.Format("Name..................: {0}", romDump.Name))
- ' .AppendLine(String.Format("Bank Type.............: {0}", romDump.BankType.ToString))
- ' .AppendLine(String.Format("Cartridge Type........: {0}", romDump.CartridgeType.ToString.ToUpper.Replace("_", "/")))
- ' .AppendLine(String.Format("Checksum..............: {0}", String.Format("0x{0}", Convert.ToString(CInt(romDump.Checksum), toBase:=16).ToUpper)))
- ' .AppendLine(String.Format("Checksum Complement...: {0}", String.Format("0x{0}", Convert.ToString(CInt(romDump.ChecksumComplement), toBase:=16).ToUpper)))
- ' .AppendLine(String.Format("Country Code..........: {0}", romDump.Country.Code.ToString))
- ' .AppendLine(String.Format("Country Name..........: {0}", romDump.Country.Name))
- ' .AppendLine(String.Format("Country Region........: {0}", romDump.Country.Region.ToString.ToUpper))
- ' .AppendLine(String.Format("Header Type (SMC).....: {0}", romDump.HeaderType.ToString))
- ' .AppendLine(String.Format("Layout................: {0}", romDump.Layout.ToString))
- ' .AppendLine(String.Format("License Code/Name.....: {0}", romDump.LicenseCode.ToString))
- ' .AppendLine(String.Format("ROM Size..............: {0} MBits", romDump.RomSize.ToString.Substring(1, romDump.RomSize.ToString.LastIndexOf("M") - 2)).Replace("_or_", "/"))
- ' .AppendLine(String.Format("RAM Size..............: {0} KBits", romDump.RamSize.ToString.Substring(1, romDump.RamSize.ToString.LastIndexOf("K") - 2)))
- ' .AppendLine(String.Format("Version Number........: 1.{0}", romDump.Version.ToString))
- 'End With
- 'Clipboard.SetText(sb.ToString) : MessageBox.Show(sb.ToString)
- #End Region
- #Region " Modify SNES ROM "
- 'Dim romDump As New SnesRom("C:\ROM.smc")
- '' Or...
- '' Dim romDump As New SnesRom(File.ReadAllBytes("C:\ROM.smc"))
- 'With romDump
- ' .Name = "Elektrocitos"
- ' .Version = 1
- ' .Country = New SnesRom.CountryData(countryCode:=0) ' Japan.
- ' .LicenseCode = SnesRom.LicenseCodeEnum.Taito
- ' .RomSize = SnesRom.ROMSizeEnum._4_Mbits
- ' .RamSize = SnesRom.SRAMSizeEnum._256_Kbits
- ' .Save("C:\Elektron.smc", replace:=True)
- 'End With
- #End Region
- #End Region
- #Region " Option Statements "
- Option Strict On
- Option Explicit On
- Option Infer Off
- #End Region
- #Region " Imports "
- Imports System.IO
- Imports System.Text
- #End Region
- ''' <summary>
- ''' Read or modify a SNES ROM header.
- ''' </summary>
- Public NotInheritable Class SnesRom
- #Region " Properties "
- ''' <summary>
- ''' Gets the raw byte-data of the ROM file.
- ''' </summary>
- ''' <value>The raw byte-data of the ROM file.</value>
- Public ReadOnly Property RawData As Byte()
- Get
- Return Me.rawDataB
- End Get
- End Property
- ''' <summary>
- ''' (backing field) The raw byte-data of the ROM file.
- ''' </summary>
- Private ReadOnly rawDataB As Byte()
- ''' <summary>
- ''' Gets The ROM header type.
- ''' </summary>
- ''' <remarks>http://romhack.wikia.com/wiki/SMC_header</remarks>
- ''' <value>The ROM header type.</value>
- Public ReadOnly Property HeaderType As HeaderTypeEnum
- Get
- Return Me.headerTypeB
- End Get
- End Property
- ''' <summary>
- ''' (backing field) The ROM header type.
- ''' </summary>
- Private headerTypeB As HeaderTypeEnum
- ''' <summary>
- ''' Gets the SNES header address location.
- ''' </summary>
- ''' <remarks>http://romhack.wikia.com/wiki/SNES_header</remarks>
- ''' <value>The SNES header address location.</value>
- Private ReadOnly Property HeaderLocation As Integer
- Get
- Return Me.headerLocationB
- End Get
- End Property
- ''' <summary>
- ''' (backing field) The SNES header address location.
- ''' </summary>
- Private headerLocationB As Integer = 33216
- ''' <summary>
- ''' Gets or sets the name of the ROM, typically in ASCII.
- ''' The name buffer consists in 21 characters.
- ''' </summary>
- ''' <remarks>http://romhack.wikia.com/wiki/SNES_header</remarks>
- ''' <value>The name of the ROM.</value>
- Public Property Name As String
- Get
- Return Me.nameB
- End Get
- Set(ByVal value As String)
- Me.SetName(value)
- Me.nameB = value
- End Set
- End Property
- ''' <summary>
- ''' (backing field) The name of the ROM.
- ''' </summary>
- Private nameB As String
- ''' <summary>
- ''' Gets the ROM layout.
- ''' The SNES ROM layout describes how the ROM banks appear in a ROM image and in the SNES address space.
- ''' </summary>
- ''' <remarks>http://romhack.wikia.com/wiki/SNES_ROM_layout</remarks>
- ''' <value>The ROM layout.</value>
- Public ReadOnly Property Layout As Byte
- Get
- Return Me.layoutB
- End Get
- End Property
- ''' <summary>
- ''' (backing field) The ROM layout.
- ''' </summary>
- Private layoutB As Byte
- ''' <summary>
- ''' Gets the bank type.
- ''' An image contains only LoROM banks or only HiROM banks, not both.
- ''' </summary>
- ''' <remarks>http://romhack.wikia.com/wiki/SNES_ROM_layout</remarks>
- ''' <value>The bank type.</value>
- Public ReadOnly Property BankType As BankTypeEnum
- Get
- Return Me.bankTypeB
- End Get
- End Property
- ''' <summary>
- ''' (backing field) The bank type.
- ''' </summary>
- Private bankTypeB As BankTypeEnum
- ''' <summary>
- ''' Gets the cartrifge type, it can be a ROM only, or a ROM with save-RAM.
- ''' </summary>
- ''' <remarks>http://romhack.wikia.com/wiki/SNES_header</remarks>
- ''' <value>The cartridge type.</value>
- Public ReadOnly Property CartridgeType As CartridgeTypeEnum
- Get
- Return Me.cartridgeTypeB
- End Get
- End Property
- ''' <summary>
- ''' (backing field) The cartrifge type.
- ''' </summary>
- Private cartridgeTypeB As CartridgeTypeEnum
- ''' <summary>
- ''' Gets or sets the ROM size, in megabits.
- ''' </summary>
- ''' <remarks>http://romhack.wikia.com/wiki/SNES_header</remarks>
- ''' <value>The ROM size, in megabits.</value>
- Public Property RomSize As ROMSizeEnum
- Get
- Return DirectCast(Me.romSizeB, ROMSizeEnum)
- End Get
- Set(ByVal value As ROMSizeEnum)
- Me.SetByte(Me.startAddressRomSize, value)
- Me.romSizeB = value
- End Set
- End Property
- ''' <summary>
- ''' (backing field) The ROM size-byte (from 8 to 13).
- ''' </summary>
- Private romSizeB As Byte
- ''' <summary>
- ''' Gets or sets the RAM size, in kilobits.
- ''' If value is 0, the ROM has no RAM.
- ''' </summary>
- ''' <remarks>http://romhack.wikia.com/wiki/SNES_header</remarks>
- ''' <value>The RAM size, in kilobits.</value>
- Public Property RamSize As SRAMSizeEnum
- Get
- ' Formula:
- ' 1 << (3 + Me.ramSizeB) = "X" KBits
- Return DirectCast(Me.ramSizeB, SRAMSizeEnum)
- End Get
- Set(ByVal value As SRAMSizeEnum)
- Me.SetByte(Me.startAddressRamSize, value)
- Me.ramSizeB = value
- End Set
- End Property
- ''' <summary>
- ''' (backing field) The RAM size-byte (from 0 to 5).
- ''' </summary>
- Private ramSizeB As Byte
- ''' <summary>
- ''' Gets or sets the country data.
- ''' </summary>
- ''' <remarks>http://romhack.wikia.com/wiki/SNES_header</remarks>
- ''' <value>The country data.</value>
- Public Property Country As CountryData
- Get
- Return New CountryData(Me.CountryCode)
- End Get
- Set(ByVal value As CountryData)
- Me.SetByte(Me.startAddressCountryCode, value.Code)
- Me.CountryCode = value.Code
- End Set
- End Property
- ''' <summary>
- ''' The country code.
- ''' </summary>
- Private Property CountryCode As Byte
- ''' <summary>
- ''' Gets or sets the license code.
- ''' </summary>
- ''' <remarks>http://romhack.wikia.com/wiki/SNES_header</remarks>
- ''' <value>The license code.</value>
- Public Property LicenseCode As LicenseCodeEnum
- Get
- Return DirectCast(Me.licenseCodeB, LicenseCodeEnum)
- End Get
- Set(ByVal value As LicenseCodeEnum)
- Me.SetByte(Me.startAddressLicenseCode, value)
- Me.licenseCodeB = value
- End Set
- End Property
- ''' <summary>
- ''' (backing field) The license code.
- ''' </summary>
- Private licenseCodeB As Byte
- ''' <summary>
- ''' Gets or sets the version number.
- ''' </summary>
- ''' <remarks>http://romhack.wikia.com/wiki/SNES_header</remarks>
- ''' <value>The version number.</value>
- Public Property Version As Byte
- Get
- Return Me.versionB
- End Get
- Set(ByVal value As Byte)
- Me.SetByte(Me.startAddressVersion, Version)
- Me.versionB = value
- End Set
- End Property
- ''' <summary>
- ''' (backing field) The version number.
- ''' </summary>
- Private versionB As Byte
- ''' <summary>
- ''' Gets the checksum complement.
- ''' </summary>
- ''' <remarks>http://romhack.wikia.com/wiki/SNES_header</remarks>
- ''' <value>The checksum complement.</value>
- Public ReadOnly Property ChecksumComplement As UShort
- Get
- Return Me.checksumComplementB
- End Get
- End Property
- ''' <summary>
- ''' (backing field) The checksum complement.
- ''' </summary>
- Private checksumComplementB As UShort
- ''' <summary>
- ''' Gets the checksum.
- ''' </summary>
- ''' <remarks>http://romhack.wikia.com/wiki/SNES_header</remarks>
- ''' <value>The checksum.</value>
- Public ReadOnly Property Checksum As UShort
- Get
- Return Me.checksumB
- End Get
- End Property
- ''' <summary>
- ''' (backing field) The checksum.
- ''' </summary>
- Private checksumB As UShort
- #End Region
- #Region " Header Addresses "
- ' ********************************************************************************************************************
- ' NOTE:
- ' The reason for the variables that are commented-out is just because are unused, but could be helpful in the future.
- ' ********************************************************************************************************************
- ' ''' <summary>
- ' ''' The start address of a Lo-ROM header.
- ' ''' </summary>
- 'Private ReadOnly loRomHeaderAddress As UShort = 32704
- ' ''' <summary>
- ' ''' The start address of a Hi-ROM header.
- ' ''' </summary>
- 'Private ReadOnly hiRomHeaderAddress As UShort = 65472
- ''' <summary>
- ''' The start address of the ROM name.
- ''' </summary>
- Private ReadOnly startAddressName As Integer = 0
- ''' <summary>
- ''' The end address of the ROM name.
- ''' </summary>
- Private ReadOnly endAddressName As Integer = 20
- ''' <summary>
- ''' The start address of the ROM layout.
- ''' </summary>
- Private ReadOnly startAddressLayout As Integer = 21
- ' ''' <summary>
- ' ''' The end address of the ROM layout.
- ' ''' </summary>
- 'Private ReadOnly endAddressLayout As Integer = 21
- ''' <summary>
- ''' The start address of the ROM cartridge type.
- ''' </summary>
- Private ReadOnly startAddressCartridgeType As Integer = 22
- ' ''' <summary>
- ' ''' The end address of the ROM cartridge type.
- ' ''' </summary>
- 'Private ReadOnly endAddressCartridgeType As Integer = 22
- ''' <summary>
- ''' The start address of the ROM size (rom).
- ''' </summary>
- Private ReadOnly startAddressRomSize As Integer = 23
- ' ''' <summary>
- ' ''' The end address of the ROM size (rom).
- ' ''' </summary>
- 'Private ReadOnly endAddressRomSize As Integer = 23
- ''' <summary>
- ''' The start address of the ROM size (ram).
- ''' </summary>
- Private ReadOnly startAddressRamSize As Integer = 24
- ' ''' <summary>
- ' ''' The end address of the ROM size (ram).
- ' ''' </summary>
- 'Private ReadOnly endAddressRamSize As Integer = 24
- ''' <summary>
- ''' The start address of the ROM country code.
- ''' </summary>
- Private ReadOnly startAddressCountryCode As Integer = 25
- ' ''' <summary>
- ' ''' The end address of the ROM country code.
- ' ''' </summary>
- 'Private ReadOnly endAddressCountryCode As Integer = 25
- ''' <summary>
- ''' The start address of the ROM license code.
- ''' </summary>
- Private ReadOnly startAddressLicenseCode As Integer = 26
- ' ''' <summary>
- ' ''' The end address of the ROM license code.
- ' ''' </summary>
- 'Private ReadOnly endAddressLicenseCode As Integer = 26
- ''' <summary>
- ''' The start address of the ROM Version Number.
- ''' </summary>
- Private ReadOnly startAddressVersion As Integer = 27
- ' ''' <summary>
- ' ''' The end address of the ROM Version Number.
- ' ''' </summary>
- 'Private ReadOnly endAddresVersion As Integer = 27
- ''' <summary>
- ''' The start address of the ROM checksum complement.
- ''' </summary>
- Private ReadOnly startAddressChecksumComplement As Integer = 28
- ''' <summary>
- ''' The end address of the ROM checksum complement.
- ''' </summary>
- Private ReadOnly endAddressChecksumComplement As Integer = 29
- ''' <summary>
- ''' The start address of the ROM checksum.
- ''' </summary>
- Private ReadOnly startAddressChecksum As Integer = 30
- ''' <summary>
- ''' The end address of the ROM checksum.
- ''' </summary>
- Private ReadOnly endAddressChecksum As Integer = 31
- #End Region
- #Region " Enumerations "
- ''' <summary>
- ''' Specifies a SNES ROM header type.
- ''' A headered ROM has SMC header and SNES header.
- ''' A headerless ROM has no SMC header, but still contains a SNES header.
- ''' Note that both a LoRom and HiRom images can be headered, or headerless.
- ''' <remarks>http://romhack.wikia.com/wiki/SNES_header</remarks>
- ''' </summary>
- Public Enum HeaderTypeEnum As Integer
- ''' <summary>
- ''' A headered SNES ROM.
- ''' The ROM contains an SMC header, and also contains an SNES header.
- ''' </summary>
- Headered = 0
- ''' <summary>
- ''' A headerless SNES ROM.
- ''' The ROM does not contains an SMC header, but contains an SNES header.
- ''' </summary>
- Headerless = 1
- End Enum
- ''' <summary>
- ''' Specifies a SNES ROM bank type.
- ''' <remarks>http://romhack.wikia.com/wiki/SNES_ROM_layout</remarks>
- ''' </summary>
- Public Enum BankTypeEnum As UShort
- ''' <summary>
- ''' A LoROM maps each ROM bank into the upper half (being addresses $8000 to $ffff) of each SNES bank,
- ''' starting with SNES bank $00, and starting again with SNES bank $80.
- ''' </summary>
- LoRom = 32704US
- ''' <summary>
- ''' A HiROM maps each ROM bank into the whole (being addresses $0000 to $ffff) of each SNES bank,
- ''' starting with SNES bank $40, and starting again with SNES bank $80.
- ''' </summary>
- HiRom = 65472US
- End Enum
- ''' <summary>
- ''' Specifies a SNES ROM cartridge type.
- ''' <remarks>http://softpixel.com/~cwright/sianse/docs/Snesrom.txt</remarks>
- ''' </summary>
- Public Enum CartridgeTypeEnum As Byte
- ''' <summary>
- ''' A ROM only.
- ''' </summary>
- ROM = 0
- ''' <summary>
- ''' A ROM with RAM.
- ''' </summary>
- ROM_RAM = 1
- ''' <summary>
- ''' A ROM with Save-RAM.
- ''' </summary>
- ROM_SRAM = 2
- ''' <summary>
- '''
- ''' </summary>
- ROM_DSP1 = 3
- ''' <summary>
- '''
- ''' </summary>
- ROM_DSP1_RAM = 4
- ''' <summary>
- '''
- ''' </summary>
- ROM_DSP1_SRAM = 5
- ''' <summary>
- '''
- ''' </summary>
- ROM_FX = 19
- ''' <summary>
- '''
- ''' </summary>
- ROM_RAM_GB = 227
- ''' <summary>
- '''
- ''' </summary>
- ROM_DSP2 = 246
- End Enum
- ''' <summary>
- ''' Specifies a SNES Save-RAM size.
- ''' <remarks>http://softpixel.com/~cwright/sianse/docs/Snesrom.txt</remarks>
- ''' </summary>
- Public Enum ROMSizeEnum As Byte
- ''' <summary>
- ''' ROM of 2 Megabit size.
- ''' </summary>
- _2_Mbits = 8
- ''' <summary>
- ''' ROM of 4 Megabit size.
- ''' </summary>
- _4_Mbits = 9
- ''' <summary>
- ''' ROM of 8 Megabit size.
- ''' </summary>
- _8_Mbits = 10
- ''' <summary>
- ''' ROM of 10, 12, or 16 Megabit size.
- ''' </summary>
- _10_or_12_or_16_Mbits = 11
- ''' <summary>
- ''' ROM of 24 or 32 Megabit size.
- ''' </summary>
- _24_or_32_Mbits = 12
- ''' <summary>
- ''' ROM of 48 or 64 Megabit size.
- ''' </summary>
- _48_or_64_Mbits = 13
- End Enum
- ''' <summary>
- ''' Specifies a SNES Save-RAM size.
- ''' <remarks>http://softpixel.com/~cwright/sianse/docs/Snesrom.txt</remarks>
- ''' </summary>
- Public Enum SRAMSizeEnum As Byte
- ''' <summary>
- ''' The ROM does not contains an S-RAM.
- ''' </summary>
- _0_Kbits = 0
- ''' <summary>
- ''' S-RAM of 16 Kilobits.
- ''' </summary>
- _16_Kbits = 1
- ''' <summary>
- ''' S-RAM of 32 Kilobits.
- ''' </summary>
- _32_Kbits = 2
- ''' <summary>
- ''' S-RAM of 64 Kilobits.
- ''' </summary>
- _64_Kbits = 3
- ''' <summary>
- ''' S-RAM of 128 Kilobits.
- ''' </summary>
- _128_Kbits = 4
- ''' <summary>
- ''' S-RAM of 256 Kilobits.
- ''' </summary>
- _256_Kbits = 5
- End Enum
- ''' <summary>
- ''' Specifies a SNES ROM license code.
- ''' <remarks>http://softpixel.com/~cwright/sianse/docs/Snesrom.txt</remarks>
- ''' </summary>
- Public Enum LicenseCodeEnum As Byte
- ''' <summary>
- ''' Any license company.
- ''' </summary>
- _NoLicense = 0
- Nintendo = 1
- Zamuse = 5
- Capcom = 8
- Hot_B = 9
- Jaleco = 10
- Storm = 11
- Mebio_Software = 15
- Gremlin_Graphics = 18
- COBRA_Team = 21
- Human_Field = 22
- Hudson_Soft = 24
- Yanoman = 26
- Tecmo = 28
- Forum = 30
- Virgin = 31
- Tokai_Engeneering = 33
- POW = 34
- Loriciel = 35
- Enix = 38
- Kemco = 40
- Seta = 41
- Visit = 45
- HECT = 53
- Loriciel_1 = 61
- Seika = 64
- UBI_Soft = 65
- Spectrum_Holobyte = 71
- Irem = 73
- Raya_Systems = 75
- Renovation_Pruducts = 76
- Malibu_Games = 77
- US_Gold = 79
- Absolute_Entertainment = 80
- Acclaim = 81
- Activision = 82
- American_Sammy = 83
- GameTek = 84
- Hi_Tech = 85
- LJN_Toys = 86
- Mindscape = 90
- Technos_Japan = 93
- American_Softworks = 95
- Titus = 96
- Virgin_Games = 97
- Maxis = 98
- Ocean = 103
- Electronic_Arts = 105
- Laser_Beam = 107
- Elite = 110
- Electro_Brain = 111
- Infogrames = 112
- Interplay = 113
- LucasArts = 114
- Sculptured_Soft = 115
- Storm_1 = 117
- THQ_Software = 120
- Accolade_Inc = 121
- Triffix_Entertainment = 122
- Microprose = 124
- Kemco_1 = 127
- Namco = 130
- Koei = 132
- Tokuma_Shoten_Intermedia = 134
- DATAM_Polystar = 136
- Bullet_Proof_Software = 139
- Vic_Tokai = 140
- IMax = 143
- CHUN_Soft = 145
- Video_System = 146
- BEC = 147
- Kaneco = 151
- Pack_in_Video = 153
- Nichibutsu = 154
- Tecmo_1 = 155
- Imagineer = 156
- Wolf_Team = 160
- Konami = 164
- K_Amusement = 165
- Takara = 167
- Technos_Japan_1 = 169
- JVC = 170
- Toei_Animation = 172
- Toho = 173
- Namco_1 = 175
- Activision_1 = 177
- BanDai_America = 178
- Enix_1 = 180
- Halken = 182
- Culture_Brain = 186
- Sunsoft = 187
- Toshiba_EMI = 188
- Sony_Imagesoft = 189
- Sammy = 191
- Taito = 192
- Kemco_2 = 194
- Square = 195
- NHK = 196
- Data_East = 197
- Tonkin_House = 198
- Koei_1 = 200
- Konami_USA = 202
- Meldac = 205
- PONY_CANYON = 206
- Sotsu_Agency = 207
- Sofel = 209
- Quest_Corp = 210
- Sigma = 211
- Naxat = 214
- Capcom_1 = 216
- Banpresto = 217
- Hiro = 219
- NCS = 221
- Human_Entertainment = 222
- Ringler_Studios = 223
- Jaleco_1 = 224
- Sotsu_Agency_1 = 226
- TandESoft = 228
- EPOCH = 229
- Athena = 231
- Asmik = 232
- Natsume = 233
- King = 234
- Atlus = 235
- Sony_Music = 236
- Psygnosis = 238
- Beam_Software = 243
- Tec_Magik = 244
- Hudson_Soft_1 = 255
- End Enum
- #End Region
- #Region " Exceptions "
- ''' <summary>
- ''' Exception that is thrown when a SNES ROM has an invalid format.
- ''' </summary>
- <Serializable>
- Public NotInheritable Class InvalidRomFormatException : Inherits Exception
- ''' <summary>
- ''' Initializes a new instance of the <see cref="InvalidROMFormatException"/> class.
- ''' </summary>
- Public Sub New()
- MyBase.New("The SNES ROM image has an invalid format.")
- End Sub
- ''' <summary>
- ''' Initializes a new instance of the <see cref="InvalidROMFormatException"/> class.
- ''' </summary>
- ''' <param name="message">The message that describes the error.</param>
- Public Sub New(ByVal message As String)
- MyBase.New(message)
- End Sub
- ''' <summary>
- ''' Initializes a new instance of the <see cref="InvalidROMFormatException"/> class.
- ''' </summary>
- ''' <param name="message">The message that describes the error.</param>
- ''' <param name="inner">The inner exception.</param>
- Public Sub New(ByVal message As String, ByVal inner As Exception)
- MyBase.New(message, inner)
- End Sub
- End Class
- #End Region
- #Region " Types "
- ''' <summary>
- ''' Defines a SNES ROM country.
- ''' </summary>
- <Serializable>
- Public NotInheritable Class CountryData
- #Region " Properties "
- ''' <summary>
- ''' Gets the region, which can de PAL or NTSC.
- ''' </summary>
- ''' <remarks>http://romhack.wikia.com/wiki/SNES_header</remarks>
- ''' <value>The country code.</value>
- Public ReadOnly Property Region As RegionTypeEnum
- Get
- Return Me.regionB
- End Get
- End Property
- ''' <summary>
- ''' (backing field) The region, which can de PAL or NTSC.
- ''' </summary>
- Private ReadOnly regionB As RegionTypeEnum
- ''' <summary>
- ''' Gets the country code.
- ''' </summary>
- ''' <value>The country code.</value>
- Public ReadOnly Property Code As Byte
- Get
- Return Me.codeB
- End Get
- End Property
- ''' <summary>
- ''' (backing field) The country code.
- ''' </summary>
- Private ReadOnly codeB As Byte
- ''' <summary>
- ''' Gets the country name.
- ''' </summary>
- ''' <value>The country name.</value>
- Public ReadOnly Property Name As String
- Get
- Return Me.nameB
- End Get
- End Property
- ''' <summary>
- ''' (backing field) The country name.
- ''' </summary>
- Private ReadOnly nameB As String
- #End Region
- #Region " Enumerations "
- ''' <summary>
- ''' Specifies a SNES ROM region type.
- ''' <remarks>http://romhack.wikia.com/wiki/SNES_header</remarks>
- ''' </summary>
- Public Enum RegionTypeEnum As Integer
- ''' <summary>
- ''' A PAL SNES ROM.
- ''' </summary>
- Pal = 0
- ''' <summary>
- ''' An NTSC SNES ROM.
- ''' </summary>
- Ntsc = 1
- End Enum
- #End Region
- #Region " Countries "
- ''' <summary>
- ''' The NTSC and PAL countries, based on country code from 0 to 13, so countrycode 0 = Japan, countrycode 1 = United States, and so on.
- ''' <remarks>http://softpixel.com/~cwright/sianse/docs/Snesrom.txt</remarks>
- ''' </summary>
- Private ReadOnly countryDict As New Dictionary(Of Integer, String) From
- {
- {0, "Japan"},
- {1, "United States"},
- {2, "Europe, Oceania, Asia"},
- {3, "Sweden"},
- {4, "Finland"},
- {5, "Denmark"},
- {6, "France"},
- {7, "Holland"},
- {8, "Spain"},
- {9, "Germany, Austria, Switz"},
- {10, "Italy"},
- {11, "Hong Kong, China"},
- {12, "Indonesia"},
- {13, "Korea"}
- }
- #End Region
- #Region " Regions "
- ''' <summary>
- ''' The country codes for NTSC region.
- ''' <remarks>http://softpixel.com/~cwright/sianse/docs/Snesrom.txt</remarks>
- ''' </summary>
- Private ReadOnly ntscRegionCodes As Integer() =
- {0, 1}
- ''' <summary>
- ''' The country codes for PAL region.
- ''' <remarks>http://softpixel.com/~cwright/sianse/docs/Snesrom.txt</remarks>
- ''' </summary>
- Private ReadOnly palRegionCodes As Integer() =
- {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}
- #End Region
- #Region " Constructors "
- ''' <summary>
- ''' Initializes a new instance of the <see cref="CountryData"/> class.
- ''' </summary>
- ''' <param name="countryCode">The SNES ROM country code.</param>
- ''' <exception cref="ArgumentException">Invalid country code.;countryCode</exception>
- Public Sub New(ByVal countryCode As Byte)
- If Not (Me.ntscRegionCodes.Concat(Me.palRegionCodes)).Contains(countryCode) Then
- Throw New ArgumentException(message:="Invalid country code.", paramName:="countryCode")
- Else
- Me.codeB = countryCode
- Me.nameB = Me.countryDict(countryCode)
- ' Determine region.
- If Me.ntscRegionCodes.Contains(countryCode) Then
- Me.regionB = RegionTypeEnum.Ntsc
- ElseIf Me.palRegionCodes.Contains(countryCode) Then
- Me.regionB = RegionTypeEnum.Pal
- End If
- End If
- End Sub
- ''' <summary>
- ''' Prevents a default instance of the <see cref="CountryData"/> class from being created.
- ''' </summary>
- Private Sub New()
- End Sub
- #End Region
- End Class
- #End Region
- #Region " Constructors "
- ''' <summary>
- ''' Prevents a default instance of the <see cref="SnesRom"/> class from being created.
- ''' </summary>
- Private Sub New()
- End Sub
- ''' <summary>
- ''' Initializes a new instance of the <see cref="SnesRom"/> class.
- ''' </summary>
- ''' <param name="romFilePath">The SNES ROM file path.</param>
- Public Sub New(ByVal romFilePath As String)
- Me.New(File.ReadAllBytes(romFilePath))
- End Sub
- ''' <summary>
- ''' Initializes a new instance of the <see cref="SnesRom"/> class.
- ''' </summary>
- ''' <param name="romData">The raw byte-data of the ROM file.</param>
- Public Sub New(ByVal romData As Byte())
- Me.rawDataB = romData
- Me.VerifyRomFormat()
- Me.VerifyBankType()
- Me.ReadHeader()
- End Sub
- #End Region
- #Region " Private Methods "
- ''' <summary>
- ''' Reads the ROM header to retrieve the header data.
- ''' </summary>
- Private Sub ReadHeader()
- ' Read range of bytes.
- Me.nameB = Encoding.ASCII.GetString(Me.GetBytes(Me.startAddressName, Me.endAddressName)).Trim
- ' Read single bytes.
- Me.layoutB = Me.GetByte(Me.startAddressLayout)
- Me.cartridgeTypeB = DirectCast(Me.GetByte(Me.startAddressCartridgeType), CartridgeTypeEnum)
- Me.romSizeB = Me.GetByte(Me.startAddressRomSize)
- Me.ramSizeB = Me.GetByte(Me.startAddressRamSize)
- Me.CountryCode = Me.GetByte(Me.startAddressCountryCode)
- Me.licenseCodeB = Me.GetByte(Me.startAddressLicenseCode)
- Me.versionB = Me.GetByte(Me.startAddressVersion)
- End Sub
- ''' <summary>
- ''' Verifies the SNES ROM format.
- ''' </summary>
- ''' <exception cref="SnesRom.InvalidRomFormatException">The SNES ROM image has an invalid format.</exception>
- Private Sub VerifyRomFormat()
- If (Me.rawDataB.Length Mod 1024 = 512) Then
- Me.headerTypeB = HeaderTypeEnum.Headered
- ElseIf (Me.rawDataB.Length Mod 1024 = 0) Then
- Me.headerTypeB = HeaderTypeEnum.Headerless
- Else
- Throw New InvalidRomFormatException(message:="The SNES ROM image has an invalid format.")
- End If
- End Sub
- ''' <summary>
- ''' Verifies the SNES ROM bank type.
- ''' </summary>
- ''' <exception cref="Exception">Cannot recognize the bank type.</exception>
- Private Sub VerifyBankType()
- If Me.HeaderIsAt(BankTypeEnum.LoRom) Then
- Me.bankTypeB = BankTypeEnum.LoRom
- ElseIf Me.HeaderIsAt(BankTypeEnum.HiRom) Then
- Me.bankTypeB = BankTypeEnum.HiRom
- Else
- Throw New Exception(message:="Cannot recognize the bank type.")
- End If
- End Sub
- ''' <summary>
- ''' Verifies the checksum.
- ''' </summary>
- ''' <remarks>
- ''' Offset 0x07FC0 in a headerless LoROM image (LoROM rom sin smc header)
- ''' Offset 0x0FFC0 in a headerless HiROM image (HiROM rom sin smc header)
- ''' </remarks>
- ''' <returns><c>true</c> if checksum is ok, <c>false</c> otherwise.</returns>
- Private Function VerifyChecksum() As Boolean
- If Me.HeaderType = HeaderTypeEnum.Headered Then
- Me.headerLocationB += 512
- End If
- Me.checksumComplementB = BitConverter.ToUInt16(Me.GetBytes(Me.startAddressChecksumComplement, Me.endAddressChecksumComplement), startIndex:=0)
- Me.checksumB = BitConverter.ToUInt16(Me.GetBytes(Me.startAddressChecksum, Me.endAddressChecksum), startIndex:=0)
- Return CUShort(Me.Checksum Xor Me.ChecksumComplement).Equals(UShort.MaxValue)
- End Function
- ''' <summary>
- ''' Determines whether the ROM header is in the specified address.
- ''' </summary>
- ''' <param name="address">The address.</param>
- ''' <returns><c>true</c> if the ROM header is in the specified address, <c>false</c> otherwise.</returns>
- Private Function HeaderIsAt(ByVal address As UShort) As Boolean
- Me.headerLocationB = address
- Return Me.VerifyChecksum()
- End Function
- ''' <summary>
- ''' Gets the specified byte from the raw byte-data.
- ''' </summary>
- ''' <param name="address">The address.</param>
- ''' <returns>The specified byte from the raw byte-data.</returns>
- Private Function GetByte(ByVal address As Integer) As Byte
- Return Buffer.GetByte(array:=Me.RawData,
- index:=Me.HeaderLocation + address)
- End Function
- ''' <summary>
- ''' Gets the specified range of bytes from the raw byte-data.
- ''' </summary>
- ''' <param name="from">From address.</param>
- ''' <param name="to">To address.</param>
- ''' <returns>The specified bytes from the raw byte-data.</returns>
- Private Function GetBytes(ByVal from As Integer,
- ByVal [to] As Integer) As Byte()
- Return Me.RawData.Skip(Me.HeaderLocation + from).Take(([to] - from) + 1).ToArray()
- End Function
- ''' <summary>
- ''' Replaces a single byte in the raw byte-data, with the specified data.
- ''' </summary>
- ''' <param name="address">the address.</param>
- ''' <param name="data">The byte-data.</param>
- Private Sub SetByte(ByVal address As Integer,
- ByVal data As Byte)
- Buffer.SetByte(array:=Me.rawDataB,
- index:=Me.HeaderLocation + address,
- value:=data)
- End Sub
- ''' <summary>
- ''' Replaces the specified range of bytes in the raw byte-data, with the specified data.
- ''' </summary>
- ''' <param name="from">From address.</param>
- ''' <param name="to">To address.</param>
- ''' <param name="data">The byte-data.</param>
- ''' <exception cref="ArgumentException">The byte-length of the specified data differs from the byte-length to be replaced;data</exception>
- Private Sub SetBytes(ByVal from As Integer,
- ByVal [to] As Integer,
- ByVal data As Byte())
- If data.Length <> (([to] - from) + 1) Then
- Throw New ArgumentException("The byte-length of the specified data differs from the byte-length to be replaced.", "data")
- Else
- Buffer.BlockCopy(src:=data, srcOffset:=0,
- dst:=Me.rawDataB, dstOffset:=Me.HeaderLocation + from,
- count:=([to] - from) + 1)
- End If
- End Sub
- ''' <summary>
- ''' Sets the ROM name.
- ''' </summary>
- ''' <param name="name">The ROM name.</param>
- ''' <exception cref="ArgumentNullException">name</exception>
- ''' <exception cref="ArgumentException">The name should contain 21 or less characters;name.</exception>
- Private Sub SetName(ByVal name As String)
- Dim fixedNameLength As Integer = (Me.endAddressName - Me.startAddressName) + 1
- If String.IsNullOrEmpty(name) Then
- Throw New ArgumentNullException(paramName:="name")
- ElseIf (name.Length > fixedNameLength) Then
- Throw New ArgumentException(message:="The name should contain 21 or less characters.", paramName:="name")
- Else
- ' fill with spaces up to 21 character length.
- name = name.PadRight(totalWidth:=fixedNameLength, paddingChar:=" "c)
- Me.SetBytes(Me.startAddressName, Me.endAddressName, Encoding.ASCII.GetBytes(name))
- End If
- End Sub
- #End Region
- #Region " Public Methods "
- ''' <summary>
- ''' Save the ROM changes to the specified file path.
- ''' </summary>
- ''' <param name="filePath">The ROM file path.</param>
- ''' <param name="replace">
- ''' If set to <c>true</c>, then replaces any existing file,
- ''' otherwise, throws an <see cref="IOException"/> exception if file already exists.
- ''' </param>
- ''' <exception cref="IOException">The destination file already exists.</exception>
- Public Sub Save(ByVal filePath As String, ByVal replace As Boolean)
- If Not replace AndAlso File.Exists(filePath) Then
- Throw New IOException(message:="The destination file already exists.")
- Else
- Try
- File.WriteAllBytes(filePath, Me.rawDataB)
- Catch ex As Exception
- Throw
- End Try
- End If
- End Sub
- #End Region
- End Class
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement