🐛Correct character set for ProDOS should be Apple IIc's.

This commit is contained in:
2017-12-28 05:52:04 +00:00
parent 741a3289a2
commit e3bc39a243

View File

@@ -57,36 +57,36 @@ namespace DiscImageChef.Filesystems
/// <summary> /// <summary>
/// A file that occupies between 257 and 32768 blocks /// A file that occupies between 257 and 32768 blocks
/// </summary> /// </summary>
const byte TREE_FILE_TYPE = 0x03; const byte TREE_FILE_TYPE = 0x03;
const byte PASCAL_AREA_TYPE = 0x04; const byte PASCAL_AREA_TYPE = 0x04;
const byte SUBDIRECTORY_TYPE = 0x0D; const byte SUBDIRECTORY_TYPE = 0x0D;
const byte SUBDIRECTORY_HEADER_TYPE = 0x0E; const byte SUBDIRECTORY_HEADER_TYPE = 0x0E;
const byte ROOT_DIRECTORY_TYPE = 0x0F; const byte ROOT_DIRECTORY_TYPE = 0x0F;
const byte VERSION1 = 0x00; const byte VERSION1 = 0x00;
const uint YEAR_MASK = 0xFE000000; const uint YEAR_MASK = 0xFE000000;
const uint MONTH_MASK = 0x1E00000; const uint MONTH_MASK = 0x1E00000;
const uint DAY_MASK = 0x1F0000; const uint DAY_MASK = 0x1F0000;
const uint HOUR_MASK = 0x1F00; const uint HOUR_MASK = 0x1F00;
const uint MINUTE_MASK = 0x3F; const uint MINUTE_MASK = 0x3F;
const byte DESTROY_ATTRIBUTE = 0x80; const byte DESTROY_ATTRIBUTE = 0x80;
const byte RENAME_ATTRIBUTE = 0x40; const byte RENAME_ATTRIBUTE = 0x40;
const byte BACKUP_ATTRIBUTE = 0x20; const byte BACKUP_ATTRIBUTE = 0x20;
const byte WRITE_ATTRIBUTE = 0x02; const byte WRITE_ATTRIBUTE = 0x02;
const byte READ_ATTRIBUTE = 0x01; const byte READ_ATTRIBUTE = 0x01;
const byte RESERVED_ATTRIBUTE_MASK = 0x1C; const byte RESERVED_ATTRIBUTE_MASK = 0x1C;
const byte STORAGE_TYPE_MASK = 0xF0; const byte STORAGE_TYPE_MASK = 0xF0;
const byte NAME_LENGTH_MASK = 0x0F; const byte NAME_LENGTH_MASK = 0x0F;
const byte ENTRY_LENGTH = 0x27; const byte ENTRY_LENGTH = 0x27;
const byte ENTRIES_PER_BLOCK = 0x0D; const byte ENTRIES_PER_BLOCK = 0x0D;
public FileSystemType XmlFsType { get; private set; } public FileSystemType XmlFsType { get; private set; }
public Encoding Encoding { get; private set; } public Encoding Encoding { get; private set; }
public string Name => "Apple ProDOS filesystem"; public string Name => "Apple ProDOS filesystem";
public Guid Id => new Guid("43874265-7B8A-4739-BCF7-07F80D5932BF"); public Guid Id => new Guid("43874265-7B8A-4739-BCF7-07F80D5932BF");
public bool Identify(IMediaImage imagePlugin, Partition partition) public bool Identify(IMediaImage imagePlugin, Partition partition)
{ {
@@ -94,7 +94,7 @@ namespace DiscImageChef.Filesystems
// Blocks 0 and 1 are boot code // Blocks 0 and 1 are boot code
byte[] rootDirectoryKeyBlock = imagePlugin.ReadSector(2 + partition.Start); byte[] rootDirectoryKeyBlock = imagePlugin.ReadSector(2 + partition.Start);
bool APMFromHDDOnCD = false; bool APMFromHDDOnCD = false;
if(imagePlugin.Info.SectorSize == 2352 || imagePlugin.Info.SectorSize == 2448 || if(imagePlugin.Info.SectorSize == 2352 || imagePlugin.Info.SectorSize == 2448 ||
imagePlugin.Info.SectorSize == 2048) imagePlugin.Info.SectorSize == 2048)
@@ -103,8 +103,8 @@ namespace DiscImageChef.Filesystems
foreach(int offset in new[] {0, 0x200, 0x400, 0x600, 0x800, 0xA00}.Where(offset => foreach(int offset in new[] {0, 0x200, 0x400, 0x600, 0x800, 0xA00}.Where(offset =>
BitConverter BitConverter
.ToUInt16(tmp, .ToUInt16(tmp,
offset) == offset) ==
0 && 0 &&
(byte) (byte)
((tmp[offset + 0x04] & ((tmp[offset + 0x04] &
@@ -142,18 +142,18 @@ namespace DiscImageChef.Filesystems
DicConsole.DebugWriteLine("ProDOS plugin", "bit_map_pointer = {0}", bitMapPointer); DicConsole.DebugWriteLine("ProDOS plugin", "bit_map_pointer = {0}", bitMapPointer);
if(bitMapPointer > partition.End) return false; if(bitMapPointer > partition.End) return false;
ushort totalBlocks = BitConverter.ToUInt16(rootDirectoryKeyBlock, 0x29); ushort totalBlocks = BitConverter.ToUInt16(rootDirectoryKeyBlock, 0x29);
if(APMFromHDDOnCD) totalBlocks /= 4; if(APMFromHDDOnCD) totalBlocks /= 4;
DicConsole.DebugWriteLine("ProDOS plugin", "{0} <= ({1} - {2} + 1)? {3}", totalBlocks, partition.End, DicConsole.DebugWriteLine("ProDOS plugin", "{0} <= ({1} - {2} + 1)? {3}", totalBlocks, partition.End,
partition.Start, totalBlocks <= partition.End - partition.Start + 1); partition.Start, totalBlocks <= partition.End - partition.Start + 1);
return totalBlocks <= partition.End - partition.Start + 1; return totalBlocks <= partition.End - partition.Start + 1;
} }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
Encoding encoding) Encoding encoding)
{ {
Encoding = encoding ?? new Apple2gs(); Encoding = encoding ?? new Apple2c();
StringBuilder sbInformation = new StringBuilder(); StringBuilder sbInformation = new StringBuilder();
// Blocks 0 and 1 are boot code // Blocks 0 and 1 are boot code
@@ -168,8 +168,8 @@ namespace DiscImageChef.Filesystems
foreach(int offset in new[] {0, 0x200, 0x400, 0x600, 0x800, 0xA00}.Where(offset => foreach(int offset in new[] {0, 0x200, 0x400, 0x600, 0x800, 0xA00}.Where(offset =>
BitConverter BitConverter
.ToUInt16(tmp, .ToUInt16(tmp,
offset) == offset) ==
0 && 0 &&
(byte) (byte)
((tmp[offset + 0x04] & ((tmp[offset + 0x04] &
@@ -188,54 +188,55 @@ namespace DiscImageChef.Filesystems
} }
ProDOSRootDirectoryKeyBlock rootDirectoryKeyBlock = ProDOSRootDirectoryKeyBlock rootDirectoryKeyBlock =
new ProDOSRootDirectoryKeyBlock {header = new ProDOSRootDirectoryHeader()}; new ProDOSRootDirectoryKeyBlock {header = new ProDOSRootDirectoryHeader()};
rootDirectoryKeyBlock.zero = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x00); rootDirectoryKeyBlock.zero = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x00);
rootDirectoryKeyBlock.next_pointer = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x02); rootDirectoryKeyBlock.next_pointer = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x02);
rootDirectoryKeyBlock.header.storage_type = rootDirectoryKeyBlock.header.storage_type =
(byte)((rootDirectoryKeyBlockBytes[0x04] & STORAGE_TYPE_MASK) >> 4); (byte)((rootDirectoryKeyBlockBytes[0x04] & STORAGE_TYPE_MASK) >>
4);
rootDirectoryKeyBlock.header.name_length = (byte)(rootDirectoryKeyBlockBytes[0x04] & NAME_LENGTH_MASK); rootDirectoryKeyBlock.header.name_length = (byte)(rootDirectoryKeyBlockBytes[0x04] & NAME_LENGTH_MASK);
byte[] temporal = new byte[rootDirectoryKeyBlock.header.name_length]; byte[] temporal = new byte[rootDirectoryKeyBlock.header.name_length];
Array.Copy(rootDirectoryKeyBlockBytes, 0x05, temporal, 0, rootDirectoryKeyBlock.header.name_length); Array.Copy(rootDirectoryKeyBlockBytes, 0x05, temporal, 0, rootDirectoryKeyBlock.header.name_length);
rootDirectoryKeyBlock.header.volume_name = Encoding.GetString(temporal); rootDirectoryKeyBlock.header.volume_name = Encoding.GetString(temporal);
rootDirectoryKeyBlock.header.reserved = BitConverter.ToUInt64(rootDirectoryKeyBlockBytes, 0x14); rootDirectoryKeyBlock.header.reserved = BitConverter.ToUInt64(rootDirectoryKeyBlockBytes, 0x14);
ushort tempTimestampLeft = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x1C); ushort tempTimestampLeft = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x1C);
ushort tempTimestampRight = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x1E); ushort tempTimestampRight = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x1E);
bool dateCorrect; bool dateCorrect;
try try
{ {
uint tempTimestamp = (uint)((tempTimestampLeft << 16) + tempTimestampRight); uint tempTimestamp = (uint)((tempTimestampLeft << 16) + tempTimestampRight);
int year = (int)((tempTimestamp & YEAR_MASK) >> 25); int year = (int)((tempTimestamp & YEAR_MASK) >> 25);
int month = (int)((tempTimestamp & MONTH_MASK) >> 21); int month = (int)((tempTimestamp & MONTH_MASK) >> 21);
int day = (int)((tempTimestamp & DAY_MASK) >> 16); int day = (int)((tempTimestamp & DAY_MASK) >> 16);
int hour = (int)((tempTimestamp & HOUR_MASK) >> 8); int hour = (int)((tempTimestamp & HOUR_MASK) >> 8);
int minute = (int)(tempTimestamp & MINUTE_MASK); int minute = (int)(tempTimestamp & MINUTE_MASK);
year += 1900; year += 1900;
if(year < 1940) year += 100; if(year < 1940) year += 100;
DicConsole.DebugWriteLine("ProDOS plugin", "temp_timestamp_left = 0x{0:X4}", tempTimestampLeft); 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_right = 0x{0:X4}", tempTimestampRight);
DicConsole.DebugWriteLine("ProDOS plugin", "temp_timestamp = 0x{0:X8}", tempTimestamp); DicConsole.DebugWriteLine("ProDOS plugin", "temp_timestamp = 0x{0:X8}", tempTimestamp);
DicConsole.DebugWriteLine("ProDOS plugin", DicConsole.DebugWriteLine("ProDOS plugin",
"Datetime field year {0}, month {1}, day {2}, hour {3}, minute {4}.", year, "Datetime field year {0}, month {1}, day {2}, hour {3}, minute {4}.", year,
month, day, hour, minute); month, day, hour, minute);
rootDirectoryKeyBlock.header.creation_time = new DateTime(year, month, day, hour, minute, 0); rootDirectoryKeyBlock.header.creation_time = new DateTime(year, month, day, hour, minute, 0);
dateCorrect = true; dateCorrect = true;
} }
catch(ArgumentOutOfRangeException) { dateCorrect = false; } catch(ArgumentOutOfRangeException) { dateCorrect = false; }
rootDirectoryKeyBlock.header.version = rootDirectoryKeyBlockBytes[0x20]; rootDirectoryKeyBlock.header.version = rootDirectoryKeyBlockBytes[0x20];
rootDirectoryKeyBlock.header.min_version = rootDirectoryKeyBlockBytes[0x21]; rootDirectoryKeyBlock.header.min_version = rootDirectoryKeyBlockBytes[0x21];
rootDirectoryKeyBlock.header.access = rootDirectoryKeyBlockBytes[0x22]; rootDirectoryKeyBlock.header.access = rootDirectoryKeyBlockBytes[0x22];
rootDirectoryKeyBlock.header.entry_length = rootDirectoryKeyBlockBytes[0x23]; rootDirectoryKeyBlock.header.entry_length = rootDirectoryKeyBlockBytes[0x23];
rootDirectoryKeyBlock.header.entries_per_block = rootDirectoryKeyBlockBytes[0x24]; rootDirectoryKeyBlock.header.entries_per_block = rootDirectoryKeyBlockBytes[0x24];
rootDirectoryKeyBlock.header.file_count = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x25); rootDirectoryKeyBlock.header.file_count = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x25);
rootDirectoryKeyBlock.header.bit_map_pointer = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x27); rootDirectoryKeyBlock.header.bit_map_pointer = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x27);
rootDirectoryKeyBlock.header.total_blocks = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x29); rootDirectoryKeyBlock.header.total_blocks = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x29);
if(APMFromHDDOnCD) if(APMFromHDDOnCD)
sbInformation.AppendLine("ProDOS uses 512 bytes/sector while devices uses 2048 bytes/sector.") sbInformation.AppendLine("ProDOS uses 512 bytes/sector while devices uses 2048 bytes/sector.")
@@ -257,8 +258,8 @@ namespace DiscImageChef.Filesystems
sbInformation.AppendLine("ProDOS version 1 at least required for reading this volume."); sbInformation.AppendLine("ProDOS version 1 at least required for reading this volume.");
else else
sbInformation sbInformation
.AppendFormat("Unknown ProDOS version with field {0} is at least required for reading this volume.", .AppendFormat("Unknown ProDOS version with field {0} is at least required for reading this volume.",
rootDirectoryKeyBlock.header.min_version).AppendLine(); rootDirectoryKeyBlock.header.min_version).AppendLine();
sbInformation.AppendFormat("Volume name is {0}", rootDirectoryKeyBlock.header.volume_name).AppendLine(); sbInformation.AppendFormat("Volume name is {0}", rootDirectoryKeyBlock.header.volume_name).AppendLine();
if(dateCorrect) if(dateCorrect)
@@ -267,11 +268,12 @@ namespace DiscImageChef.Filesystems
sbInformation.AppendFormat("{0} bytes per directory entry", rootDirectoryKeyBlock.header.entry_length) sbInformation.AppendFormat("{0} bytes per directory entry", rootDirectoryKeyBlock.header.entry_length)
.AppendLine(); .AppendLine();
sbInformation sbInformation
.AppendFormat("{0} entries per directory block", rootDirectoryKeyBlock.header.entries_per_block) .AppendFormat("{0} entries per directory block", rootDirectoryKeyBlock.header.entries_per_block)
.AppendLine(); .AppendLine();
sbInformation.AppendFormat("{0} files in root directory", rootDirectoryKeyBlock.header.file_count) sbInformation.AppendFormat("{0} files in root directory", rootDirectoryKeyBlock.header.file_count)
.AppendLine(); .AppendLine();
sbInformation.AppendFormat("{0} blocks in volume", rootDirectoryKeyBlock.header.total_blocks).AppendLine(); sbInformation.AppendFormat("{0} blocks in volume", rootDirectoryKeyBlock.header.total_blocks)
.AppendLine();
sbInformation.AppendFormat("Bitmap starts at block {0}", rootDirectoryKeyBlock.header.bit_map_pointer) sbInformation.AppendFormat("Bitmap starts at block {0}", rootDirectoryKeyBlock.header.bit_map_pointer)
.AppendLine(); .AppendLine();
@@ -292,18 +294,19 @@ namespace DiscImageChef.Filesystems
information = sbInformation.ToString(); information = sbInformation.ToString();
XmlFsType = new FileSystemType(); XmlFsType = new FileSystemType();
XmlFsType.VolumeName = rootDirectoryKeyBlock.header.volume_name; XmlFsType.VolumeName = rootDirectoryKeyBlock.header.volume_name;
if(dateCorrect) if(dateCorrect)
{ {
XmlFsType.CreationDate = rootDirectoryKeyBlock.header.creation_time; XmlFsType.CreationDate = rootDirectoryKeyBlock.header.creation_time;
XmlFsType.CreationDateSpecified = true; XmlFsType.CreationDateSpecified = true;
} }
XmlFsType.Files = rootDirectoryKeyBlock.header.file_count;
XmlFsType.Files = rootDirectoryKeyBlock.header.file_count;
XmlFsType.FilesSpecified = true; XmlFsType.FilesSpecified = true;
XmlFsType.Clusters = rootDirectoryKeyBlock.header.total_blocks; XmlFsType.Clusters = rootDirectoryKeyBlock.header.total_blocks;
XmlFsType.ClusterSize = (int)((partition.End - partition.Start + 1) * imagePlugin.Info.SectorSize / XmlFsType.ClusterSize = (int)((partition.End - partition.Start + 1) * imagePlugin.Info.SectorSize /
(ulong)XmlFsType.Clusters); (ulong)XmlFsType.Clusters);
XmlFsType.Type = "ProDOS"; XmlFsType.Type = "ProDOS";
} }