First commit to SVN

git-svn-id: svn://claunia.com/FileSystemIDandChk@1 17725271-3d32-4980-a8cb-9ff532f270ba
This commit is contained in:
2011-03-03 18:34:33 +00:00
commit beec65407a
17 changed files with 2762 additions and 0 deletions

24
FileSystemIDandChk.sln Normal file
View File

@@ -0,0 +1,24 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileSystemIDandChk", "FileSystemIDandChk\FileSystemIDandChk.csproj", "{7A4B05BE-73C9-4F34-87FE-E80CCF1F732D}"
EndProject
Project("{9344bdbb-3e7f-41fc-a0dd-8665d75ee146}") = "Packages", "Packages.mdproj", "{8996EF59-09B9-4920-A3DE-2F8EA2EBBCFF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7A4B05BE-73C9-4F34-87FE-E80CCF1F732D}.Debug|x86.ActiveCfg = Debug|x86
{7A4B05BE-73C9-4F34-87FE-E80CCF1F732D}.Debug|x86.Build.0 = Debug|x86
{7A4B05BE-73C9-4F34-87FE-E80CCF1F732D}.Release|x86.ActiveCfg = Release|x86
{7A4B05BE-73C9-4F34-87FE-E80CCF1F732D}.Release|x86.Build.0 = Release|x86
{8996EF59-09B9-4920-A3DE-2F8EA2EBBCFF}.Debug|x86.ActiveCfg = Debug|Any CPU
{8996EF59-09B9-4920-A3DE-2F8EA2EBBCFF}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = FileSystemIDandChk\FileSystemIDandChk.csproj
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,27 @@
using System.Reflection;
using System.Runtime.CompilerServices;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
[assembly: AssemblyTitle("FileSystemIDandChk")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("1.0.*")]
// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.
//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")]

View File

@@ -0,0 +1,24 @@
using System;
using System.Text;
namespace FileSystemIDandChk
{
public static class StringHandlers
{
public static string CToString (byte[] CString)
{
StringBuilder sb = new StringBuilder();
for(int i = 0; i<CString.Length; i++)
{
if(CString[i]==0)
break;
sb.Append(Encoding.ASCII.GetString(CString, i, 1));
}
return sb.ToString();
}
}
}

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>9.0.21022</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{7A4B05BE-73C9-4F34-87FE-E80CCF1F732D}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>FileSystemIDandChk</RootNamespace>
<AssemblyName>FileSystemIDandChk</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
<Externalconsole>true</Externalconsole>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<DebugType>none</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
<Externalconsole>true</Externalconsole>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="Main.cs" />
<Compile Include="AssemblyInfo.cs" />
<Compile Include="Plugins\AppleMFS.cs" />
<Compile Include="Swapping.cs" />
<Compile Include="Plugins\Plugin.cs" />
<Compile Include="Plugins.cs" />
<Compile Include="Plugins\ISO9660.cs" />
<Compile Include="Plugins\PCEngine.cs" />
<Compile Include="Plugins\Opera.cs" />
<Compile Include="Plugins\AppleHFS.cs" />
<Compile Include="Plugins\FAT.cs" />
<Compile Include="PartPlugins\PartPlugin.cs" />
<Compile Include="PartPlugins\AppleMap.cs" />
<Compile Include="CToString.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
<Folder Include="Plugins\" />
<Folder Include="PartPlugins\" />
</ItemGroup>
</Project>

230
FileSystemIDandChk/Main.cs Normal file
View File

@@ -0,0 +1,230 @@
using System;
using System.IO;
using System.Collections.Generic;
using FileSystemIDandChk.Plugins;
using FileSystemIDandChk.PartPlugins;
namespace FileSystemIDandChk
{
class MainClass
{
static PluginBase plugins;
public static bool chkPartitions;
public static bool chkFilesystems;
public static bool isDebug;
public static void Main (string[] args)
{
plugins = new PluginBase();
chkPartitions = true;
chkFilesystems = true;
isDebug = false;
Console.WriteLine ("Filesystem Identificator and Checker");
Console.WriteLine ("Copyright (C) Natalia Portillo, All Rights Reserved");
if(args.Length==0)
{
Usage();
}
else if(args.Length==1)
{
plugins.RegisterAllPlugins();
if(args[0]=="--formats")
{
Console.WriteLine("Supported filesystems:");
foreach(KeyValuePair<string, Plugin> kvp in plugins.PluginsList)
Console.WriteLine(kvp.Value.Name);
Console.WriteLine();
Console.WriteLine("Supported partitions:");
foreach(KeyValuePair<string, PartPlugin> kvp in plugins.PartPluginsList)
Console.WriteLine(kvp.Value.Name);
}
else
Runner(args[0]);
}
else
{
for(int i = 0; i<args.Length-1; i++)
{
switch(args[i])
{
case "--filesystems":
chkFilesystems = true;
chkPartitions = false;
break;
case "--partitions":
chkFilesystems = false;
chkPartitions = true;
break;
case "--all":
chkFilesystems = true;
chkPartitions = true;
break;
case "--debug":
isDebug = true;
break;
default:
break;
}
}
Runner(args[args.Length-1]);
}
}
private static void Runner (string filename)
{
FileStream stream;
List<string> id_plugins;
Plugin _plugin;
string information;
bool checkraw = false;
try
{
stream = File.OpenRead(filename);
if(chkPartitions)
{
List<Partition> partitions = new List<Partition>();
string partition_scheme = "";
foreach (PartPlugin _partplugin in plugins.PartPluginsList.Values)
{
List<Partition> _partitions;
if (_partplugin.GetInformation(stream, out _partitions))
{
partition_scheme=_partplugin.Name;
partitions = _partitions;
break;
}
}
if(partition_scheme=="")
{
if(!chkFilesystems)
{
Console.WriteLine("No partitions founds, not searching for filesystems");
return;
}
else
checkraw = true;
}
else
{
Console.WriteLine("Partition scheme identified as {0}", partition_scheme);
Console.WriteLine("{0} partitions found.", partitions.Count);
for(int i = 0; i< partitions.Count; i++)
{
Console.WriteLine();
Console.WriteLine("Partition {0}:", partitions[i].PartitionSequence);
Console.WriteLine("Partition name: {0}", partitions[i].PartitionName);
Console.WriteLine("Partition type: {0}", partitions[i].PartitionType);
Console.WriteLine("Partition start: {0}", partitions[i].PartitionStart);
Console.WriteLine("Partition length: {0}", partitions[i].PartitionLength);
Console.WriteLine("Partition description:");
Console.WriteLine(partitions[i].PartitionDescription);
if(chkFilesystems)
{
Console.WriteLine("Identifying filesystem on partition");
Identify(stream, out id_plugins, partitions[i].PartitionStart);
if(id_plugins.Count==0)
Console.WriteLine("Filesystem not identified");
else if(id_plugins.Count>1)
{
Console.WriteLine(String.Format("Identified by {0} plugins", id_plugins.Count));
foreach(string plugin_name in id_plugins)
{
if(plugins.PluginsList.TryGetValue(plugin_name, out _plugin))
{
Console.WriteLine(String.Format("As identified by {0}.", _plugin.Name));
_plugin.GetInformation(stream, partitions[i].PartitionStart, out information);
Console.Write(information);
}
}
}
else
{
plugins.PluginsList.TryGetValue(id_plugins[0], out _plugin);
Console.WriteLine(String.Format("Identified by {0}.", _plugin.Name));
_plugin.GetInformation(stream, partitions[i].PartitionStart, out information);
Console.Write(information);
}
}
}
}
}
if(checkraw)
{
Identify(stream, out id_plugins, 0);
if(id_plugins.Count==0)
Console.WriteLine("Filesystem not identified");
else if(id_plugins.Count>1)
{
Console.WriteLine(String.Format("Identified by {0} plugins", id_plugins.Count));
foreach(string plugin_name in id_plugins)
{
if(plugins.PluginsList.TryGetValue(plugin_name, out _plugin))
{
Console.WriteLine(String.Format("As identified by {0}.", _plugin.Name));
_plugin.GetInformation(stream, 0, out information);
Console.Write(information);
}
}
}
else
{
plugins.PluginsList.TryGetValue(id_plugins[0], out _plugin);
Console.WriteLine(String.Format("Identified by {0}.", _plugin.Name));
_plugin.GetInformation(stream, 0, out information);
Console.Write(information);
}
}
}
catch(Exception ex)
{
Console.WriteLine(String.Format("Error reading file: {0}", ex.Message));
if(isDebug)
Console.WriteLine(ex.StackTrace);
}
finally
{
stream.Close();
}
}
private static void Identify (FileStream stream, out List<string> id_plugins, long offset)
{
id_plugins = new List<string>();
foreach (Plugin _plugin in plugins.PluginsList.Values)
{
if (_plugin.Identify(stream, offset))
id_plugins.Add(_plugin.Name.ToLower());
}
}
private static void Usage ()
{
Console.WriteLine("Usage: filesystemidandchk [options] file");
Console.WriteLine();
Console.WriteLine(" --formats List all suported partition and filesystems");
Console.WriteLine(" --debug Show debug information");
Console.WriteLine(" --partitions Check only for partitions");
Console.WriteLine(" --filesystems Check only for filesystems");
Console.WriteLine(" --all Check for partitions and filesystems (default)");
Console.WriteLine();
}
}
}

View File

@@ -0,0 +1,202 @@
using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using FileSystemIDandChk;
namespace FileSystemIDandChk.PartPlugins
{
class AppleMap : PartPlugin
{
public AppleMap (PluginBase Core)
{
base.Name = "Apple Partition Map";
base.PluginUUID = new Guid("ffe4b4e9-82ed-4761-af49-8bade4081d10");
}
public override bool GetInformation (FileStream stream, out List<Partition> partitions)
{
byte[] sixteen_bits = new byte[2];
byte[] thirtytwo_bits = new byte[4];
byte[] sixteen_bytes = new byte[16];
byte[] thirtytwo_bytes = new byte[32];
ulong apm_entries;
partitions = new List<Partition>();
AppleMapBootEntry APMB = new AppleMapBootEntry();
AppleMapPartitionEntry APMEntry = new AppleMapPartitionEntry();
stream.Seek(0, SeekOrigin.Begin);
stream.Read(sixteen_bits, 0, 2);
sixteen_bits = Swapping.SwapTwoBytes(sixteen_bits);
APMB.signature = BitConverter.ToUInt16(sixteen_bits, 0);
if(APMB.signature != 0x4552)
return false; // Not an Apple Partition Map
stream.Read(sixteen_bits, 0, 2);
sixteen_bits = Swapping.SwapTwoBytes(sixteen_bits);
APMB.sector_size = BitConverter.ToUInt16(sixteen_bits, 0);
stream.Seek(APMB.sector_size, SeekOrigin.Begin); // Seek to first entry
stream.Read(sixteen_bits, 0, 2);
sixteen_bits = Swapping.SwapTwoBytes(sixteen_bits);
APMEntry.signature = BitConverter.ToUInt16(sixteen_bits, 0);
if(APMEntry.signature != 0x504D && APMEntry.signature != 0x5453) // It should have partition entry signature
return false;
stream.Seek(2, SeekOrigin.Current); // Skip reserved1
stream.Read(thirtytwo_bits, 0, 4);
thirtytwo_bits = Swapping.SwapFourBytes(thirtytwo_bits);
APMEntry.entries = BitConverter.ToUInt32(thirtytwo_bits, 0);
if(APMEntry.entries <= 1) // It should have more than one entry
return false;
stream.Seek(4, SeekOrigin.Current); // Skip start, we don't need it
stream.Seek(4, SeekOrigin.Current); // Skip sectors, we don't need it
stream.Seek(32, SeekOrigin.Current); // Skip name, we don't ned it
stream.Read(thirtytwo_bytes, 0, 32);
APMEntry.type = StringHandlers.CToString(thirtytwo_bytes);
if(APMEntry.type != "Apple_partition_map") // APM self-describes, if not, this is incorrect
return false;
apm_entries = APMEntry.entries;
for(ulong i = 2; i <= apm_entries; i++) // For each partition
{
APMEntry = new AppleMapPartitionEntry();
stream.Seek((long)(APMB.sector_size*i), SeekOrigin.Begin); // Seek to partition descriptor
stream.Read(sixteen_bits, 0, 2);
sixteen_bits = Swapping.SwapTwoBytes(sixteen_bits);
APMEntry.signature = BitConverter.ToUInt16(sixteen_bits, 0);
if(APMEntry.signature == 0x504D || APMEntry.signature == 0x5453) // It should have partition entry signature
{
Partition _partition = new Partition();
StringBuilder sb = new StringBuilder();
stream.Seek(2, SeekOrigin.Current); // Skip reserved1
stream.Seek(4, SeekOrigin.Current); // Skip entries
stream.Read(thirtytwo_bits, 0, 4);
thirtytwo_bits = Swapping.SwapFourBytes(thirtytwo_bits);
APMEntry.start = BitConverter.ToUInt32(thirtytwo_bits, 0);
stream.Read(thirtytwo_bits, 0, 4);
thirtytwo_bits = Swapping.SwapFourBytes(thirtytwo_bits);
APMEntry.sectors = BitConverter.ToUInt32(thirtytwo_bits, 0);
stream.Read(thirtytwo_bytes, 0, 32);
APMEntry.name = StringHandlers.CToString(thirtytwo_bytes);
stream.Read(thirtytwo_bytes, 0, 32);
APMEntry.type = StringHandlers.CToString(thirtytwo_bytes);
stream.Read(thirtytwo_bits, 0, 4);
thirtytwo_bits = Swapping.SwapFourBytes(thirtytwo_bits);
APMEntry.first_data_block = BitConverter.ToUInt32(thirtytwo_bits, 0);
stream.Read(thirtytwo_bits, 0, 4);
thirtytwo_bits = Swapping.SwapFourBytes(thirtytwo_bits);
APMEntry.data_sectors = BitConverter.ToUInt32(thirtytwo_bits, 0);
stream.Read(thirtytwo_bits, 0, 4);
thirtytwo_bits = Swapping.SwapFourBytes(thirtytwo_bits);
APMEntry.status = BitConverter.ToUInt32(thirtytwo_bits, 0);
stream.Read(thirtytwo_bits, 0, 4);
thirtytwo_bits = Swapping.SwapFourBytes(thirtytwo_bits);
APMEntry.first_boot_block = BitConverter.ToUInt32(thirtytwo_bits, 0);
stream.Read(thirtytwo_bits, 0, 4);
thirtytwo_bits = Swapping.SwapFourBytes(thirtytwo_bits);
APMEntry.boot_size = BitConverter.ToUInt32(thirtytwo_bits, 0);
stream.Read(thirtytwo_bits, 0, 4);
thirtytwo_bits = Swapping.SwapFourBytes(thirtytwo_bits);
APMEntry.load_address = BitConverter.ToUInt32(thirtytwo_bits, 0);
stream.Seek(4, SeekOrigin.Current);
stream.Read(thirtytwo_bits, 0, 4);
thirtytwo_bits = Swapping.SwapFourBytes(thirtytwo_bits);
APMEntry.entry_point = BitConverter.ToUInt32(thirtytwo_bits, 0);
stream.Seek(4, SeekOrigin.Current);
stream.Read(thirtytwo_bits, 0, 4);
thirtytwo_bits = Swapping.SwapFourBytes(thirtytwo_bits);
APMEntry.checksum = BitConverter.ToUInt32(thirtytwo_bits, 0);
stream.Read(sixteen_bytes, 0, 16);
APMEntry.processor = StringHandlers.CToString(sixteen_bytes);
_partition.PartitionSequence = i;
_partition.PartitionType = APMEntry.type;
_partition.PartitionName = APMEntry.name;
_partition.PartitionStart = APMEntry.start * APMB.sector_size;
_partition.PartitionLength = APMEntry.sectors * APMB.sector_size;
sb.AppendLine("Partition flags:");
if((APMEntry.status & 0x01) == 0x01)
sb.AppendLine("Partition is valid.");
if((APMEntry.status & 0x02) == 0x02)
sb.AppendLine("Partition entry is not available.");
if((APMEntry.status & 0x04) == 0x04)
sb.AppendLine("Partition is mounted.");
if((APMEntry.status & 0x08) == 0x08)
sb.AppendLine("Partition is bootable.");
if((APMEntry.status & 0x10) == 0x10)
sb.AppendLine("Partition is readable.");
if((APMEntry.status & 0x20) == 0x20)
sb.AppendLine("Partition is writable.");
if((APMEntry.status & 0x40) == 0x40)
sb.AppendLine("Partition's boot code is position independent.");
if((APMEntry.status & 0x08) == 0x08)
{
sb.AppendFormat("First boot sector: {0}", APMEntry.first_boot_block).AppendLine();
sb.AppendFormat("Boot is {0} bytes.", APMEntry.boot_size).AppendLine();
sb.AppendFormat("Boot load address: 0x{0:X8}", APMEntry.load_address).AppendLine();
sb.AppendFormat("Boot entry point: 0x{0:X8}", APMEntry.entry_point).AppendLine();
sb.AppendFormat("Boot code checksum: 0x{0:X8}", APMEntry.checksum).AppendLine();
sb.AppendFormat("Processor: {0}", APMEntry.processor).AppendLine();
}
_partition.PartitionDescription = sb.ToString();
if((APMEntry.status & 0x01) == 0x01)
partitions.Add(_partition);
}
}
return true;
}
public struct AppleMapBootEntry
{
public UInt16 signature; // Signature ("ER")
public UInt16 sector_size; // Byter per sector
public UInt32 sectors; // Sectors of the disk
public UInt16 reserved1; // Reserved
public UInt16 reserved2; // Reserved
public UInt32 reserved3; // Reserved
public UInt16 driver_entries; // Number of entries of the driver descriptor
public UInt32 first_driver_blk; // First sector of the driver
public UInt16 driver_size; // Size in 512bytes sectors of the driver
public UInt16 operating_system; // Operating system (MacOS = 1)
}
public struct AppleMapPartitionEntry
{
public UInt16 signature; // Signature ("PM" or "TS")
public UInt16 reserved1; // Reserved
public UInt32 entries; // Number of entries on the partition map, each one sector
public UInt32 start; // First sector of the partition
public UInt32 sectors; // Number of sectos of the partition
public string name; // Partition name, 32 bytes, null-padded
public string type; // Partition type. 32 bytes, null-padded
public UInt32 first_data_block; // First sector of the data area
public UInt32 data_sectors; // Number of sectors of the data area
public UInt32 status; // Partition status
public UInt32 first_boot_block; // First sector of the boot code
public UInt32 boot_size; // Size in bytes of the boot code
public UInt32 load_address; // Load address of the boot code
public UInt32 reserved2; // Reserved
public UInt32 entry_point; // Entry point of the boot code
public UInt32 reserved3; // Reserved
public UInt32 checksum; // Boot code checksum
public string processor; // Processor type, 16 bytes, null-padded
}
}
}

View File

@@ -0,0 +1,28 @@
using System;
using System.IO;
using System.Collections.Generic;
namespace FileSystemIDandChk.PartPlugins
{
public abstract class PartPlugin
{
public string Name;
public Guid PluginUUID;
protected PartPlugin ()
{
}
public abstract bool GetInformation(FileStream stream, out List<Partition> partitions);
}
public struct Partition
{
public ulong PartitionSequence; // Partition number, 0-started
public string PartitionType; // Partition type
public string PartitionName; // Partition name (if the scheme supports it)
public long PartitionStart; // Start of the partition, in bytes
public long PartitionLength; // Length in bytes of the partition
public string PartitionDescription; // Information that does not find space in this struct
}
}

View File

@@ -0,0 +1,64 @@
using System;
using System.Reflection;
using System.Collections.Generic;
using FileSystemIDandChk.Plugins;
using FileSystemIDandChk.PartPlugins;
namespace FileSystemIDandChk
{
public class PluginBase
{
public Dictionary<string, Plugin> PluginsList;
public Dictionary<string, PartPlugin> PartPluginsList;
public PluginBase ()
{
this.PluginsList = new Dictionary<string, Plugin>();
this.PartPluginsList = new Dictionary<string, PartPlugin>();
}
public void RegisterAllPlugins()
{
Assembly assembly = Assembly.GetExecutingAssembly();
foreach (Type type in assembly.GetTypes())
{
try
{
if (type.IsSubclassOf(typeof(Plugin)))
{
Plugin plugin = (Plugin)type.GetConstructor(new Type[] { typeof(PluginBase) }).Invoke(new object[] { this });
this.RegisterPlugin(plugin);
}
else if (type.IsSubclassOf(typeof(PartPlugin)))
{
PartPlugin partplugin = (PartPlugin)type.GetConstructor(new Type[] { typeof(PluginBase) }).Invoke(new object[] { this });
this.RegisterPartPlugin(partplugin);
}
}
catch (Exception exception)
{
Console.WriteLine(exception.ToString());
}
}
}
private void RegisterPlugin(Plugin plugin)
{
if (!this.PluginsList.ContainsKey(plugin.Name.ToLower()))
{
this.PluginsList.Add(plugin.Name.ToLower(), plugin);
}
}
private void RegisterPartPlugin(PartPlugin partplugin)
{
if (!this.PartPluginsList.ContainsKey(partplugin.Name.ToLower()))
{
this.PartPluginsList.Add(partplugin.Name.ToLower(), partplugin);
}
}
}
}

View File

@@ -0,0 +1,401 @@
using System;
using System.IO;
using System.Text;
using FileSystemIDandChk;
// Information from Inside Macintosh
namespace FileSystemIDandChk.Plugins
{
class AppleHFS : Plugin
{
private DateTime HFSDateDelta = new DateTime(1904, 01, 01, 00, 00, 00);
public AppleHFS(PluginBase Core)
{
base.Name = "Apple Hierarchical File System";
base.PluginUUID = new Guid("8f4ee9d5-6820-4d7a-ae6b-3a4a49e7a88f");
}
public override bool Identify(FileStream stream, long offset)
{
byte[] signature = new byte[2];
ushort drSigWord;
stream.Seek(0x400 + offset, SeekOrigin.Begin);
stream.Read(signature, 0, 2);
signature = Swapping.SwapTwoBytes(signature);
drSigWord = BitConverter.ToUInt16(signature, 0);
if(drSigWord == 0x4244)
return true;
else
return false;
}
public override void GetInformation (FileStream stream, long offset, out string information)
{
information = "";
StringBuilder sb = new StringBuilder();
HFS_MasterDirectoryBlock MDB = new HFS_MasterDirectoryBlock();
HFS_BootBlock BB = new HFS_BootBlock();
byte[] sixteen_bit = new byte[2];
byte[] thirtytwo_bit = new byte[4];
byte[] fifthteen_bytes = new byte[15];
stream.Seek(0x400 + offset, SeekOrigin.Begin);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
MDB.drSigWord = BitConverter.ToUInt16(sixteen_bit, 0);
if(MDB.drSigWord != 0x4244)
return;
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
MDB.drCrDate = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
MDB.drLsMod = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
MDB.drAtrb = BitConverter.ToUInt16(sixteen_bit, 0);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
MDB.drNmFls = BitConverter.ToUInt16(sixteen_bit, 0);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
MDB.drVBMSt = BitConverter.ToUInt16(sixteen_bit, 0);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
MDB.drAllocPtr = BitConverter.ToUInt16(sixteen_bit, 0);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
MDB.drNmAlBlks = BitConverter.ToUInt16(sixteen_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
MDB.drAlBlkSiz = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
MDB.drClpSiz = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
MDB.drAlBlSt = BitConverter.ToUInt16(sixteen_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
MDB.drNxtCNID = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
MDB.drFreeBks = BitConverter.ToUInt16(sixteen_bit, 0);
MDB.drVN = new byte[28];
stream.Read(MDB.drVN, 0, 28);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
MDB.drVolBkUp = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
MDB.drVSeqNum = BitConverter.ToUInt16(sixteen_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
MDB.drWrCnt = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
MDB.drXTClpSiz = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
MDB.drCTClpSiz = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
MDB.drNmRtDirs = BitConverter.ToUInt16(sixteen_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
MDB.drFilCnt = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
MDB.drDirCnt = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
MDB.drFndrInfo0 = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
MDB.drFndrInfo1 = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
MDB.drFndrInfo2 = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
MDB.drFndrInfo3 = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
MDB.drFndrInfo4 = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
MDB.drFndrInfo5 = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
MDB.drFndrInfo6 = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
MDB.drFndrInfo7 = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
MDB.drEmbedSigWord = BitConverter.ToUInt16(sixteen_bit, 0);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
MDB.xdrStABNt = BitConverter.ToUInt16(sixteen_bit, 0);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
MDB.xdrNumABlks = BitConverter.ToUInt16(sixteen_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
MDB.drXTFlSize = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Seek(12, SeekOrigin.Current);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
MDB.drCTFlSize = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Seek(12, SeekOrigin.Current);
stream.Seek(0 + offset, SeekOrigin.Begin);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
BB.signature = BitConverter.ToUInt16(sixteen_bit, 0);
if(BB.signature == 0x4C4B)
{
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
BB.branch = BitConverter.ToUInt32(thirtytwo_bit, 0);
BB.boot_flags = (byte)stream.ReadByte();
BB.boot_version = (byte)stream.ReadByte();
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
BB.sec_sv_pages = BitConverter.ToInt16(sixteen_bit, 0);
stream.Seek(1, SeekOrigin.Current);
stream.Read(fifthteen_bytes, 0, 15);
BB.system_name = Encoding.ASCII.GetString(fifthteen_bytes);
stream.Seek(1, SeekOrigin.Current);
stream.Read(fifthteen_bytes, 0, 15);
BB.finder_name = Encoding.ASCII.GetString(fifthteen_bytes);
stream.Seek(1, SeekOrigin.Current);
stream.Read(fifthteen_bytes, 0, 15);
BB.debug_name = Encoding.ASCII.GetString(fifthteen_bytes);
stream.Seek(1, SeekOrigin.Current);
stream.Read(fifthteen_bytes, 0, 15);
BB.disasm_name = Encoding.ASCII.GetString(fifthteen_bytes);
stream.Seek(1, SeekOrigin.Current);
stream.Read(fifthteen_bytes, 0, 15);
BB.stupscr_name = Encoding.ASCII.GetString(fifthteen_bytes);
stream.Seek(1, SeekOrigin.Current);
stream.Read(fifthteen_bytes, 0, 15);
BB.bootup_name = Encoding.ASCII.GetString(fifthteen_bytes);
stream.Seek(1, SeekOrigin.Current);
stream.Read(fifthteen_bytes, 0, 15);
BB.clipbrd_name = Encoding.ASCII.GetString(fifthteen_bytes);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
BB.max_files = BitConverter.ToUInt16(sixteen_bit, 0);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
BB.queue_size = BitConverter.ToUInt16(sixteen_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
BB.heap_128k = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
BB.heap_256k = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
BB.heap_512k = BitConverter.ToUInt32(thirtytwo_bit, 0);
}
else
BB.signature = 0x0000;
sb.AppendLine("Apple Hierarchical File System");
sb.AppendLine();
sb.AppendLine("Master Directory Block:");
sb.AppendFormat("Creation date: {0}", HFSDateDelta.AddTicks((long)(MDB.drCrDate*10000000))).AppendLine();
sb.AppendFormat("Last modification date: {0}", HFSDateDelta.AddTicks((long)(MDB.drLsMod*10000000))).AppendLine();
sb.AppendFormat("Last backup date: {0}", HFSDateDelta.AddTicks((long)(MDB.drVolBkUp*10000000))).AppendLine();
sb.AppendFormat("Backup sequence number: {0}", MDB.drVSeqNum).AppendLine();
if((MDB.drAtrb & 0x80) == 0x80)
sb.AppendLine("Volume is locked by hardware.");
if((MDB.drAtrb & 0x100) == 0x100)
sb.AppendLine("Volume was unmonted.");
else
sb.AppendLine("Volume is mounted.");
if((MDB.drAtrb & 0x200) == 0x200)
sb.AppendLine("Volume has spared bad blocks.");
if((MDB.drAtrb & 0x400) == 0x400)
sb.AppendLine("Volume does not need cache.");
if((MDB.drAtrb & 0x800) == 0x800)
sb.AppendLine("Boot volume is inconsistent.");
if((MDB.drAtrb & 0x1000) == 0x1000)
sb.AppendLine("There are reused CNIDs.");
if((MDB.drAtrb & 0x2000) == 0x2000)
sb.AppendLine("Volume is journaled.");
if((MDB.drAtrb & 0x4000) == 0x4000)
sb.AppendLine("Volume is seriously inconsistent.");
if((MDB.drAtrb & 0x8000) == 0x8000)
sb.AppendLine("Volume is locked by software.");
sb.AppendFormat("{0} files on root directory", MDB.drNmFls).AppendLine();
sb.AppendFormat("{0} directories on root directory", MDB.drNmRtDirs).AppendLine();
sb.AppendFormat("{0} files on volume", MDB.drFilCnt).AppendLine();
sb.AppendFormat("{0} directories on volume", MDB.drDirCnt).AppendLine();
sb.AppendFormat("Volume write count: {0}", MDB.drWrCnt).AppendLine();
sb.AppendFormat("Volume bitmap starting sector (in 512-bytes): {0}", MDB.drVBMSt).AppendLine();
sb.AppendFormat("Next allocation block: {0}.", MDB.drAllocPtr).AppendLine();
sb.AppendFormat("{0} volume allocation blocks.", MDB.drNmAlBlks).AppendLine();
sb.AppendFormat("{0} bytes per allocation block.", MDB.drAlBlkSiz).AppendLine();
sb.AppendFormat("{0} bytes to allocate when extending a file.", MDB.drClpSiz).AppendLine();
sb.AppendFormat("{0} bytes to allocate when extending a Extents B-Tree.", MDB.drXTClpSiz).AppendLine();
sb.AppendFormat("{0} bytes to allocate when extending a Catalog B-Tree.", MDB.drCTClpSiz).AppendLine();
sb.AppendFormat("Sector of first allocation block: {0}", MDB.drAlBlSt).AppendLine();
sb.AppendFormat("Next unused CNID: {0}", MDB.drNxtCNID).AppendLine();
sb.AppendFormat("{0} unused allocation blocks.", MDB.drFreeBks).AppendLine();
sb.AppendFormat("{0} bytes in the Extents B-Tree", MDB.drXTFlSize).AppendLine();
sb.AppendFormat("{0} bytes in the Catalog B-Tree", MDB.drCTFlSize).AppendLine();
StringBuilder volumeName = new StringBuilder();
for(int i = 1; i < 28; i++)
{
if(MDB.drVN[i] == 0)
break;
volumeName.Append(Encoding.ASCII.GetString(MDB.drVN, i, 1));
}
sb.AppendFormat("Volume name: {0}", volumeName.ToString()).AppendLine();
sb.AppendLine("Finder info:");
sb.AppendFormat("CNID of bootable system's directory: {0}", MDB.drFndrInfo0).AppendLine();
sb.AppendFormat("CNID of first-run application's directory: {0}", MDB.drFndrInfo1).AppendLine();
sb.AppendFormat("CNID of previously opened directory: {0}", MDB.drFndrInfo2).AppendLine();
sb.AppendFormat("CNID of bootable Mac OS 8 or 9 directory: {0}", MDB.drFndrInfo3).AppendLine();
sb.AppendFormat("CNID of bootable Mac OS X directory: {0}", MDB.drFndrInfo5).AppendLine();
sb.AppendFormat("Mac OS X Volume ID: {0:X8}{1:X8}", MDB.drFndrInfo6, MDB.drFndrInfo7).AppendLine();
if(MDB.drEmbedSigWord == 0x482B)
{
sb.AppendLine("Volume wraps a HFS+ volume.");
sb.AppendFormat("Starting block of the HFS+ volume: {0}", MDB.xdrStABNt).AppendLine();
sb.AppendFormat("Allocations blocks of the HFS+ volume: {0}", MDB.xdrNumABlks).AppendLine();
}
if(BB.signature == 0x4C4B)
{
sb.AppendLine("Volume is bootable.");
sb.AppendLine();
sb.AppendLine("Boot Block:");
if((BB.boot_flags & 0x40) == 0x40)
sb.AppendLine("Boot block should be executed.");
if((BB.boot_flags & 0x80) == 0x80)
{
sb.AppendLine("Boot block is in new unknown format.");
}
else
{
if(BB.sec_sv_pages > 0)
sb.AppendLine("Allocate secondary sound buffer at boot.");
else if(BB.sec_sv_pages < 0)
sb.AppendLine("Allocate secondary sound and video buffers at boot.");
sb.AppendFormat("System filename: {0}", BB.system_name).AppendLine();
sb.AppendFormat("Finder filename: {0}", BB.finder_name).AppendLine();
sb.AppendFormat("Debugger filename: {0}", BB.debug_name).AppendLine();
sb.AppendFormat("Disassembler filename: {0}", BB.disasm_name).AppendLine();
sb.AppendFormat("Startup screen filename: {0}", BB.stupscr_name).AppendLine();
sb.AppendFormat("First program to execute at boot: {0}", BB.bootup_name).AppendLine();
sb.AppendFormat("Clipboard filename: {0}", BB.clipbrd_name).AppendLine();
sb.AppendFormat("Maximum opened files: {0}", BB.max_files*4).AppendLine();
sb.AppendFormat("Event queue size: {0}", BB.queue_size).AppendLine();
sb.AppendFormat("Heap size with 128KiB of RAM: {0} bytes", BB.heap_128k).AppendLine();
sb.AppendFormat("Heap size with 256KiB of RAM: {0} bytes", BB.heap_256k).AppendLine();
sb.AppendFormat("Heap size with 512KiB of RAM or more: {0} bytes", BB.heap_512k).AppendLine();
}
}
else
sb.AppendLine("Volume is not bootable.");
information = sb.ToString();
return;
}
private struct HFS_MasterDirectoryBlock // Should be offset 0x0400 bytes in volume
{
public UInt16 drSigWord; // Signature, 0x4244
public UInt32 drCrDate; // Volume creation date
public UInt32 drLsMod; // Volume last modification date
public UInt16 drAtrb; // Volume attributes
public UInt16 drNmFls; // Files in root directory
public UInt16 drVBMSt; // Start 512-byte sector of volume bitmap
public UInt16 drAllocPtr; // Allocation block to begin next allocation
public UInt16 drNmAlBlks; // Allocation blocks
public UInt32 drAlBlkSiz; // Bytes per allocation block
public UInt32 drClpSiz; // Bytes to allocate when extending a file
public UInt16 drAlBlSt; // Start 512-byte sector of first allocation block
public UInt32 drNxtCNID; // CNID for next file
public UInt16 drFreeBks; // Free allocation blocks
public byte[] drVN; // Volume name (28 bytes)
public UInt32 drVolBkUp; // Volume last backup time
public UInt16 drVSeqNum; // Volume backup sequence number
public UInt32 drWrCnt; // Filesystem write count
public UInt32 drXTClpSiz; // Bytes to allocate when extending the extents B-Tree
public UInt32 drCTClpSiz; // Bytes to allocate when extending the catalog B-Tree
public UInt16 drNmRtDirs; // Number of directories in root directory
public UInt32 drFilCnt; // Number of files in the volume
public UInt32 drDirCnt; // Number of directories in the volume
public UInt32 drFndrInfo0; // finderInfo[0], CNID for bootable system's directory
public UInt32 drFndrInfo1; // finderInfo[1], CNID of the directory containing the boot application
public UInt32 drFndrInfo2; // finderInfo[2], CNID of the directory that should be opened on boot
public UInt32 drFndrInfo3; // finderInfo[3], CNID for Mac OS 8 or 9 directory
public UInt32 drFndrInfo4; // finderInfo[4], Reserved
public UInt32 drFndrInfo5; // finderInfo[5], CNID for Mac OS X directory
public UInt32 drFndrInfo6; // finderInfo[6], first part of Mac OS X volume ID
public UInt32 drFndrInfo7; // finderInfo[7], second part of Mac OS X volume ID
public UInt16 drEmbedSigWord; // Embedded volume signature, "H+" if HFS+ is embedded ignore following two fields if not
public UInt16 xdrStABNt; // Starting block number of embedded HFS+ volume
public UInt16 xdrNumABlks; // Allocation blocks used by embedded volume
public UInt32 drXTFlSize; // Bytes in the extents B-Tree
// 3 HFS extents following, 32 bits each
public UInt32 drCTFlSize; // Bytes in the catalog B-Tree
// 3 HFS extents following, 32 bits each
}
private struct HFS_BootBlock // Should be offset 0x0000 bytes in volume
{
public UInt16 signature; // Signature, 0x4C4B if bootable
public UInt32 branch; // Branch
public byte boot_flags; // Boot block flags
public byte boot_version; // Boot block version
public Int16 sec_sv_pages; // Allocate secondary buffers
public string system_name; // System file name (10 bytes)
public string finder_name; // Finder file name (10 bytes)
public string debug_name; // Debugger file name (10 bytes)
public string disasm_name; // Disassembler file name (10 bytes)
public string stupscr_name; // Startup screen file name (10 bytes)
public string bootup_name; // First program to execute on boot (10 bytes)
public string clipbrd_name; // Clipboard file name (10 bytes)
public UInt16 max_files; // 1/4 of maximum opened at a time files
public UInt16 queue_size; // Event queue size
public UInt32 heap_128k; // Heap size on a Mac with 128KiB of RAM
public UInt32 heap_256k; // Heap size on a Mac with 256KiB of RAM
public UInt32 heap_512k; // Heap size on a Mac with 512KiB of RAM or more
} // Follows boot code
}
}

View File

@@ -0,0 +1,259 @@
using System;
using System.IO;
using System.Text;
using FileSystemIDandChk;
// Information from Inside Macintosh
namespace FileSystemIDandChk.Plugins
{
class AppleMFS : Plugin
{
private DateTime MFSDateDelta = new DateTime(1904, 01, 01, 00, 00, 00);
public AppleMFS(PluginBase Core)
{
base.Name = "Apple Macintosh File System";
base.PluginUUID = new Guid("67591456-90fa-49bd-ac89-14ef750b8af3");
}
public override bool Identify(FileStream stream, long offset)
{
byte[] signature = new byte[2];
ushort drSigWord;
stream.Seek(0x400 + offset, SeekOrigin.Begin);
stream.Read(signature, 0, 2);
signature = Swapping.SwapTwoBytes(signature);
drSigWord = BitConverter.ToUInt16(signature, 0);
if(drSigWord == 0xD2D7)
return true;
else
return false;
}
public override void GetInformation (FileStream stream, long offset, out string information)
{
information = "";
StringBuilder sb = new StringBuilder();
MFS_MasterDirectoryBlock MDB = new MFS_MasterDirectoryBlock();
MFS_BootBlock BB = new MFS_BootBlock();
byte[] sixteen_bit = new byte[2];
byte[] thirtytwo_bit = new byte[4];
byte[] fifthteen_bytes = new byte[15];
byte[] variable_size;
stream.Seek(0x400 + offset, SeekOrigin.Begin);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
MDB.drSigWord = BitConverter.ToUInt16(sixteen_bit, 0);
if(MDB.drSigWord != 0xD2D7)
return;
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
MDB.drCrDate = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
MDB.drLsBkUp = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
MDB.drAtrb = BitConverter.ToUInt16(sixteen_bit, 0);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
MDB.drNmFls = BitConverter.ToUInt16(sixteen_bit, 0);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
MDB.drDirSt = BitConverter.ToUInt16(sixteen_bit, 0);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
MDB.drBlLen = BitConverter.ToUInt16(sixteen_bit, 0);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
MDB.drNmAlBlks = BitConverter.ToUInt16(sixteen_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
MDB.drAlBlkSiz = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
MDB.drClpSiz = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
MDB.drAlBlSt = BitConverter.ToUInt16(sixteen_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
MDB.drNxtFNum = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
MDB.drFreeBks = BitConverter.ToUInt16(sixteen_bit, 0);
MDB.drVNSiz = (byte)stream.ReadByte();
variable_size = new byte[MDB.drVNSiz];
stream.Read(variable_size, 0, MDB.drVNSiz);
MDB.drVN = Encoding.ASCII.GetString(variable_size);
stream.Seek(0 + offset, SeekOrigin.Begin);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
BB.signature = BitConverter.ToUInt16(sixteen_bit, 0);
if(BB.signature == 0x4C4B)
{
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
BB.branch = BitConverter.ToUInt32(thirtytwo_bit, 0);
BB.boot_flags = (byte)stream.ReadByte();
BB.boot_version = (byte)stream.ReadByte();
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
BB.sec_sv_pages = BitConverter.ToInt16(sixteen_bit, 0);
stream.Seek(1, SeekOrigin.Current);
stream.Read(fifthteen_bytes, 0, 15);
BB.system_name = Encoding.ASCII.GetString(fifthteen_bytes);
stream.Seek(1, SeekOrigin.Current);
stream.Read(fifthteen_bytes, 0, 15);
BB.finder_name = Encoding.ASCII.GetString(fifthteen_bytes);
stream.Seek(1, SeekOrigin.Current);
stream.Read(fifthteen_bytes, 0, 15);
BB.debug_name = Encoding.ASCII.GetString(fifthteen_bytes);
stream.Seek(1, SeekOrigin.Current);
stream.Read(fifthteen_bytes, 0, 15);
BB.disasm_name = Encoding.ASCII.GetString(fifthteen_bytes);
stream.Seek(1, SeekOrigin.Current);
stream.Read(fifthteen_bytes, 0, 15);
BB.stupscr_name = Encoding.ASCII.GetString(fifthteen_bytes);
stream.Seek(1, SeekOrigin.Current);
stream.Read(fifthteen_bytes, 0, 15);
BB.bootup_name = Encoding.ASCII.GetString(fifthteen_bytes);
stream.Seek(1, SeekOrigin.Current);
stream.Read(fifthteen_bytes, 0, 15);
BB.clipbrd_name = Encoding.ASCII.GetString(fifthteen_bytes);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
BB.max_files = BitConverter.ToUInt16(sixteen_bit, 0);
stream.Read(sixteen_bit, 0, 2);
sixteen_bit = Swapping.SwapTwoBytes(sixteen_bit);
BB.queue_size = BitConverter.ToUInt16(sixteen_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
BB.heap_128k = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
BB.heap_256k = BitConverter.ToUInt32(thirtytwo_bit, 0);
stream.Read(thirtytwo_bit, 0, 4);
thirtytwo_bit = Swapping.SwapFourBytes(thirtytwo_bit);
BB.heap_512k = BitConverter.ToUInt32(thirtytwo_bit, 0);
}
else
BB.signature = 0x0000;
sb.AppendLine("Apple Macintosh File System");
sb.AppendLine();
sb.AppendLine("Master Directory Block:");
sb.AppendFormat("Creation date: {0}", MFSDateDelta.AddTicks((long)(MDB.drCrDate*10000000))).AppendLine();
sb.AppendFormat("Last backup date: {0}", MFSDateDelta.AddTicks((long)(MDB.drLsBkUp*10000000))).AppendLine();
if((MDB.drAtrb & 0x80) == 0x80)
sb.AppendLine("Volume is locked by hardware.");
if((MDB.drAtrb & 0x8000) == 0x8000)
sb.AppendLine("Volume is locked by software.");
sb.AppendFormat("{0} files on volume", MDB.drNmFls).AppendLine();
sb.AppendFormat("First directory block: {0}", MDB.drDirSt).AppendLine();
sb.AppendFormat("{0} blocks in directory.", MDB.drBlLen).AppendLine();
sb.AppendFormat("{0} volume allocation blocks.", MDB.drNmAlBlks).AppendLine();
sb.AppendFormat("Size of allocation blocks: {0}", MDB.drAlBlkSiz).AppendLine();
sb.AppendFormat("{0} bytes to allocate.", MDB.drClpSiz).AppendLine();
sb.AppendFormat("{0} first allocation block.", MDB.drAlBlSt).AppendLine();
sb.AppendFormat("Next unused file number: {0}", MDB.drNxtFNum).AppendLine();
sb.AppendFormat("{0} unused allocation blocks.", MDB.drFreeBks).AppendLine();
sb.AppendFormat("Volume name: {0}", MDB.drVN).AppendLine();
if(BB.signature == 0x4C4B)
{
sb.AppendLine("Volume is bootable.");
sb.AppendLine();
sb.AppendLine("Boot Block:");
if((BB.boot_flags & 0x40) == 0x40)
sb.AppendLine("Boot block should be executed.");
if((BB.boot_flags & 0x80) == 0x80)
{
sb.AppendLine("Boot block is in new unknown format.");
}
else
{
if(BB.sec_sv_pages > 0)
sb.AppendLine("Allocate secondary sound buffer at boot.");
else if(BB.sec_sv_pages < 0)
sb.AppendLine("Allocate secondary sound and video buffers at boot.");
sb.AppendFormat("System filename: {0}", BB.system_name).AppendLine();
sb.AppendFormat("Finder filename: {0}", BB.finder_name).AppendLine();
sb.AppendFormat("Debugger filename: {0}", BB.debug_name).AppendLine();
sb.AppendFormat("Disassembler filename: {0}", BB.disasm_name).AppendLine();
sb.AppendFormat("Startup screen filename: {0}", BB.stupscr_name).AppendLine();
sb.AppendFormat("First program to execute at boot: {0}", BB.bootup_name).AppendLine();
sb.AppendFormat("Clipboard filename: {0}", BB.clipbrd_name).AppendLine();
sb.AppendFormat("Maximum opened files: {0}", BB.max_files*4).AppendLine();
sb.AppendFormat("Event queue size: {0}", BB.queue_size).AppendLine();
sb.AppendFormat("Heap size with 128KiB of RAM: {0} bytes", BB.heap_128k).AppendLine();
sb.AppendFormat("Heap size with 256KiB of RAM: {0} bytes", BB.heap_256k).AppendLine();
sb.AppendFormat("Heap size with 512KiB of RAM or more: {0} bytes", BB.heap_512k).AppendLine();
}
}
else
sb.AppendLine("Volume is not bootable.");
information = sb.ToString();
return;
}
private struct MFS_MasterDirectoryBlock // Should be offset 0x0400 bytes in volume
{
public UInt16 drSigWord; // Signature, 0xD2D7
public UInt32 drCrDate; // Volume creation date
public UInt32 drLsBkUp; // Volume last backup date
public UInt16 drAtrb; // Volume attributes
public UInt16 drNmFls; // Volume number of files
public UInt16 drDirSt; // First directory block
public UInt16 drBlLen; // Length of directory in blocks
public UInt16 drNmAlBlks; // Volume allocation blocks
public UInt32 drAlBlkSiz; // Size of allocation blocks
public UInt32 drClpSiz; // Number of bytes to allocate
public UInt16 drAlBlSt; // First allocation block in block map
public UInt32 drNxtFNum; // Next unused file number
public UInt16 drFreeBks; // Number of unused allocation blocks
public byte drVNSiz; // Length of volume name
public string drVN; // Characters of volume name
}
private struct MFS_BootBlock // Should be offset 0x0000 bytes in volume
{
public UInt16 signature; // Signature, 0x4C4B if bootable
public UInt32 branch; // Branch
public byte boot_flags; // Boot block flags
public byte boot_version; // Boot block version
public short sec_sv_pages; // Allocate secondary buffers
public string system_name; // System file name (10 bytes)
public string finder_name; // Finder file name (10 bytes)
public string debug_name; // Debugger file name (10 bytes)
public string disasm_name; // Disassembler file name (10 bytes)
public string stupscr_name; // Startup screen file name (10 bytes)
public string bootup_name; // First program to execute on boot (10 bytes)
public string clipbrd_name; // Clipboard file name (10 bytes)
public UInt16 max_files; // 1/4 of maximum opened at a time files
public UInt16 queue_size; // Event queue size
public UInt32 heap_128k; // Heap size on a Mac with 128KiB of RAM
public UInt32 heap_256k; // Heap size on a Mac with 256KiB of RAM
public UInt32 heap_512k; // Heap size on a Mac with 512KiB of RAM or more
} // Follows boot code
}
}

View File

@@ -0,0 +1,263 @@
using System;
using System.IO;
using System.Text;
using FileSystemIDandChk;
// Information from Inside Macintosh
namespace FileSystemIDandChk.Plugins
{
class FAT : Plugin
{
public FAT(PluginBase Core)
{
base.Name = "Microsoft File Allocation Table";
base.PluginUUID = new Guid("67591456-90fa-49bd-ac89-14ef750b8af3");
}
public override bool Identify(FileStream stream, long offset)
{
byte media_descriptor; // Not present on DOS <= 3, present on TOS but != of first FAT entry
byte[] fat32_signature = new byte[8]; // "FAT32 "
byte[] first_fat_entry_b = new byte[4]; // No matter FAT size we read 2 bytes for checking
ulong first_fat_entry;
stream.Seek(0x15 + offset, SeekOrigin.Begin); // Media Descriptor if present is in 0x15
media_descriptor = (byte)stream.ReadByte();
stream.Seek(0x52 + offset, SeekOrigin.Begin); // FAT32 signature, if present, is in 0x52
stream.Read(fat32_signature, 0, 8);
stream.Seek(0x200 + offset, SeekOrigin.Begin); // First FAT entry is always at 0x200 in pre-FAT32
stream.Read(first_fat_entry_b, 0, 4);
first_fat_entry = BitConverter.ToUInt32(first_fat_entry_b, 0); // Easier to manage
// Let's start the fun
if(Encoding.ASCII.GetString(fat32_signature) == "FAT32 ")
return true; // Seems easy, check reading
if((first_fat_entry & 0xFFFFFFF0) == 0xFFFFFFF0) // Seems to be FAT16
{
if((first_fat_entry & 0xFF) == media_descriptor)
return true; // It MUST be FAT16, or... maybe not :S
}
else if((first_fat_entry & 0x00FFFFF0) == 0x00FFFFF0)
{
//if((first_fat_entry & 0xFF) == media_descriptor) // Pre DOS<4 does not implement this, TOS does and is !=
return true; // It MUST be FAT12, or... maybe not :S
}
return false;
}
public override void GetInformation (FileStream stream, long offset, out string information)
{
information = "";
StringBuilder sb = new StringBuilder();
byte media_descriptor; // Not present on DOS <= 3, present on TOS but != of first FAT entry
byte[] fat32_signature = new byte[8]; // "FAT32 "
byte[] first_fat_entry_b = new byte[4]; // No matter FAT size we read 2 bytes for checking
ulong first_fat_entry;
stream.Seek(0x15 + offset, SeekOrigin.Begin); // Media Descriptor if present is in 0x15
media_descriptor =(byte) stream.ReadByte();
stream.Seek(0x52 + offset, SeekOrigin.Begin); // FAT32 signature, if present, is in 0x52
stream.Read(fat32_signature, 0, 8);
stream.Seek(0x200 + offset, SeekOrigin.Begin); // First FAT entry is always at 0x200 in pre-FAT32
stream.Read(first_fat_entry_b, 0, 4);
first_fat_entry = BitConverter.ToUInt32(first_fat_entry_b, 0); // Easier to manage
// Let's start the fun
if(Encoding.ASCII.GetString(fat32_signature) == "FAT32 ")
sb.AppendLine("Microsoft FAT32"); // Seems easy, check reading
else if((first_fat_entry & 0xFFFFFFF0) == 0xFFFFFFF0) // Seems to be FAT16
{
if((first_fat_entry & 0xFF) == media_descriptor)
sb.AppendLine("Microsoft FAT16"); // It MUST be FAT16, or... maybe not :S
}
else if((first_fat_entry & 0x00FFFFF0) == 0x00FFFFF0)
{
//if((first_fat_entry & 0xFF) == media_descriptor) // Pre DOS<4 does not implement this, TOS does and is !=
sb.AppendLine("Microsoft FAT12"); // It MUST be FAT12, or... maybe not :S
}
else
return;
BIOSParameterBlock BPB = new BIOSParameterBlock();
ExtendedParameterBlock EPB = new ExtendedParameterBlock();
FAT32ParameterBlock FAT32PB = new FAT32ParameterBlock();
byte[] eight_bytes = new byte[8];
byte[] eleven_bytes = new byte[11];
byte[] sixteen_bits = new byte[2];
byte[] thirtytwo_bits = new byte[4];
stream.Seek(3 + offset, SeekOrigin.Begin);
stream.Read(eight_bytes, 0, 8);
BPB.OEMName = Encoding.ASCII.GetString(eight_bytes);
stream.Read(sixteen_bits, 0, 2);
BPB.bps = BitConverter.ToUInt16(sixteen_bits, 0);
BPB.spc = (byte)stream.ReadByte();
stream.Read(sixteen_bits, 0, 2);
BPB.rsectors = BitConverter.ToUInt16(sixteen_bits, 0);
BPB.fats_no = (byte)stream.ReadByte();
stream.Read(sixteen_bits, 0, 2);
BPB.root_ent = BitConverter.ToUInt16(sixteen_bits, 0);
stream.Read(sixteen_bits, 0, 2);
BPB.sectors = BitConverter.ToUInt16(sixteen_bits, 0);
BPB.media = (byte)stream.ReadByte();
stream.Read(sixteen_bits, 0, 2);
BPB.spfat = BitConverter.ToUInt16(sixteen_bits, 0);
stream.Read(sixteen_bits, 0, 2);
BPB.sptrk = BitConverter.ToUInt16(sixteen_bits, 0);
stream.Read(sixteen_bits, 0, 2);
BPB.heads = BitConverter.ToUInt16(sixteen_bits, 0);
stream.Read(thirtytwo_bits, 0, 4);
BPB.hsectors = BitConverter.ToUInt32(thirtytwo_bits, 0);
stream.Read(thirtytwo_bits, 0, 4);
BPB.big_sectors = BitConverter.ToUInt32(thirtytwo_bits, 0);
if(Encoding.ASCII.GetString(fat32_signature) == "FAT32 ")
{
stream.Read(thirtytwo_bits, 0, 4);
FAT32PB.spfat = BitConverter.ToUInt32(thirtytwo_bits, 0);
stream.Read(sixteen_bits, 0, 2);
FAT32PB.fat_flags = BitConverter.ToUInt16(sixteen_bits, 0);
stream.Read(sixteen_bits, 0, 2);
FAT32PB.version = BitConverter.ToUInt16(sixteen_bits, 0);
stream.Read(thirtytwo_bits, 0, 4);
FAT32PB.root_cluster = BitConverter.ToUInt32(thirtytwo_bits, 0);
stream.Read(sixteen_bits, 0, 2);
FAT32PB.fsinfo_sector = BitConverter.ToUInt16(sixteen_bits, 0);
stream.Read(sixteen_bits, 0, 2);
FAT32PB.backup_sector = BitConverter.ToUInt16(sixteen_bits, 0);
FAT32PB.drive_no = (byte)stream.ReadByte();
FAT32PB.nt_flags = (byte)stream.ReadByte();
FAT32PB.signature = (byte)stream.ReadByte();
stream.Read(thirtytwo_bits, 0, 4);
FAT32PB.serial_no = BitConverter.ToUInt32(thirtytwo_bits, 0);
stream.Read(eleven_bytes, 0, 11);
FAT32PB.volume_label = Encoding.ASCII.GetString(eleven_bytes);
stream.Read(eight_bytes, 0, 8);
FAT32PB.fs_type = Encoding.ASCII.GetString(eight_bytes);
}
else
{
EPB.drive_no = (byte)stream.ReadByte();
EPB.nt_flags = (byte)stream.ReadByte();
EPB.signature = (byte)stream.ReadByte();
stream.Read(thirtytwo_bits, 0, 4);
EPB.serial_no = BitConverter.ToUInt32(thirtytwo_bits, 0);
stream.Read(eleven_bytes, 0, 11);
EPB.volume_label = Encoding.ASCII.GetString(eleven_bytes);
stream.Read(eight_bytes, 0, 8);
EPB.fs_type = Encoding.ASCII.GetString(eight_bytes);
}
sb.AppendFormat("OEM Name: {0}", BPB.OEMName).AppendLine();
sb.AppendFormat("{0} bytes per sector.", BPB.bps).AppendLine();
sb.AppendFormat("{0} sectors per cluster.", BPB.spc).AppendLine();
sb.AppendFormat("{0} sectors reserved between BPB and FAT.", BPB.rsectors).AppendLine();
sb.AppendFormat("{0} FATs.", BPB.fats_no).AppendLine();
sb.AppendFormat("{0} entires on root directory.", BPB.root_ent).AppendLine();
if(BPB.sectors==0)
sb.AppendFormat("{0} sectors on volume.", BPB.big_sectors).AppendLine();
else
sb.AppendFormat("{0} sectors on volume.", BPB.sectors).AppendLine();
if((BPB.media & 0xF0) == 0xF0)
sb.AppendFormat("Media format: 0x{0:X2}", BPB.media).AppendLine();
if(Encoding.ASCII.GetString(fat32_signature) == "FAT32 ")
sb.AppendFormat("{0} sectors per FAT.", FAT32PB.spfat).AppendLine();
else
sb.AppendFormat("{0} sectors per FAT.", BPB.spfat).AppendLine();
sb.AppendFormat("{0} sectors per track.", BPB.sptrk).AppendLine();
sb.AppendFormat("{0} heads.", BPB.heads).AppendLine();
sb.AppendFormat("{0} hidden sectors before BPB.", BPB.hsectors).AppendLine();
if(Encoding.ASCII.GetString(fat32_signature) == "FAT32 ")
{
sb.AppendFormat("Cluster of root directory: {0}", FAT32PB.root_cluster).AppendLine();
sb.AppendFormat("Sector of FSINFO structure: {0}", FAT32PB.fsinfo_sector).AppendLine();
sb.AppendFormat("Sector of backup FAT32 parameter block: {0}", FAT32PB.backup_sector).AppendLine();
sb.AppendFormat("Drive number: 0x{0:X2}", FAT32PB.drive_no).AppendLine();
sb.AppendFormat("Volume Serial Number: 0x{0:X8}", FAT32PB.serial_no).AppendLine();
if((FAT32PB.nt_flags & 0x01) == 0x01)
{
sb.AppendLine("Volume should be checked on next mount.");
if((EPB.nt_flags & 0x02) == 0x02)
sb.AppendLine("Disk surface should be checked also.");
}
sb.AppendFormat("Volume label: {0}", EPB.volume_label).AppendLine();
sb.AppendFormat("Filesystem type: {0}", EPB.fs_type).AppendLine();
}
else if(EPB.signature == 0x28 || EPB.signature == 0x29)
{
sb.AppendFormat("Drive number: 0x{0:X2}", EPB.drive_no).AppendLine();
sb.AppendFormat("Volume Serial Number: 0x{0:X8}", EPB.serial_no).AppendLine();
if(EPB.signature==0x29)
{
if((EPB.nt_flags & 0x01) == 0x01)
{
sb.AppendLine("Volume should be checked on next mount.");
if((EPB.nt_flags & 0x02) == 0x02)
sb.AppendLine("Disk surface should be checked also.");
}
sb.AppendFormat("Volume label: {0}", EPB.volume_label).AppendLine();
sb.AppendFormat("Filesystem type: {0}", EPB.fs_type).AppendLine();
}
}
information = sb.ToString();
}
public struct BIOSParameterBlock
{
public string OEMName; // OEM Name, 8 bytes, space-padded
public UInt16 bps; // Bytes per sector
public byte spc; // Sectors per cluster
public UInt16 rsectors; // Reserved sectors between BPB and FAT
public byte fats_no; // Number of FATs
public UInt16 root_ent; // Number of entries on root directory
public UInt16 sectors; // Sectors in volume
public byte media; // Media descriptor
public UInt16 spfat; // Sectors per FAT
public UInt16 sptrk; // Sectors per track
public UInt16 heads; // Heads
public UInt32 hsectors; // Hidden sectors before BPB
public UInt32 big_sectors; // Sectors in volume if > 65535
}
public struct ExtendedParameterBlock
{
public byte drive_no; // Drive number
public byte nt_flags; // Volume flags if NT (must be 0x29 signature)
public byte signature; // EPB signature, 0x28 or 0x29
public UInt32 serial_no; // Volume serial number
/* Present only if signature == 0x29 */
public string volume_label; // Volume label, 11 bytes, space-padded
public string fs_type; // Filesystem type, 8 bytes, space-padded
}
public struct FAT32ParameterBlock
{
public UInt32 spfat; // Sectors per FAT
public UInt16 fat_flags; // FAT flags
public UInt16 version; // FAT32 version
public UInt32 root_cluster; // Cluster of root directory
public UInt16 fsinfo_sector; // Sector of FSINFO structure
public UInt16 backup_sector; // Secfor of FAT32PB bacup
byte[] reserved; // 12 reserved bytes
public byte drive_no; // Drive number
public byte nt_flags; // Volume flags
public byte signature; // FAT32PB signature, should be 0x29
public UInt32 serial_no; // Volume serial number
public string volume_label; // Volume label, 11 bytes, space-padded
public string fs_type; // Filesystem type, 8 bytes, space-padded, must be "FAT32 "
}
}
}

View File

@@ -0,0 +1,927 @@
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
{
public ISO9660Plugin(PluginBase Core)
{
base.Name = "ISO9660 Filesystem";
base.PluginUUID = new Guid("d812f4d3-c357-400d-90fd-3b22ef786aa8");
}
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)
{
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 + offset, SeekOrigin.Begin);
VDType = (byte)fileStream.ReadByte();
byte[] VDMagic = new byte[5];
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 + offset, 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) + offset, 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) + offset, 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) + offset, 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) + offset, SeekOrigin.Begin);
if (fileStream.Read(VDPathTableStart, 0, 4) != 4)
break; // Something bad happened
// Seek to next identifiers
fileStream.Seek(32958 + (2048 * counter) + offset, 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) + offset, 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) + offset, 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) + offset, 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) + offset, 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) + offset, 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();
if(!Joliet)
decodedVD = DecodeVolumeDescriptor(VDSysId, VDVolId, VDVolSetId, VDPubId, VDDataPrepId, VDAppId, VCTime, VMTime, VXTime, VETime);
else
decodedVD = DecodeJolietDescriptor(JolietSysId, JolietVolId, JolietVolSetId, JolietPubId, JolietDataPrepId, JolietAppId, JolietCTime, JolietMTime, JolietXTime, JolietETime);
int i = BitConverter.ToInt32(VDPathTableStart, 0);
fileStream.Seek((i * 2048)+2 + offset, 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 + offset, 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 + offset, 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();
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 = DecodeVDDateTime(VCTime);
if (VMTime[0] == '0' || VMTime[0] == 0x00)
{
decodedVD.HasModificationTime = false;
}
else
{
decodedVD.HasModificationTime = true;
decodedVD.ModificationTime = DecodeVDDateTime(VMTime);
}
if (VXTime[0] == '0' || VXTime[0] == 0x00)
{
decodedVD.HasExpirationTime = false;
}
else
{
decodedVD.HasExpirationTime = true;
decodedVD.ExpirationTime = DecodeVDDateTime(VXTime);
}
if (VETime[0] == '0' || VETime[0] == 0x00)
{
decodedVD.HasEffectiveTime = false;
}
else
{
decodedVD.HasEffectiveTime = true;
decodedVD.EffectiveTime = DecodeVDDateTime(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 = DecodeVDDateTime(VCTime);
if (VMTime[0] == '0' || VMTime[0] == 0x00)
{
decodedVD.HasModificationTime = false;
}
else
{
decodedVD.HasModificationTime = true;
decodedVD.ModificationTime = DecodeVDDateTime(VMTime);
}
if (VXTime[0] == '0' || VXTime[0] == 0x00)
{
decodedVD.HasExpirationTime = false;
}
else
{
decodedVD.HasExpirationTime = true;
decodedVD.ExpirationTime = DecodeVDDateTime(VXTime);
}
if (VETime[0] == '0' || VETime[0] == 0x00)
{
decodedVD.HasEffectiveTime = false;
}
else
{
decodedVD.HasEffectiveTime = true;
decodedVD.EffectiveTime = DecodeVDDateTime(VETime);
}
return decodedVD;
}
private DateTime DecodeVDDateTime(byte[] VDDateTime)
{
int year, month, day, hour, minute, second, hundredths;
byte[] twocharvalue = new byte[2];
byte[] fourcharvalue = new byte[4];
fourcharvalue[0] = VDDateTime[0];
fourcharvalue[1] = VDDateTime[1];
fourcharvalue[2] = VDDateTime[2];
fourcharvalue[3] = VDDateTime[3];
year = Convert.ToInt32(Encoding.ASCII.GetString(fourcharvalue));
twocharvalue[0] = VDDateTime[4];
twocharvalue[1] = VDDateTime[5];
month = Convert.ToInt32(Encoding.ASCII.GetString(twocharvalue));
twocharvalue[0] = VDDateTime[6];
twocharvalue[1] = VDDateTime[7];
day = Convert.ToInt32(Encoding.ASCII.GetString(twocharvalue));
twocharvalue[0] = VDDateTime[8];
twocharvalue[1] = VDDateTime[9];
hour = Convert.ToInt32(Encoding.ASCII.GetString(twocharvalue));
twocharvalue[0] = VDDateTime[10];
twocharvalue[1] = VDDateTime[11];
minute = Convert.ToInt32(Encoding.ASCII.GetString(twocharvalue));
twocharvalue[0] = VDDateTime[12];
twocharvalue[1] = VDDateTime[13];
second = Convert.ToInt32(Encoding.ASCII.GetString(twocharvalue));
twocharvalue[0] = VDDateTime[14];
twocharvalue[1] = VDDateTime[15];
hundredths = Convert.ToInt32(Encoding.ASCII.GetString(twocharvalue));
DateTime decodedDT = new DateTime(year, month, day, hour, minute, second, hundredths * 10, DateTimeKind.Unspecified);
return decodedDT;
}
}
}

View File

@@ -0,0 +1,134 @@
using System;
using System.IO;
using System.Text;
using FileSystemIDandChk;
// Information from Inside Macintosh
namespace FileSystemIDandChk.Plugins
{
class OperaFS : Plugin
{
public OperaFS(PluginBase Core)
{
base.Name = "Opera Filesystem Plugin";
base.PluginUUID = new Guid("0ec84ec7-eae6-4196-83fe-943b3fe46dbd");
}
public override bool Identify(FileStream fileStream, long offset)
{
fileStream.Seek(0 + offset, SeekOrigin.Begin);
byte record_type;
byte[] sync_bytes = new byte[5];
byte record_version;
record_type = (byte)fileStream.ReadByte();
fileStream.Read(sync_bytes, 0, 5);
record_version = (byte)fileStream.ReadByte();
if (record_type != 1 || record_version != 1)
return false;
if(Encoding.ASCII.GetString(sync_bytes) != "ZZZZZ")
return false;
return true;
}
public override void GetInformation (FileStream fileStream, long offset, out string information)
{
information = "";
StringBuilder SuperBlockMetadata = new StringBuilder();
fileStream.Seek(0 + offset, SeekOrigin.Begin);
byte[] record_type = new byte[1];
byte[] sync_bytes = new byte[5];
byte[] record_version = new byte[1];
byte[] volume_flags = new byte[1];
byte[] volume_comment = new byte[32];
byte[] volume_label = new byte[32];
byte[] volume_id = new byte[4];
byte[] block_size = new byte[4];
byte[] block_count = new byte[4];
byte[] root_dirid = new byte[4];
byte[] rootdir_blocks = new byte[4];
byte[] rootdir_bsize = new byte[4];
byte[] last_root_copy = new byte[4];
fileStream.Read(record_type, 0, 1);
fileStream.Read(sync_bytes, 0, 5);
fileStream.Read(record_version, 0, 1);
fileStream.Read(volume_flags, 0, 1);
fileStream.Read(volume_comment, 0, 32);
fileStream.Read(volume_label, 0, 32);
fileStream.Read(volume_id, 0, 4);
fileStream.Read(block_size, 0, 4);
fileStream.Read(block_count, 0, 4);
fileStream.Read(root_dirid, 0, 4);
fileStream.Read(rootdir_blocks, 0, 4);
fileStream.Read(rootdir_bsize, 0, 4);
fileStream.Read(last_root_copy, 0, 4);
if (record_type[0] != 1 || record_version[0] != 1)
return;
if(Encoding.ASCII.GetString(sync_bytes) != "ZZZZZ")
return;
// Swapping data (C# is LE, Opera is BE)
volume_id = Swapping.SwapFourBytes(volume_id);
block_size = Swapping.SwapFourBytes(block_size);
block_count = Swapping.SwapFourBytes(block_count);
root_dirid = Swapping.SwapFourBytes(root_dirid);
rootdir_blocks = Swapping.SwapFourBytes(rootdir_blocks);
rootdir_bsize = Swapping.SwapFourBytes(rootdir_bsize);
last_root_copy = Swapping.SwapFourBytes(last_root_copy);
int vid = BitConverter.ToInt32(volume_id, 0);
int rdid = BitConverter.ToInt32(root_dirid, 0);
StringBuilder VolumeComment = new StringBuilder();
for (int i = 0; i < volume_comment.Length; i++)
{
if (volume_comment[i] != 0x00)
VolumeComment.Append((char)volume_comment[i]);
else
break;
}
if (VolumeComment.Length == 0)
VolumeComment.Append("Not set.");
StringBuilder VolumeLabel = new StringBuilder();
for (int i = 0; i < volume_label.Length; i++)
{
if (volume_label[i] != 0x00)
VolumeLabel.Append((char)volume_label[i]);
else
break;
}
if (VolumeLabel.Length == 0)
VolumeLabel.Append("Not set.");
int bs = BitConverter.ToInt32(block_size, 0);
int vblocks = BitConverter.ToInt32(block_count, 0);
int rbs = BitConverter.ToInt32(rootdir_bsize, 0);
int rblocks = BitConverter.ToInt32(rootdir_blocks, 0);
SuperBlockMetadata.AppendFormat("Opera filesystem disc.").AppendLine();
SuperBlockMetadata.AppendFormat("Volume label: {0}", VolumeLabel.ToString()).AppendLine();
SuperBlockMetadata.AppendFormat("Volume comment: {0}", VolumeComment.ToString()).AppendLine();
SuperBlockMetadata.AppendFormat("Volume identifier: 0x{0}", vid.ToString("X")).AppendLine();
SuperBlockMetadata.AppendFormat("Block size: {0} bytes", bs).AppendLine();
SuperBlockMetadata.AppendFormat("Volume size: {0} blocks, {1} bytes", vblocks, bs*vblocks).AppendLine();
SuperBlockMetadata.AppendFormat("Root directory identifier: 0x{0}", rdid.ToString("X")).AppendLine();
SuperBlockMetadata.AppendFormat("Root directory block size: {0} bytes", rbs).AppendLine();
SuperBlockMetadata.AppendFormat("Root directory size: {0} blocks, {1} bytes", rblocks, rbs*rblocks).AppendLine();
SuperBlockMetadata.AppendFormat("Last root directory copy: {0}", BitConverter.ToInt32(last_root_copy, 0)).AppendLine();
information = SuperBlockMetadata.ToString();
}
}
}

View File

@@ -0,0 +1,38 @@
using System;
using System.IO;
using System.Text;
using FileSystemIDandChk;
// Information from Inside Macintosh
namespace FileSystemIDandChk.Plugins
{
class PCEnginePlugin : Plugin
{
public PCEnginePlugin(PluginBase Core)
{
base.Name = "PC Engine CD Plugin";
base.PluginUUID = new Guid("e5ee6d7c-90fa-49bd-ac89-14ef750b8af3");
}
public override bool Identify(FileStream stream, long offset)
{
byte[] system_descriptor = new byte[23];
stream.Seek(2080 + offset, SeekOrigin.Begin);
stream.Read(system_descriptor, 0, 23);
if(Encoding.ASCII.GetString(system_descriptor) == "PC Engine CD-ROM SYSTEM")
return true;
else
return false;
}
public override void GetInformation (FileStream stream, long offset, out string information)
{
information = "";
}
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.IO;
namespace FileSystemIDandChk.Plugins
{
public abstract class Plugin
{
public string Name;
public Guid PluginUUID;
protected Plugin()
{
}
public abstract bool Identify(FileStream stream, long offset);
public abstract void GetInformation(FileStream stream, long offset, out string information);
}
}

View File

@@ -0,0 +1,63 @@
using System;
namespace FileSystemIDandChk
{
static class Swapping
{
public static byte[] SwapTenBytes(byte[] source)
{
byte[] destination = new byte[8];
destination[0] = source[9];
destination[1] = source[8];
destination[2] = source[7];
destination[3] = source[6];
destination[4] = source[5];
destination[5] = source[4];
destination[6] = source[3];
destination[7] = source[2];
destination[8] = source[1];
destination[9] = source[0];
return destination;
}
public static byte[] SwapEightBytes(byte[] source)
{
byte[] destination = new byte[8];
destination[0] = source[7];
destination[1] = source[6];
destination[2] = source[5];
destination[3] = source[4];
destination[4] = source[3];
destination[5] = source[2];
destination[6] = source[1];
destination[7] = source[0];
return destination;
}
public static byte[] SwapFourBytes(byte[] source)
{
byte[] destination = new byte[4];
destination[0] = source[3];
destination[1] = source[2];
destination[2] = source[1];
destination[3] = source[0];
return destination;
}
public static byte[] SwapTwoBytes(byte[] source)
{
byte[] destination = new byte[2];
destination[0] = source[1];
destination[1] = source[0];
return destination;
}
}
}

1
Packages.mdproj Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?>