Files
Aaru/FileSystemIDandChk/Plugins/ISO9660.cs
Natalia Portillo a20dbb709a * FileSystemIDandChk/Plugins/ISO9660.cs:
Added code preventing it to be run on each partition,
	  because this filesystem will be once and only. Now it runs
	  only one time whenever there are partitions or how many.

	* FileSystemIDandChk/Plugins/FAT.cs:
	  Added code to handle false positives (FATs can be 1 or 2,
	  maybe 0 in the wild, never bigger).
	Modified for BinaryReader class.

	* FileSystemIDandChk/Plugins/BFS.cs:
	  Missed negation operand

	* FileSystemIDandChk/PartPlugins/NeXT.cs:
	* FileSystemIDandChk/PartPlugins/AppleMap.cs:
	  Added constants and modified for EndianAwareBinaryReader
	  class.

git-svn-id: svn://claunia.com/FileSystemIDandChk@16 17725271-3d32-4980-a8cb-9ff532f270ba
2012-08-05 03:02:55 +00:00

924 lines
53 KiB
C#

using System;
using System.IO;
using System.Text;
using System.Globalization;
using FileSystemIDandChk;
// This is coded following ECMA-119.
// TODO: Differentiate ISO Level 1, 2, 3 and ISO 9660:1999
// TODO: Apple extensiones, requires XA or advance RR interpretation.
namespace FileSystemIDandChk.Plugins
{
class ISO9660Plugin : Plugin
{
private static bool alreadyLaunched;
public ISO9660Plugin(PluginBase Core)
{
base.Name = "ISO9660 Filesystem";
base.PluginUUID = new Guid("d812f4d3-c357-400d-90fd-3b22ef786aa8");
alreadyLaunched = false;
}
private struct DecodedVolumeDescriptor
{
public string SystemIdentifier;
public string VolumeIdentifier;
public string VolumeSetIdentifier;
public string PublisherIdentifier;
public string DataPreparerIdentifier;
public string ApplicationIdentifier;
public DateTime CreationTime;
public bool HasModificationTime;
public DateTime ModificationTime;
public bool HasExpirationTime;
public DateTime ExpirationTime;
public bool HasEffectiveTime;
public DateTime EffectiveTime;
}
public override bool Identify(FileStream fileStream, long offset)
{
if(alreadyLaunched)
return false;
else
alreadyLaunched = true;
byte VDType;
// ISO9660 Primary Volume Descriptor starts at 32768, so that's minimal size.
if (fileStream.Length < 32768)
return false;
// Seek to Volume Descriptor
fileStream.Seek(32768, SeekOrigin.Begin);
VDType = (byte)fileStream.ReadByte();
byte[] VDMagic = new byte[5];
// Wrong, VDs can be any order!
if (VDType == 255) // Supposedly we are in the PVD.
return false;
if (fileStream.Read(VDMagic, 0, 5) != 5)
return false; // Something bad happened
if (Encoding.ASCII.GetString(VDMagic) != "CD001") // Recognized, it is an ISO9660, now check for rest of data.
return false;
return true;
}
public override void GetInformation (FileStream fileStream, long offset, out string information)
{
information = "";
StringBuilder ISOMetadata = new StringBuilder();
bool Joliet = false;
bool Bootable = false;
bool RockRidge = false;
byte VDType; // Volume Descriptor Type, should be 1 or 2.
byte[] VDMagic = new byte[5]; // Volume Descriptor magic "CD001"
byte[] VDSysId = new byte[32]; // System Identifier
byte[] VDVolId = new byte[32]; // Volume Identifier
byte[] VDVolSetId = new byte[128]; // Volume Set Identifier
byte[] VDPubId = new byte[128]; // Publisher Identifier
byte[] VDDataPrepId = new byte[128]; // Data Preparer Identifier
byte[] VDAppId = new byte[128]; // Application Identifier
byte[] VCTime = new byte[17]; // Volume Creation Date and Time
byte[] VMTime = new byte[17]; // Volume Modification Date and Time
byte[] VXTime = new byte[17]; // Volume Expiration Date and Time
byte[] VETime = new byte[17]; // Volume Effective Date and Time
byte[] JolietMagic = new byte[3];
byte[] JolietSysId = new byte[32]; // System Identifier
byte[] JolietVolId = new byte[32]; // Volume Identifier
byte[] JolietVolSetId = new byte[128]; // Volume Set Identifier
byte[] JolietPubId = new byte[128]; // Publisher Identifier
byte[] JolietDataPrepId = new byte[128]; // Data Preparer Identifier
byte[] JolietAppId = new byte[128]; // Application Identifier
byte[] JolietCTime = new byte[17]; // Volume Creation Date and Time
byte[] JolietMTime = new byte[17]; // Volume Modification Date and Time
byte[] JolietXTime = new byte[17]; // Volume Expiration Date and Time
byte[] JolietETime = new byte[17]; // Volume Effective Date and Time
byte[] BootSysId = new byte[32];
string BootSpec = "";
byte[] VDPathTableStart = new byte[4];
byte[] RootDirectoryLocation = new byte[4];
fileStream.Seek(0, SeekOrigin.Begin);
// ISO9660 Primary Volume Descriptor starts at 32768, so that's minimal size.
if (fileStream.Length < 32768)
return;
int counter = 0;
while (true)
{
// Seek to Volume Descriptor
fileStream.Seek(32768+(2048*counter), SeekOrigin.Begin);
VDType = (byte)fileStream.ReadByte();
if (VDType == 255) // Supposedly we are in the PVD.
{
if (counter == 0)
return;
break;
}
if (fileStream.Read(VDMagic, 0, 5) != 5)
{
if (counter == 0)
return; // Something bad happened
break;
}
if (Encoding.ASCII.GetString(VDMagic) != "CD001") // Recognized, it is an ISO9660, now check for rest of data.
{
if (counter == 0)
return;
break;
}
switch(VDType)
{
case 0: // TODO
{
Bootable = true;
BootSpec = "Unknown";
// Seek to boot system identifier
fileStream.Seek(32775 + (2048 * counter), SeekOrigin.Begin);
if (fileStream.Read(BootSysId, 0, 32) != 32)
break; // Something bad happened
if (Encoding.ASCII.GetString(BootSysId).Substring(0, 23) == "EL TORITO SPECIFICATION")
BootSpec = "El Torito";
break;
}
case 1:
{
// Seek to first identifiers
fileStream.Seek(32776 + (2048 * counter), SeekOrigin.Begin);
if (fileStream.Read(VDSysId, 0, 32) != 32)
break; // Something bad happened
if (fileStream.Read(VDVolId, 0, 32) != 32)
break; // Something bad happened
// Get path table start
fileStream.Seek(32908 + (2048 * counter), SeekOrigin.Begin);
if (fileStream.Read(VDPathTableStart, 0, 4) != 4)
break; // Something bad happened
// Seek to next identifiers
fileStream.Seek(32958 + (2048 * counter), SeekOrigin.Begin);
if (fileStream.Read(VDVolSetId, 0, 128) != 128)
break; // Something bad happened
if (fileStream.Read(VDPubId, 0, 128) != 128)
break; // Something bad happened
if (fileStream.Read(VDDataPrepId, 0, 128) != 128)
break; // Something bad happened
if (fileStream.Read(VDAppId, 0, 128) != 128)
break; // Something bad happened
// Seek to dates
fileStream.Seek(33581 + (2048 * counter), SeekOrigin.Begin);
if (fileStream.Read(VCTime, 0, 17) != 17)
break; // Something bad happened
if (fileStream.Read(VMTime, 0, 17) != 17)
break; // Something bad happened
if (fileStream.Read(VXTime, 0, 17) != 17)
break; // Something bad happened
if (fileStream.Read(VETime, 0, 17) != 17)
break; // Something bad happened
break;
}
case 2:
{
// Check if this is Joliet
fileStream.Seek(32856 + (2048 * counter), SeekOrigin.Begin);
if (fileStream.Read(JolietMagic, 0, 3) != 3)
{
break; // Something bad happened
}
if (JolietMagic[0] == '%' && JolietMagic[1] == '/')
{
if (JolietMagic[2] == '@' || JolietMagic[2] == 'C' || JolietMagic[2] == 'E')
{
Joliet = true;
}
else
{
break;
}
}
else
break;
// Seek to first identifiers
fileStream.Seek(32776 + (2048 * counter), SeekOrigin.Begin);
if (fileStream.Read(JolietSysId, 0, 32) != 32)
break; // Something bad happened
if (fileStream.Read(JolietVolId, 0, 32) != 32)
break; // Something bad happened
// Seek to next identifiers
fileStream.Seek(32958 + (2048 * counter), SeekOrigin.Begin);
if (fileStream.Read(JolietVolSetId, 0, 128) != 128)
break; // Something bad happened
if (fileStream.Read(JolietPubId, 0, 128) != 128)
break; // Something bad happened
if (fileStream.Read(JolietDataPrepId, 0, 128) != 128)
break; // Something bad happened
if (fileStream.Read(JolietAppId, 0, 128) != 128)
break; // Something bad happened
// Seek to dates
fileStream.Seek(33581 + (2048 * counter), SeekOrigin.Begin);
if (fileStream.Read(JolietCTime, 0, 17) != 17)
break; // Something bad happened
if (fileStream.Read(JolietMTime, 0, 17) != 17)
break; // Something bad happened
if (fileStream.Read(JolietXTime, 0, 17) != 17)
break; // Something bad happened
if (fileStream.Read(JolietETime, 0, 17) != 17)
break; // Something bad happened
break;
}
}
counter++;
}
DecodedVolumeDescriptor decodedVD = new DecodedVolumeDescriptor();
DecodedVolumeDescriptor decodedJolietVD = new DecodedVolumeDescriptor();
decodedVD = DecodeVolumeDescriptor(VDSysId, VDVolId, VDVolSetId, VDPubId, VDDataPrepId, VDAppId, VCTime, VMTime, VXTime, VETime);
if(Joliet)
decodedJolietVD = DecodeJolietDescriptor(JolietSysId, JolietVolId, JolietVolSetId, JolietPubId, JolietDataPrepId, JolietAppId, JolietCTime, JolietMTime, JolietXTime, JolietETime);
int i = BitConverter.ToInt32(VDPathTableStart, 0);
fileStream.Seek((i * 2048)+2, SeekOrigin.Begin); // Seek to first path table location field
// Check for Rock Ridge
if (fileStream.Read(RootDirectoryLocation, 0, 4) == 4)
{
fileStream.Seek((BitConverter.ToInt32(RootDirectoryLocation,0) * 2048)+34, SeekOrigin.Begin); // Seek to root directory, first entry, system use field
byte[] SUSPMagic = new byte[2];
byte[] RRMagic = new byte[2];
fileStream.Read(SUSPMagic, 0, 2);
if (Encoding.ASCII.GetString(SUSPMagic) == "SP")
{
fileStream.Seek(5, SeekOrigin.Current); // Seek for rock ridge magic
fileStream.Read(RRMagic, 0, 2);
if (Encoding.ASCII.GetString(RRMagic) == "RR")
{
RockRidge = true;
}
}
}
#region SEGA IP.BIN Read and decoding
bool SegaCD = false;
bool Saturn = false;
bool Dreamcast = false;
StringBuilder IPBinInformation = new StringBuilder();
byte[] SegaHardwareID = new byte[16];
fileStream.Seek(0, SeekOrigin.Begin); // Seek to start (again)
fileStream.Read(SegaHardwareID, 0, 16);
switch (Encoding.ASCII.GetString(SegaHardwareID))
{
case "SEGADISCSYSTEM ":
case "SEGADATADISC ":
case "SEGAOS ":
{
SegaCD = true; // Ok, this contains SegaCD IP.BIN
IPBinInformation.AppendLine("--------------------------------");
IPBinInformation.AppendLine("SEGA IP.BIN INFORMATION:");
IPBinInformation.AppendLine("--------------------------------");
// Definitions following
byte[] volume_name = new byte[11]; // Varies
byte[] spare_space1 = new byte[1]; // 0x00
byte[] volume_version = new byte[2]; // Volume version in BCD. <100 = Prerelease.
byte[] volume_type = new byte[2]; // Bit 0 = 1 => CD-ROM. Rest should be 0.
byte[] system_name = new byte[11]; // Unknown, varies!
byte[] spare_space2 = new byte[1]; // 0x00
byte[] system_version = new byte[2]; // Should be 1
byte[] spare_space3 = new byte[2]; // 0x0000
byte[] ip_address = new byte[4]; // Initial program address
byte[] ip_loadsize = new byte[4]; // Load size of initial program
byte[] ip_entry_address = new byte[4]; // Initial program entry address
byte[] ip_work_ram_size = new byte[4]; // Initial program work RAM size in bytes
byte[] sp_address = new byte[4]; // System program address
byte[] sp_loadsize = new byte[4]; // Load size of system program
byte[] sp_entry_address = new byte[4]; // System program entry address
byte[] sp_work_ram_size = new byte[4]; // System program work RAM size in bytes
byte[] release_date = new byte[8]; // MMDDYYYY
byte[] unknown1 = new byte[7]; // Seems to be all 0x20s
byte[] spare_space4 = new byte[1]; // 0x00 ?
byte[] system_reserved = new byte[160]; // System Reserved Area
byte[] hardware_id = new byte[16]; // Hardware ID
byte[] copyright = new byte[3]; // "(C)" -- Can be the developer code directly!, if that is the code release date will be displaced
byte[] developer_code = new byte[5]; // "SEGA" or "T-xx"
byte[] unknown2 = new byte[1]; // Seems to be part of developer code, need to get a SEGA disc to check
byte[] release_date2 = new byte[8]; // Another release date, this with month in letters?
byte[] domestic_title = new byte[48]; // Domestic version of the game title
byte[] overseas_title = new byte[48]; // Overseas version of the game title
byte[] application_type = new byte[2]; // Application type
byte[] space_space5 = new byte[1]; // 0x20
byte[] product_code = new byte[13]; // Official product code
byte[] peripherals = new byte[16]; // Supported peripherals, see above
byte[] spare_space6 = new byte[16]; // 0x20
byte[] spare_space7 = new byte[64]; // Inside here should be modem information, but I need to get a modem-enabled game
byte[] region_codes = new byte[16]; // Region codes, space-filled
//Reading all data
fileStream.Read(volume_name, 0, 11); // Varies
fileStream.Read(spare_space1, 0, 1); // 0x00
fileStream.Read(volume_version, 0, 2); // Volume version in BCD. <100 = Prerelease.
fileStream.Read(volume_type, 0, 2); // Bit 0 = 1 => CD-ROM. Rest should be 0.
fileStream.Read(system_name, 0, 11); // Unknown, varies!
fileStream.Read(spare_space2, 0, 1); // 0x00
fileStream.Read(system_version, 0, 2); // Should be 1
fileStream.Read(spare_space3, 0, 2); // 0x0000
fileStream.Read(ip_address, 0, 4); // Initial program address
fileStream.Read(ip_loadsize, 0, 4); // Load size of initial program
fileStream.Read(ip_entry_address, 0, 4); // Initial program entry address
fileStream.Read(ip_work_ram_size, 0, 4); // Initial program work RAM size in bytes
fileStream.Read(sp_address, 0, 4); // System program address
fileStream.Read(sp_loadsize, 0, 4); // Load size of system program
fileStream.Read(sp_entry_address, 0, 4); // System program entry address
fileStream.Read(sp_work_ram_size, 0, 4); // System program work RAM size in bytes
fileStream.Read(release_date, 0, 8); // MMDDYYYY
fileStream.Read(unknown1, 0, 7); // Seems to be all 0x20s
fileStream.Read(spare_space4, 0, 1); // 0x00 ?
fileStream.Read(system_reserved, 0, 160); // System Reserved Area
fileStream.Read(hardware_id, 0, 16); // Hardware ID
fileStream.Read(copyright, 0, 3); // "(C)" -- Can be the developer code directly!, if that is the code release date will be displaced
if (Encoding.ASCII.GetString(copyright) != "(C)")
fileStream.Seek(-3, SeekOrigin.Current);
fileStream.Read(developer_code, 0, 5); // "SEGA" or "T-xx"
if (Encoding.ASCII.GetString(copyright) != "(C)")
fileStream.Seek(1, SeekOrigin.Current);
fileStream.Read(release_date2, 0, 8); // Another release date, this with month in letters?
if (Encoding.ASCII.GetString(copyright) != "(C)")
fileStream.Seek(2, SeekOrigin.Current);
fileStream.Read(domestic_title, 0, 48); // Domestic version of the game title
fileStream.Read(overseas_title, 0, 48); // Overseas version of the game title
fileStream.Read(application_type, 0, 2); // Application type
fileStream.Read(space_space5, 0, 1); // 0x20
fileStream.Read(product_code, 0, 13); // Official product code
fileStream.Read(peripherals, 0, 16); // Supported peripherals, see above
fileStream.Read(spare_space6, 0, 16); // 0x20
fileStream.Read(spare_space7, 0, 64); // Inside here should be modem information, but I need to get a modem-enabled game
fileStream.Read(region_codes, 0, 16); // Region codes, space-filled
// Decoding all data
DateTime ipbindate = new DateTime();
CultureInfo provider = CultureInfo.InvariantCulture;
ipbindate = DateTime.ParseExact(Encoding.ASCII.GetString(release_date), "MMddyyyy", provider);
switch (Encoding.ASCII.GetString(application_type))
{
case "GM":
IPBinInformation.AppendLine("Disc is a game.");
break;
case "AI":
IPBinInformation.AppendLine("Disc is an application.");
break;
default:
IPBinInformation.AppendLine("Disc is from unknown type.");
break;
}
IPBinInformation.AppendFormat("Volume name: {0}", Encoding.ASCII.GetString(volume_name)).AppendLine();
//IPBinInformation.AppendFormat("Volume version: {0}", Encoding.ASCII.GetString(volume_version)).AppendLine();
//IPBinInformation.AppendFormat("{0}", Encoding.ASCII.GetString(volume_type)).AppendLine();
IPBinInformation.AppendFormat("System name: {0}", Encoding.ASCII.GetString(system_name)).AppendLine();
//IPBinInformation.AppendFormat("System version: {0}", Encoding.ASCII.GetString(system_version)).AppendLine();
IPBinInformation.AppendFormat("Initial program address: 0x{0}", BitConverter.ToInt32(ip_address, 0).ToString("X")).AppendLine();
IPBinInformation.AppendFormat("Initial program load size: {0} bytes", BitConverter.ToInt32(ip_loadsize, 0)).AppendLine();
IPBinInformation.AppendFormat("Initial program entry address: 0x{0}", BitConverter.ToInt32(ip_entry_address, 0).ToString("X")).AppendLine();
IPBinInformation.AppendFormat("Initial program work RAM: {0} bytes", BitConverter.ToInt32(ip_work_ram_size, 0)).AppendLine();
IPBinInformation.AppendFormat("System program address: 0x{0}", BitConverter.ToInt32(sp_address, 0).ToString("X")).AppendLine();
IPBinInformation.AppendFormat("System program load size: {0} bytes", BitConverter.ToInt32(sp_loadsize, 0)).AppendLine();
IPBinInformation.AppendFormat("System program entry address: 0x{0}", BitConverter.ToInt32(sp_entry_address, 0).ToString("X")).AppendLine();
IPBinInformation.AppendFormat("System program work RAM: {0} bytes", BitConverter.ToInt32(sp_work_ram_size, 0)).AppendLine();
IPBinInformation.AppendFormat("Release date: {0}", ipbindate.ToString()).AppendLine();
IPBinInformation.AppendFormat("Release date (other format): {0}", Encoding.ASCII.GetString(release_date2)).AppendLine();
IPBinInformation.AppendFormat("Hardware ID: {0}", Encoding.ASCII.GetString(hardware_id)).AppendLine();
IPBinInformation.AppendFormat("Developer code: {0}", Encoding.ASCII.GetString(developer_code)).AppendLine();
IPBinInformation.AppendFormat("Domestic title: {0}", Encoding.ASCII.GetString(domestic_title)).AppendLine();
IPBinInformation.AppendFormat("Overseas title: {0}", Encoding.ASCII.GetString(overseas_title)).AppendLine();
IPBinInformation.AppendFormat("Product code: {0}", Encoding.ASCII.GetString(product_code)).AppendLine();
IPBinInformation.AppendFormat("Peripherals:").AppendLine();
foreach(byte peripheral in peripherals)
{
switch((char)peripheral)
{
case 'A':
IPBinInformation.AppendLine("Game supports analog controller.");
break;
case 'B':
IPBinInformation.AppendLine("Game supports trackball.");
break;
case 'G':
IPBinInformation.AppendLine("Game supports light gun.");
break;
case 'J':
IPBinInformation.AppendLine("Game supports JoyPad.");
break;
case 'K':
IPBinInformation.AppendLine("Game supports keyboard.");
break;
case 'M':
IPBinInformation.AppendLine("Game supports mouse.");
break;
case 'O':
IPBinInformation.AppendLine("Game supports Master System's JoyPad.");
break;
case 'P':
IPBinInformation.AppendLine("Game supports printer interface.");
break;
case 'R':
IPBinInformation.AppendLine("Game supports serial (RS-232C) interface.");
break;
case 'T':
IPBinInformation.AppendLine("Game supports tablet interface.");
break;
case 'V':
IPBinInformation.AppendLine("Game supports paddle controller.");
break;
case ' ':
break;
default:
IPBinInformation.AppendFormat("Game supports unknown peripheral {0}.", peripheral.ToString()).AppendLine();
break;
}
}
IPBinInformation.AppendLine("Regions supported:");
foreach (byte region in region_codes)
{
switch ((char)region)
{
case 'J':
IPBinInformation.AppendLine("Japanese NTSC.");
break;
case 'U':
IPBinInformation.AppendLine("USA NTSC.");
break;
case 'E':
IPBinInformation.AppendLine("Europe PAL.");
break;
case ' ':
break;
default:
IPBinInformation.AppendFormat("Game supports unknown region {0}.", region.ToString()).AppendLine();
break;
}
}
break;
}
case "SEGA SEGASATURN ":
{
Saturn = true;
IPBinInformation.AppendLine("--------------------------------");
IPBinInformation.AppendLine("SEGA IP.BIN INFORMATION:");
IPBinInformation.AppendLine("--------------------------------");
// Definitions following
byte[] maker_id = new byte[16]; // "SEGA ENTERPRISES"
byte[] product_no = new byte[10]; // Product number
byte[] product_version = new byte[6]; // Product version
byte[] release_date = new byte[8]; // YYYYMMDD
byte[] saturn_media = new byte[3]; // "CD-"
byte[] disc_no = new byte[1]; // Disc number
byte[] disc_no_separator = new byte[1]; // '/'
byte[] disc_total_nos = new byte[1]; // Total number of discs
byte[] spare_space1 = new byte[2]; // " "
byte[] region_codes = new byte[10]; // Region codes, space-filled
byte[] spare_space2 = new byte[6]; // " "
byte[] peripherals = new byte[16]; // Supported peripherals, see above
byte[] product_name = new byte[112]; // Game name, space-filled
// Reading all data
fileStream.Read(maker_id, 0, 16); // "SEGA ENTERPRISES"
fileStream.Read(product_no, 0, 10); // Product number
fileStream.Read(product_version, 0, 6); // Product version
fileStream.Read(release_date, 0, 8); // YYYYMMDD
fileStream.Read(saturn_media, 0, 3); // "CD-"
fileStream.Read(disc_no, 0, 1); // Disc number
fileStream.Read(disc_no_separator, 0, 1); // '/'
fileStream.Read(disc_total_nos, 0, 1); // Total number of discs
fileStream.Read(spare_space1, 0, 2); // " "
fileStream.Read(region_codes, 0, 10); // Region codes, space-filled
fileStream.Read(spare_space2, 0, 6); // " "
fileStream.Read(peripherals, 0, 16); // Supported peripherals, see above
fileStream.Read(product_name, 0, 112); // Game name, space-filled
// Decoding all data
DateTime ipbindate = new DateTime();
CultureInfo provider = CultureInfo.InvariantCulture;
ipbindate = DateTime.ParseExact(Encoding.ASCII.GetString(release_date), "yyyyMMdd", provider);
IPBinInformation.AppendFormat("Product name: {0}", Encoding.ASCII.GetString(product_name)).AppendLine();
IPBinInformation.AppendFormat("Product number: {0}", Encoding.ASCII.GetString(product_no)).AppendLine();
IPBinInformation.AppendFormat("Product version: {0}", Encoding.ASCII.GetString(product_version)).AppendLine();
IPBinInformation.AppendFormat("Release date: {0}", ipbindate.ToString()).AppendLine();
IPBinInformation.AppendFormat("Disc number {0} of {1}", Encoding.ASCII.GetString(disc_no), Encoding.ASCII.GetString(disc_total_nos)).AppendLine();
IPBinInformation.AppendFormat("Peripherals:").AppendLine();
foreach (byte peripheral in peripherals)
{
switch ((char)peripheral)
{
case 'A':
IPBinInformation.AppendLine("Game supports analog controller.");
break;
case 'J':
IPBinInformation.AppendLine("Game supports JoyPad.");
break;
case 'K':
IPBinInformation.AppendLine("Game supports keyboard.");
break;
case 'M':
IPBinInformation.AppendLine("Game supports mouse.");
break;
case 'S':
IPBinInformation.AppendLine("Game supports analog steering controller.");
break;
case 'T':
IPBinInformation.AppendLine("Game supports multitap.");
break;
case ' ':
break;
default:
IPBinInformation.AppendFormat("Game supports unknown peripheral {0}.", peripheral.ToString()).AppendLine();
break;
}
}
IPBinInformation.AppendLine("Regions supported:");
foreach (byte region in region_codes)
{
switch ((char)region)
{
case 'J':
IPBinInformation.AppendLine("Japanese NTSC.");
break;
case 'U':
IPBinInformation.AppendLine("North America NTSC.");
break;
case 'E':
IPBinInformation.AppendLine("Europe PAL.");
break;
case 'T':
IPBinInformation.AppendLine("Asia NTSC.");
break;
case ' ':
break;
default:
IPBinInformation.AppendFormat("Game supports unknown region {0}.", region.ToString()).AppendLine();
break;
}
}
break;
}
case "SEGA SEGAKATANA ":
{
Dreamcast = true;
IPBinInformation.AppendLine("--------------------------------");
IPBinInformation.AppendLine("SEGA IP.BIN INFORMATION:");
IPBinInformation.AppendLine("--------------------------------");
// Declarations following
byte[] maker_id = new byte[16]; // "SEGA ENTERPRISES"
byte[] dreamcast_crc = new byte[4]; // CRC of product_no and product_version
byte[] spare_space1 = new byte[1]; // " "
byte[] dreamcast_media = new byte[6]; // "GD-ROM"
byte[] disc_no = new byte[1]; // Disc number
byte[] disc_no_separator = new byte[1]; // '/'
byte[] disc_total_nos = new byte[1]; // Total number of discs
byte[] spare_space2 = new byte[2]; // " "
byte[] region_codes = new byte[8]; // Region codes, space-filled
byte[] peripherals = new byte[4]; // Supported peripherals, bitwise
byte[] product_no = new byte[10]; // Product number
byte[] product_version = new byte[6]; // Product version
byte[] release_date = new byte[8]; // YYYYMMDD
byte[] spare_space3 = new byte[8]; // " "
byte[] boot_filename = new byte[12]; // Usually "1ST_READ.BIN" or "0WINCE.BIN "
byte[] producer = new byte[16]; // Game producer, space-filled
byte[] product_name = new byte[128]; // Game name, space-filled
// Reading all data
fileStream.Read(maker_id, 0, 16); // "SEGA ENTERPRISES"
fileStream.Read(dreamcast_crc, 0, 4); // CRC of product_no and product_version
fileStream.Read(spare_space1, 0, 1); // " "
fileStream.Read(dreamcast_media, 0, 6); // "GD-ROM"
fileStream.Read(disc_no, 0, 1); // Disc number
fileStream.Read(disc_no_separator, 0, 1); // '/'
fileStream.Read(disc_total_nos, 0, 1); // Total number of discs
fileStream.Read(spare_space2, 0, 2); // " "
fileStream.Read(region_codes, 0, 8); // Region codes, space-filled
fileStream.Read(peripherals, 0, 4); // Supported peripherals, bitwise
fileStream.Read(product_no, 0, 10); // Product number
fileStream.Read(product_version, 0, 6); // Product version
fileStream.Read(release_date, 0, 8); // YYYYMMDD
fileStream.Read(spare_space3, 0, 8); // " "
fileStream.Read(boot_filename, 0, 12); // Usually "1ST_READ.BIN" or "0WINCE.BIN "
fileStream.Read(producer, 0, 16); // Game producer, space-filled
fileStream.Read(product_name, 0, 128); // Game name, space-filled
// Decoding all data
DateTime ipbindate = new DateTime();
CultureInfo provider = CultureInfo.InvariantCulture;
ipbindate = DateTime.ParseExact(Encoding.ASCII.GetString(release_date), "yyyyMMdd", provider);
IPBinInformation.AppendFormat("Product name: {0}", Encoding.ASCII.GetString(product_name)).AppendLine();
IPBinInformation.AppendFormat("Product version: {0}", Encoding.ASCII.GetString(product_version)).AppendLine();
IPBinInformation.AppendFormat("Producer: {0}", Encoding.ASCII.GetString(producer)).AppendLine();
IPBinInformation.AppendFormat("Disc media: {0}", Encoding.ASCII.GetString(dreamcast_media)).AppendLine();
IPBinInformation.AppendFormat("Disc number {0} of {1}", Encoding.ASCII.GetString(disc_no), Encoding.ASCII.GetString(disc_total_nos)).AppendLine();
IPBinInformation.AppendFormat("Release date: {0}", ipbindate.ToString()).AppendLine();
switch (Encoding.ASCII.GetString(boot_filename))
{
case "1ST_READ.BIN":
IPBinInformation.AppendLine("Disc boots natively.");
break;
case "0WINCE.BIN ":
IPBinInformation.AppendLine("Disc boots using Windows CE.");
break;
default:
IPBinInformation.AppendFormat("Disc boots using unknown loader: {0}.", Encoding.ASCII.GetString(boot_filename)).AppendLine();
break;
}
IPBinInformation.AppendLine("Regions supported:");
foreach (byte region in region_codes)
{
switch ((char)region)
{
case 'J':
IPBinInformation.AppendLine("Japanese NTSC.");
break;
case 'U':
IPBinInformation.AppendLine("North America NTSC.");
break;
case 'E':
IPBinInformation.AppendLine("Europe PAL.");
break;
case ' ':
break;
default:
IPBinInformation.AppendFormat("Game supports unknown region {0}.", region.ToString()).AppendLine();
break;
}
}
int iPeripherals = BitConverter.ToInt32(peripherals, 0);
if((iPeripherals & 0x00000010) == 0x00000010)
IPBinInformation.AppendLine("Game uses Windows CE.");
IPBinInformation.AppendFormat("Peripherals:").AppendLine();
if ((iPeripherals & 0x00000100) == 0x00000100)
IPBinInformation.AppendLine("Game supports the VGA Box.");
if ((iPeripherals & 0x00001000) == 0x00001000)
IPBinInformation.AppendLine("Game supports other expansion.");
if ((iPeripherals & 0x00002000) == 0x00002000)
IPBinInformation.AppendLine("Game supports Puru Puru pack.");
if ((iPeripherals & 0x00004000) == 0x00004000)
IPBinInformation.AppendLine("Game supports Mike Device.");
if ((iPeripherals & 0x00008000) == 0x00008000)
IPBinInformation.AppendLine("Game supports Memory Card.");
if ((iPeripherals & 0x00010000) == 0x00010000)
IPBinInformation.AppendLine("Game requires A + B + Start buttons and D-Pad.");
if ((iPeripherals & 0x00020000) == 0x00020000)
IPBinInformation.AppendLine("Game requires C button.");
if ((iPeripherals & 0x00040000) == 0x00040000)
IPBinInformation.AppendLine("Game requires D button.");
if ((iPeripherals & 0x00080000) == 0x00080000)
IPBinInformation.AppendLine("Game requires X button.");
if ((iPeripherals & 0x00100000) == 0x00100000)
IPBinInformation.AppendLine("Game requires Y button.");
if ((iPeripherals & 0x00200000) == 0x00200000)
IPBinInformation.AppendLine("Game requires Z button.");
if ((iPeripherals & 0x00400000) == 0x00400000)
IPBinInformation.AppendLine("Game requires expanded direction buttons.");
if ((iPeripherals & 0x00800000) == 0x00800000)
IPBinInformation.AppendLine("Game requires analog R trigger.");
if ((iPeripherals & 0x01000000) == 0x01000000)
IPBinInformation.AppendLine("Game requires analog L trigger.");
if ((iPeripherals & 0x02000000) == 0x02000000)
IPBinInformation.AppendLine("Game requires analog horizontal controller.");
if ((iPeripherals & 0x04000000) == 0x04000000)
IPBinInformation.AppendLine("Game requires analog vertical controller.");
if ((iPeripherals & 0x08000000) == 0x08000000)
IPBinInformation.AppendLine("Game requires expanded analog horizontal controller.");
if ((iPeripherals & 0x10000000) == 0x10000000)
IPBinInformation.AppendLine("Game requires expanded analog vertical controller.");
if ((iPeripherals & 0x20000000) == 0x20000000)
IPBinInformation.AppendLine("Game supports Gun.");
if ((iPeripherals & 0x40000000) == 0x40000000)
IPBinInformation.AppendLine("Game supports Keyboard.");
if ((iPeripherals & 0x80000000) == 0x80000000)
IPBinInformation.AppendLine("Game supports Mouse.");
break;
}
}
#endregion
ISOMetadata.AppendFormat("ISO9660 file system").AppendLine();
if(Joliet)
ISOMetadata.AppendFormat("Joliet extensions present.").AppendLine();
if (RockRidge)
ISOMetadata.AppendFormat("Rock Ridge Interchange Protocol present.").AppendLine();
if (Bootable)
ISOMetadata.AppendFormat("Disc bootable following {0} specifications.", BootSpec).AppendLine();
if (SegaCD)
{
ISOMetadata.AppendLine("This is a SegaCD / MegaCD disc.");
ISOMetadata.AppendLine(IPBinInformation.ToString());
}
if (Saturn)
{
ISOMetadata.AppendLine("This is a Sega Saturn disc.");
ISOMetadata.AppendLine(IPBinInformation.ToString());
}
if (Dreamcast)
{
ISOMetadata.AppendLine("This is a Sega Dreamcast disc.");
ISOMetadata.AppendLine(IPBinInformation.ToString());
}
ISOMetadata.AppendLine("--------------------------------");
ISOMetadata.AppendLine("VOLUME DESCRIPTOR INFORMATION:");
ISOMetadata.AppendLine("--------------------------------");
ISOMetadata.AppendFormat("System identifier: {0}", decodedVD.SystemIdentifier).AppendLine();
ISOMetadata.AppendFormat("Volume identifier: {0}", decodedVD.VolumeIdentifier).AppendLine();
ISOMetadata.AppendFormat("Volume set identifier: {0}", decodedVD.VolumeSetIdentifier).AppendLine();
ISOMetadata.AppendFormat("Publisher identifier: {0}", decodedVD.PublisherIdentifier).AppendLine();
ISOMetadata.AppendFormat("Data preparer identifier: {0}", decodedVD.DataPreparerIdentifier).AppendLine();
ISOMetadata.AppendFormat("Application identifier: {0}", decodedVD.ApplicationIdentifier).AppendLine();
ISOMetadata.AppendFormat("Volume creation date: {0}", decodedVD.CreationTime.ToString()).AppendLine();
if (decodedVD.HasModificationTime)
ISOMetadata.AppendFormat("Volume modification date: {0}", decodedVD.ModificationTime.ToString()).AppendLine();
else
ISOMetadata.AppendFormat("Volume has not been modified.").AppendLine();
if (decodedVD.HasExpirationTime)
ISOMetadata.AppendFormat("Volume expiration date: {0}", decodedVD.ExpirationTime.ToString()).AppendLine();
else
ISOMetadata.AppendFormat("Volume does not expire.").AppendLine();
if (decodedVD.HasEffectiveTime)
ISOMetadata.AppendFormat("Volume effective date: {0}", decodedVD.EffectiveTime.ToString()).AppendLine();
else
ISOMetadata.AppendFormat("Volume has always been effective.").AppendLine();
if(Joliet)
{
ISOMetadata.AppendLine("---------------------------------------");
ISOMetadata.AppendLine("JOLIET VOLUME DESCRIPTOR INFORMATION:");
ISOMetadata.AppendLine("---------------------------------------");
ISOMetadata.AppendFormat("System identifier: {0}", decodedJolietVD.SystemIdentifier).AppendLine();
ISOMetadata.AppendFormat("Volume identifier: {0}", decodedJolietVD.VolumeIdentifier).AppendLine();
ISOMetadata.AppendFormat("Volume set identifier: {0}", decodedJolietVD.VolumeSetIdentifier).AppendLine();
ISOMetadata.AppendFormat("Publisher identifier: {0}", decodedJolietVD.PublisherIdentifier).AppendLine();
ISOMetadata.AppendFormat("Data preparer identifier: {0}", decodedJolietVD.DataPreparerIdentifier).AppendLine();
ISOMetadata.AppendFormat("Application identifier: {0}", decodedJolietVD.ApplicationIdentifier).AppendLine();
ISOMetadata.AppendFormat("Volume creation date: {0}", decodedJolietVD.CreationTime.ToString()).AppendLine();
if (decodedJolietVD.HasModificationTime)
ISOMetadata.AppendFormat("Volume modification date: {0}", decodedJolietVD.ModificationTime.ToString()).AppendLine();
else
ISOMetadata.AppendFormat("Volume has not been modified.").AppendLine();
if (decodedJolietVD.HasExpirationTime)
ISOMetadata.AppendFormat("Volume expiration date: {0}", decodedJolietVD.ExpirationTime.ToString()).AppendLine();
else
ISOMetadata.AppendFormat("Volume does not expire.").AppendLine();
if (decodedJolietVD.HasEffectiveTime)
ISOMetadata.AppendFormat("Volume effective date: {0}", decodedJolietVD.EffectiveTime.ToString()).AppendLine();
else
ISOMetadata.AppendFormat("Volume has always been effective.").AppendLine();
}
information = ISOMetadata.ToString();
}
private DecodedVolumeDescriptor DecodeJolietDescriptor(byte[] VDSysId, byte[] VDVolId, byte[] VDVolSetId, byte[] VDPubId, byte[] VDDataPrepId, byte[] VDAppId, byte[] VCTime, byte[] VMTime, byte[] VXTime, byte[] VETime)
{
DecodedVolumeDescriptor decodedVD = new DecodedVolumeDescriptor();
decodedVD.SystemIdentifier = Encoding.BigEndianUnicode.GetString(VDSysId);
decodedVD.VolumeIdentifier = Encoding.BigEndianUnicode.GetString(VDVolId);
decodedVD.VolumeSetIdentifier = Encoding.BigEndianUnicode.GetString(VDVolSetId);
decodedVD.PublisherIdentifier = Encoding.BigEndianUnicode.GetString(VDPubId);
decodedVD.DataPreparerIdentifier = Encoding.BigEndianUnicode.GetString(VDDataPrepId);
decodedVD.ApplicationIdentifier = Encoding.BigEndianUnicode.GetString(VDAppId);
if (VCTime[0] == '0' || VCTime[0] == 0x00)
decodedVD.CreationTime = DateTime.MinValue;
else
decodedVD.CreationTime = DateHandlers.ISO9660ToDateTime(VCTime);
if (VMTime[0] == '0' || VMTime[0] == 0x00)
{
decodedVD.HasModificationTime = false;
}
else
{
decodedVD.HasModificationTime = true;
decodedVD.ModificationTime = DateHandlers.ISO9660ToDateTime(VMTime);
}
if (VXTime[0] == '0' || VXTime[0] == 0x00)
{
decodedVD.HasExpirationTime = false;
}
else
{
decodedVD.HasExpirationTime = true;
decodedVD.ExpirationTime = DateHandlers.ISO9660ToDateTime(VXTime);
}
if (VETime[0] == '0' || VETime[0] == 0x00)
{
decodedVD.HasEffectiveTime = false;
}
else
{
decodedVD.HasEffectiveTime = true;
decodedVD.EffectiveTime = DateHandlers.ISO9660ToDateTime(VETime);
}
return decodedVD;
}
private DecodedVolumeDescriptor DecodeVolumeDescriptor(byte[] VDSysId, byte[] VDVolId, byte[] VDVolSetId, byte[] VDPubId, byte[] VDDataPrepId, byte[] VDAppId, byte[] VCTime, byte[] VMTime, byte[] VXTime, byte[] VETime)
{
DecodedVolumeDescriptor decodedVD = new DecodedVolumeDescriptor();
decodedVD.SystemIdentifier = Encoding.ASCII.GetString(VDSysId);
decodedVD.VolumeIdentifier = Encoding.ASCII.GetString(VDVolId);
decodedVD.VolumeSetIdentifier = Encoding.ASCII.GetString(VDVolSetId);
decodedVD.PublisherIdentifier = Encoding.ASCII.GetString(VDPubId);
decodedVD.DataPreparerIdentifier = Encoding.ASCII.GetString(VDDataPrepId);
decodedVD.ApplicationIdentifier = Encoding.ASCII.GetString(VDAppId);
if (VCTime[0] == '0' || VCTime[0] == 0x00)
decodedVD.CreationTime = DateTime.MinValue;
else
decodedVD.CreationTime = DateHandlers.ISO9660ToDateTime(VCTime);
if (VMTime[0] == '0' || VMTime[0] == 0x00)
{
decodedVD.HasModificationTime = false;
}
else
{
decodedVD.HasModificationTime = true;
decodedVD.ModificationTime = DateHandlers.ISO9660ToDateTime(VMTime);
}
if (VXTime[0] == '0' || VXTime[0] == 0x00)
{
decodedVD.HasExpirationTime = false;
}
else
{
decodedVD.HasExpirationTime = true;
decodedVD.ExpirationTime = DateHandlers.ISO9660ToDateTime(VXTime);
}
if (VETime[0] == '0' || VETime[0] == 0x00)
{
decodedVD.HasEffectiveTime = false;
}
else
{
decodedVD.HasEffectiveTime = true;
decodedVD.EffectiveTime = DateHandlers.ISO9660ToDateTime(VETime);
}
return decodedVD;
}
}
}