REFACTOR: All refactor in DiscImageChef.Filesystems.

This commit is contained in:
2017-12-22 08:43:22 +00:00
parent ef2fff0abd
commit c59e424ec8
87 changed files with 3834 additions and 4122 deletions

View File

@@ -46,55 +46,55 @@ namespace DiscImageChef.Filesystems
// Information from Apple ProDOS 8 Technical Reference
public class ProDOSPlugin : Filesystem
{
const byte EmptyStorageType = 0x00;
const byte EMPTY_STORAGE_TYPE = 0x00;
/// <summary>
/// A file that occupies one block or less
/// </summary>
const byte SeedlingFileType = 0x01;
const byte SEEDLING_FILE_TYPE = 0x01;
/// <summary>
/// A file that occupies between 2 and 256 blocks
/// </summary>
const byte SaplingFileType = 0x02;
const byte SAPLING_FILE_TYPE = 0x02;
/// <summary>
/// A file that occupies between 257 and 32768 blocks
/// </summary>
const byte TreeFileType = 0x03;
const byte PascalAreaType = 0x04;
const byte SubDirectoryType = 0x0D;
const byte SubDirectoryHeaderType = 0x0E;
const byte RootDirectoryType = 0x0F;
const byte TREE_FILE_TYPE = 0x03;
const byte PASCAL_AREA_TYPE = 0x04;
const byte SUBDIRECTORY_TYPE = 0x0D;
const byte SUBDIRECTORY_HEADER_TYPE = 0x0E;
const byte ROOT_DIRECTORY_TYPE = 0x0F;
const byte ProDOSVersion1 = 0x00;
const byte VERSION1 = 0x00;
const uint ProDOSYearMask = 0xFE000000;
const uint ProDOSMonthMask = 0x1E00000;
const uint ProDOSDayMask = 0x1F0000;
const uint ProDOSHourMask = 0x1F00;
const uint ProDOSMinuteMask = 0x3F;
const uint YEAR_MASK = 0xFE000000;
const uint MONTH_MASK = 0x1E00000;
const uint DAY_MASK = 0x1F0000;
const uint HOUR_MASK = 0x1F00;
const uint MINUTE_MASK = 0x3F;
const byte ProDOSDestroyAttribute = 0x80;
const byte ProDOSRenameAttribute = 0x40;
const byte ProDOSBackupAttribute = 0x20;
const byte ProDOSWriteAttribute = 0x02;
const byte ProDOSReadAttribute = 0x01;
const byte ProDOSReservedAttributeMask = 0x1C;
const byte DESTROY_ATTRIBUTE = 0x80;
const byte RENAME_ATTRIBUTE = 0x40;
const byte BACKUP_ATTRIBUTE = 0x20;
const byte WRITE_ATTRIBUTE = 0x02;
const byte READ_ATTRIBUTE = 0x01;
const byte RESERVED_ATTRIBUTE_MASK = 0x1C;
const byte ProDOSStorageTypeMask = 0xF0;
const byte ProDOSNameLengthMask = 0x0F;
const byte ProDOSEntryLength = 0x27;
const byte ProDOSEntriesPerBlock = 0x0D;
const byte STORAGE_TYPE_MASK = 0xF0;
const byte NAME_LENGTH_MASK = 0x0F;
const byte ENTRY_LENGTH = 0x27;
const byte ENTRIES_PER_BLOCK = 0x0D;
public ProDOSPlugin()
{
Name = "Apple ProDOS filesystem";
PluginUUID = new Guid("43874265-7B8A-4739-BCF7-07F80D5932BF");
PluginUuid = new Guid("43874265-7B8A-4739-BCF7-07F80D5932BF");
CurrentEncoding = new LisaRoman();
}
public ProDOSPlugin(Encoding encoding)
{
Name = "Apple ProDOS filesystem";
PluginUUID = new Guid("43874265-7B8A-4739-BCF7-07F80D5932BF");
PluginUuid = new Guid("43874265-7B8A-4739-BCF7-07F80D5932BF");
// TODO: Until Apple ][ encoding is implemented
CurrentEncoding = new LisaRoman();
}
@@ -102,7 +102,7 @@ namespace DiscImageChef.Filesystems
public ProDOSPlugin(ImagePlugin imagePlugin, Partition partition, Encoding encoding)
{
Name = "Apple ProDOS filesystem";
PluginUUID = new Guid("43874265-7B8A-4739-BCF7-07F80D5932BF");
PluginUuid = new Guid("43874265-7B8A-4739-BCF7-07F80D5932BF");
// TODO: Until Apple ][ encoding is implemented
CurrentEncoding = new LisaRoman();
}
@@ -121,8 +121,8 @@ namespace DiscImageChef.Filesystems
byte[] tmp = imagePlugin.ReadSectors(partition.Start, 2);
foreach(int offset in new[] {0, 0x200, 0x400, 0x600, 0x800, 0xA00}.Where(offset => BitConverter.ToUInt16(tmp, offset) == 0 &&
(byte)((tmp[offset + 0x04] & ProDOSStorageTypeMask) >> 4) == RootDirectoryType &&
tmp[offset + 0x23] == ProDOSEntryLength && tmp[offset + 0x24] == ProDOSEntriesPerBlock)) {
(byte)((tmp[offset + 0x04] & STORAGE_TYPE_MASK) >> 4) == ROOT_DIRECTORY_TYPE &&
tmp[offset + 0x23] == ENTRY_LENGTH && tmp[offset + 0x24] == ENTRIES_PER_BLOCK)) {
Array.Copy(tmp, offset, rootDirectoryKeyBlock, 0, 0x200);
APMFromHDDOnCD = true;
break;
@@ -133,28 +133,28 @@ namespace DiscImageChef.Filesystems
DicConsole.DebugWriteLine("ProDOS plugin", "prePointer = {0}", prePointer);
if(prePointer != 0) return false;
byte storage_type = (byte)((rootDirectoryKeyBlock[0x04] & ProDOSStorageTypeMask) >> 4);
DicConsole.DebugWriteLine("ProDOS plugin", "storage_type = {0}", storage_type);
if(storage_type != RootDirectoryType) return false;
byte storageType = (byte)((rootDirectoryKeyBlock[0x04] & STORAGE_TYPE_MASK) >> 4);
DicConsole.DebugWriteLine("ProDOS plugin", "storage_type = {0}", storageType);
if(storageType != ROOT_DIRECTORY_TYPE) return false;
byte entry_length = rootDirectoryKeyBlock[0x23];
DicConsole.DebugWriteLine("ProDOS plugin", "entry_length = {0}", entry_length);
if(entry_length != ProDOSEntryLength) return false;
byte entryLength = rootDirectoryKeyBlock[0x23];
DicConsole.DebugWriteLine("ProDOS plugin", "entry_length = {0}", entryLength);
if(entryLength != ENTRY_LENGTH) return false;
byte entries_per_block = rootDirectoryKeyBlock[0x24];
DicConsole.DebugWriteLine("ProDOS plugin", "entries_per_block = {0}", entries_per_block);
if(entries_per_block != ProDOSEntriesPerBlock) return false;
byte entriesPerBlock = rootDirectoryKeyBlock[0x24];
DicConsole.DebugWriteLine("ProDOS plugin", "entries_per_block = {0}", entriesPerBlock);
if(entriesPerBlock != ENTRIES_PER_BLOCK) return false;
ushort bit_map_pointer = BitConverter.ToUInt16(rootDirectoryKeyBlock, 0x27);
DicConsole.DebugWriteLine("ProDOS plugin", "bit_map_pointer = {0}", bit_map_pointer);
if(bit_map_pointer > partition.End) return false;
ushort bitMapPointer = BitConverter.ToUInt16(rootDirectoryKeyBlock, 0x27);
DicConsole.DebugWriteLine("ProDOS plugin", "bit_map_pointer = {0}", bitMapPointer);
if(bitMapPointer > partition.End) return false;
ushort total_blocks = BitConverter.ToUInt16(rootDirectoryKeyBlock, 0x29);
if(APMFromHDDOnCD) total_blocks /= 4;
ushort totalBlocks = BitConverter.ToUInt16(rootDirectoryKeyBlock, 0x29);
if(APMFromHDDOnCD) totalBlocks /= 4;
DicConsole.DebugWriteLine("ProDOS plugin", "{0} <= ({1} - {2} + 1)? {3}", total_blocks, partition.End,
partition.Start, total_blocks <= partition.End - partition.Start + 1);
return total_blocks <= partition.End - partition.Start + 1;
DicConsole.DebugWriteLine("ProDOS plugin", "{0} <= ({1} - {2} + 1)? {3}", totalBlocks, partition.End,
partition.Start, totalBlocks <= partition.End - partition.Start + 1);
return totalBlocks <= partition.End - partition.Start + 1;
}
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
@@ -173,50 +173,45 @@ namespace DiscImageChef.Filesystems
byte[] tmp = imagePlugin.ReadSectors(partition.Start, 2);
foreach(int offset in new[] {0, 0x200, 0x400, 0x600, 0x800, 0xA00}.Where(offset => BitConverter.ToUInt16(tmp, offset) == 0 &&
(byte)((tmp[offset + 0x04] & ProDOSStorageTypeMask) >> 4) == RootDirectoryType &&
tmp[offset + 0x23] == ProDOSEntryLength && tmp[offset + 0x24] == ProDOSEntriesPerBlock)) {
(byte)((tmp[offset + 0x04] & STORAGE_TYPE_MASK) >> 4) == ROOT_DIRECTORY_TYPE &&
tmp[offset + 0x23] == ENTRY_LENGTH && tmp[offset + 0x24] == ENTRIES_PER_BLOCK)) {
Array.Copy(tmp, offset, rootDirectoryKeyBlockBytes, 0, 0x200);
APMFromHDDOnCD = true;
break;
}
}
ProDOSRootDirectoryKeyBlock rootDirectoryKeyBlock = new ProDOSRootDirectoryKeyBlock();
rootDirectoryKeyBlock.header = new ProDOSRootDirectoryHeader();
byte[] temporal;
int year, month, day, hour, minute;
ushort temp_timestamp_left, temp_timestamp_right;
uint temp_timestamp;
ProDOSRootDirectoryKeyBlock rootDirectoryKeyBlock =
new ProDOSRootDirectoryKeyBlock {header = new ProDOSRootDirectoryHeader()};
rootDirectoryKeyBlock.zero = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x00);
rootDirectoryKeyBlock.next_pointer = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x02);
rootDirectoryKeyBlock.header.storage_type =
(byte)((rootDirectoryKeyBlockBytes[0x04] & ProDOSStorageTypeMask) >> 4);
rootDirectoryKeyBlock.header.name_length = (byte)(rootDirectoryKeyBlockBytes[0x04] & ProDOSNameLengthMask);
temporal = new byte[rootDirectoryKeyBlock.header.name_length];
(byte)((rootDirectoryKeyBlockBytes[0x04] & STORAGE_TYPE_MASK) >> 4);
rootDirectoryKeyBlock.header.name_length = (byte)(rootDirectoryKeyBlockBytes[0x04] & NAME_LENGTH_MASK);
byte[] temporal = new byte[rootDirectoryKeyBlock.header.name_length];
Array.Copy(rootDirectoryKeyBlockBytes, 0x05, temporal, 0, rootDirectoryKeyBlock.header.name_length);
rootDirectoryKeyBlock.header.volume_name = CurrentEncoding.GetString(temporal);
rootDirectoryKeyBlock.header.reserved = BitConverter.ToUInt64(rootDirectoryKeyBlockBytes, 0x14);
temp_timestamp_left = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x1C);
temp_timestamp_right = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x1E);
ushort tempTimestampLeft = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x1C);
ushort tempTimestampRight = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x1E);
bool dateCorrect;
try
{
temp_timestamp = (uint)((temp_timestamp_left << 16) + temp_timestamp_right);
year = (int)((temp_timestamp & ProDOSYearMask) >> 25);
month = (int)((temp_timestamp & ProDOSMonthMask) >> 21);
day = (int)((temp_timestamp & ProDOSDayMask) >> 16);
hour = (int)((temp_timestamp & ProDOSHourMask) >> 8);
minute = (int)(temp_timestamp & ProDOSMinuteMask);
uint tempTimestamp = (uint)((tempTimestampLeft << 16) + tempTimestampRight);
int year = (int)((tempTimestamp & YEAR_MASK) >> 25);
int month = (int)((tempTimestamp & MONTH_MASK) >> 21);
int day = (int)((tempTimestamp & DAY_MASK) >> 16);
int hour = (int)((tempTimestamp & HOUR_MASK) >> 8);
int minute = (int)(tempTimestamp & MINUTE_MASK);
year += 1900;
if(year < 1940) year += 100;
DicConsole.DebugWriteLine("ProDOS plugin", "temp_timestamp_left = 0x{0:X4}", temp_timestamp_left);
DicConsole.DebugWriteLine("ProDOS plugin", "temp_timestamp_right = 0x{0:X4}", temp_timestamp_right);
DicConsole.DebugWriteLine("ProDOS plugin", "temp_timestamp = 0x{0:X8}", temp_timestamp);
DicConsole.DebugWriteLine("ProDOS plugin", "temp_timestamp_left = 0x{0:X4}", tempTimestampLeft);
DicConsole.DebugWriteLine("ProDOS plugin", "temp_timestamp_right = 0x{0:X4}", tempTimestampRight);
DicConsole.DebugWriteLine("ProDOS plugin", "temp_timestamp = 0x{0:X8}", tempTimestamp);
DicConsole.DebugWriteLine("ProDOS plugin",
"Datetime field year {0}, month {1}, day {2}, hour {3}, minute {4}.", year,
month, day, hour, minute);
@@ -240,20 +235,20 @@ namespace DiscImageChef.Filesystems
sbInformation.AppendLine("ProDOS uses 512 bytes/sector while devices uses 2048 bytes/sector.")
.AppendLine();
if(rootDirectoryKeyBlock.header.version != ProDOSVersion1 ||
rootDirectoryKeyBlock.header.min_version != ProDOSVersion1)
if(rootDirectoryKeyBlock.header.version != VERSION1 ||
rootDirectoryKeyBlock.header.min_version != VERSION1)
{
sbInformation.AppendLine("Warning! Detected unknown ProDOS version ProDOS filesystem.");
sbInformation.AppendLine("All of the following information may be incorrect");
}
if(rootDirectoryKeyBlock.header.version == ProDOSVersion1)
if(rootDirectoryKeyBlock.header.version == VERSION1)
sbInformation.AppendLine("ProDOS version 1 used to create this volume.");
else
sbInformation.AppendFormat("Unknown ProDOS version with field {0} used to create this volume.",
rootDirectoryKeyBlock.header.version).AppendLine();
if(rootDirectoryKeyBlock.header.min_version == ProDOSVersion1)
if(rootDirectoryKeyBlock.header.min_version == VERSION1)
sbInformation.AppendLine("ProDOS version 1 at least required for reading this volume.");
else
sbInformation
@@ -275,36 +270,36 @@ namespace DiscImageChef.Filesystems
sbInformation.AppendFormat("Bitmap starts at block {0}", rootDirectoryKeyBlock.header.bit_map_pointer)
.AppendLine();
if((rootDirectoryKeyBlock.header.access & ProDOSReadAttribute) == ProDOSReadAttribute)
if((rootDirectoryKeyBlock.header.access & READ_ATTRIBUTE) == READ_ATTRIBUTE)
sbInformation.AppendLine("Volume can be read");
if((rootDirectoryKeyBlock.header.access & ProDOSWriteAttribute) == ProDOSWriteAttribute)
if((rootDirectoryKeyBlock.header.access & WRITE_ATTRIBUTE) == WRITE_ATTRIBUTE)
sbInformation.AppendLine("Volume can be written");
if((rootDirectoryKeyBlock.header.access & ProDOSRenameAttribute) == ProDOSRenameAttribute)
if((rootDirectoryKeyBlock.header.access & RENAME_ATTRIBUTE) == RENAME_ATTRIBUTE)
sbInformation.AppendLine("Volume can be renamed");
if((rootDirectoryKeyBlock.header.access & ProDOSDestroyAttribute) == ProDOSDestroyAttribute)
if((rootDirectoryKeyBlock.header.access & DESTROY_ATTRIBUTE) == DESTROY_ATTRIBUTE)
sbInformation.AppendLine("Volume can be destroyed");
if((rootDirectoryKeyBlock.header.access & ProDOSBackupAttribute) == ProDOSBackupAttribute)
if((rootDirectoryKeyBlock.header.access & BACKUP_ATTRIBUTE) == BACKUP_ATTRIBUTE)
sbInformation.AppendLine("Volume must be backed up");
if((rootDirectoryKeyBlock.header.access & ProDOSReservedAttributeMask) != 0)
if((rootDirectoryKeyBlock.header.access & RESERVED_ATTRIBUTE_MASK) != 0)
DicConsole.DebugWriteLine("ProDOS plugin", "Reserved attributes are set: {0:X2}",
rootDirectoryKeyBlock.header.access);
information = sbInformation.ToString();
xmlFSType = new FileSystemType();
xmlFSType.VolumeName = rootDirectoryKeyBlock.header.volume_name;
XmlFsType = new FileSystemType();
XmlFsType.VolumeName = rootDirectoryKeyBlock.header.volume_name;
if(dateCorrect)
{
xmlFSType.CreationDate = rootDirectoryKeyBlock.header.creation_time;
xmlFSType.CreationDateSpecified = true;
XmlFsType.CreationDate = rootDirectoryKeyBlock.header.creation_time;
XmlFsType.CreationDateSpecified = true;
}
xmlFSType.Files = rootDirectoryKeyBlock.header.file_count;
xmlFSType.FilesSpecified = true;
xmlFSType.Clusters = rootDirectoryKeyBlock.header.total_blocks;
xmlFSType.ClusterSize = (int)((partition.End - partition.Start + 1) * imagePlugin.ImageInfo.SectorSize /
(ulong)xmlFSType.Clusters);
xmlFSType.Type = "ProDOS";
XmlFsType.Files = rootDirectoryKeyBlock.header.file_count;
XmlFsType.FilesSpecified = true;
XmlFsType.Clusters = rootDirectoryKeyBlock.header.total_blocks;
XmlFsType.ClusterSize = (int)((partition.End - partition.Start + 1) * imagePlugin.ImageInfo.SectorSize /
(ulong)XmlFsType.Clusters);
XmlFsType.Type = "ProDOS";
}
public override Errno Mount()