Files
Aaru/DiscImageChef.Core/Sidecar/BlockMedia.cs

799 lines
41 KiB
C#
Raw Normal View History

2017-08-08 13:40:32 +01:00
// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : BlockMedia.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
2017-08-08 13:40:32 +01:00
//
// Component : Core algorithms.
2017-08-08 13:40:32 +01:00
//
// --[ Description ] ----------------------------------------------------------
//
// Contains logic to create sidecar from a block media dump.
2017-08-08 13:40:32 +01:00
//
// --[ License ] --------------------------------------------------------------
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
2018-12-29 17:34:38 +00:00
// Copyright © 2011-2019 Natalia Portillo
2017-08-08 13:40:32 +01:00
// ****************************************************************************/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
2017-08-08 13:40:32 +01:00
using DiscImageChef.CommonTypes;
using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.CommonTypes.Interfaces;
using DiscImageChef.CommonTypes.Metadata;
using DiscImageChef.Console;
2017-12-21 14:30:38 +00:00
using DiscImageChef.Decoders.ATA;
2017-08-08 13:40:32 +01:00
using DiscImageChef.Decoders.PCMCIA;
2017-12-21 14:30:38 +00:00
using DiscImageChef.DiscImages;
using DiscImageChef.Filters;
2017-08-08 13:40:32 +01:00
using Schemas;
using MediaType = DiscImageChef.CommonTypes.Metadata.MediaType;
using Tuple = DiscImageChef.Decoders.PCMCIA.Tuple;
2017-08-08 13:40:32 +01:00
namespace DiscImageChef.Core
{
public static partial class Sidecar
{
/// <summary>
/// Creates a metadata sidecar for a block media (e.g. floppy, hard disk, flash card, usb stick)
/// </summary>
/// <param name="image">Image</param>
/// <param name="filterId">Filter uuid</param>
/// <param name="imagePath">Image path</param>
/// <param name="fi">Image file information</param>
/// <param name="plugins">Image plugins</param>
/// <param name="imgChecksums">List of image checksums</param>
/// <param name="sidecar">Metadata sidecar</param>
2018-06-22 08:08:38 +01:00
static void BlockMedia(IMediaImage image, Guid filterId, string imagePath,
FileInfo fi, PluginBase plugins,
List<ChecksumType> imgChecksums, ref CICMMetadataType sidecar, Encoding encoding)
2017-08-08 13:40:32 +01:00
{
2017-08-08 14:18:31 +01:00
sidecar.BlockMedia = new[]
{
2017-12-19 20:33:03 +00:00
new BlockMediaType
{
Checksums = imgChecksums.ToArray(),
2018-06-22 08:08:38 +01:00
Image = new ImageType
2017-12-19 20:33:03 +00:00
{
format = image.Format,
offset = 0,
2017-12-19 20:33:03 +00:00
offsetSpecified = true,
Value = Path.GetFileName(imagePath)
2017-12-19 20:33:03 +00:00
},
Size = fi.Length,
Sequence = new SequenceType {MediaTitle = image.Info.MediaTitle}
2017-08-08 14:18:31 +01:00
}
};
if(image.Info.MediaSequence != 0 && image.Info.LastMediaSequence != 0)
2017-08-08 13:40:32 +01:00
{
sidecar.BlockMedia[0].Sequence.MediaSequence = image.Info.MediaSequence;
sidecar.BlockMedia[0].Sequence.TotalMedia = image.Info.LastMediaSequence;
2017-08-08 13:40:32 +01:00
}
else
{
sidecar.BlockMedia[0].Sequence.MediaSequence = 1;
sidecar.BlockMedia[0].Sequence.TotalMedia = 1;
2017-08-08 13:40:32 +01:00
}
foreach(MediaTagType tagType in image.Info.ReadableMediaTags)
2017-08-08 13:40:32 +01:00
switch(tagType)
{
case MediaTagType.ATAPI_IDENTIFY:
2017-08-08 14:18:31 +01:00
sidecar.BlockMedia[0].ATA = new ATAType
{
Identify = new DumpType
{
2017-12-19 20:33:03 +00:00
Checksums =
2018-12-31 13:17:27 +00:00
Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.ATAPI_IDENTIFY))
.ToArray(),
2017-08-08 14:18:31 +01:00
Size = image.ReadDiskTag(MediaTagType.ATAPI_IDENTIFY).Length
}
};
2017-08-08 13:40:32 +01:00
break;
case MediaTagType.ATA_IDENTIFY:
2017-08-08 14:18:31 +01:00
sidecar.BlockMedia[0].ATA = new ATAType
{
Identify = new DumpType
{
2018-12-31 13:17:27 +00:00
Checksums = Checksum
.GetChecksums(image.ReadDiskTag(MediaTagType.ATA_IDENTIFY))
.ToArray(),
2017-08-08 14:18:31 +01:00
Size = image.ReadDiskTag(MediaTagType.ATA_IDENTIFY).Length
}
};
2017-08-08 13:40:32 +01:00
break;
case MediaTagType.PCMCIA_CIS:
2018-06-22 08:08:38 +01:00
byte[] cis = image.ReadDiskTag(MediaTagType.PCMCIA_CIS);
2017-08-08 14:18:31 +01:00
sidecar.BlockMedia[0].PCMCIA = new PCMCIAType
{
2017-12-19 20:33:03 +00:00
CIS = new DumpType {Checksums = Checksum.GetChecksums(cis).ToArray(), Size = cis.Length}
2017-08-08 14:18:31 +01:00
};
2017-08-08 13:40:32 +01:00
Tuple[] tuples = CIS.GetTuples(cis);
if(tuples != null)
foreach(Tuple tuple in tuples)
switch(tuple.Code)
{
case TupleCodes.CISTPL_MANFID:
ManufacturerIdentificationTuple manfid =
CIS.DecodeManufacturerIdentificationTuple(tuple);
2017-08-08 13:40:32 +01:00
if(manfid != null)
{
sidecar.BlockMedia[0].PCMCIA.ManufacturerCode =
manfid.ManufacturerID;
sidecar.BlockMedia[0].PCMCIA.CardCode = manfid.CardID;
sidecar.BlockMedia[0].PCMCIA.ManufacturerCodeSpecified = true;
sidecar.BlockMedia[0].PCMCIA.CardCodeSpecified = true;
}
break;
case TupleCodes.CISTPL_VERS_1:
Level1VersionTuple vers = CIS.DecodeLevel1VersionTuple(tuple);
2017-08-08 13:40:32 +01:00
if(vers != null)
{
sidecar.BlockMedia[0].PCMCIA.Manufacturer = vers.Manufacturer;
sidecar.BlockMedia[0].PCMCIA.ProductName = vers.Product;
2018-06-22 08:08:38 +01:00
sidecar.BlockMedia[0].PCMCIA.Compliance =
$"{vers.MajorVersion}.{vers.MinorVersion}";
sidecar.BlockMedia[0].PCMCIA.AdditionalInformation =
vers.AdditionalInformation;
}
break;
2017-08-08 13:40:32 +01:00
}
2017-12-19 20:33:03 +00:00
2017-08-08 13:40:32 +01:00
break;
case MediaTagType.SCSI_INQUIRY:
2017-08-08 14:18:31 +01:00
sidecar.BlockMedia[0].SCSI = new SCSIType
{
Inquiry = new DumpType
{
2018-12-31 13:17:27 +00:00
Checksums = Checksum
.GetChecksums(image.ReadDiskTag(MediaTagType.SCSI_INQUIRY))
.ToArray(),
2017-08-08 14:18:31 +01:00
Size = image.ReadDiskTag(MediaTagType.SCSI_INQUIRY).Length
}
};
2017-08-08 13:40:32 +01:00
break;
case MediaTagType.SD_CID:
if(sidecar.BlockMedia[0].SecureDigital == null)
sidecar.BlockMedia[0].SecureDigital = new SecureDigitalType();
2017-08-08 14:18:31 +01:00
sidecar.BlockMedia[0].SecureDigital.CID = new DumpType
{
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.SD_CID)).ToArray(),
Size = image.ReadDiskTag(MediaTagType.SD_CID).Length
2017-08-08 14:18:31 +01:00
};
2017-08-08 13:40:32 +01:00
break;
case MediaTagType.SD_CSD:
if(sidecar.BlockMedia[0].SecureDigital == null)
sidecar.BlockMedia[0].SecureDigital = new SecureDigitalType();
2017-08-08 14:18:31 +01:00
sidecar.BlockMedia[0].SecureDigital.CSD = new DumpType
{
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.SD_CSD)).ToArray(),
Size = image.ReadDiskTag(MediaTagType.SD_CSD).Length
2017-08-08 14:18:31 +01:00
};
2017-08-08 13:40:32 +01:00
break;
2017-09-29 14:43:59 +01:00
case MediaTagType.SD_SCR:
2017-08-08 13:40:32 +01:00
if(sidecar.BlockMedia[0].SecureDigital == null)
sidecar.BlockMedia[0].SecureDigital = new SecureDigitalType();
2017-09-29 14:43:59 +01:00
sidecar.BlockMedia[0].SecureDigital.SCR = new DumpType
2017-08-08 14:18:31 +01:00
{
2017-09-29 14:43:59 +01:00
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.SD_SCR)).ToArray(),
Size = image.ReadDiskTag(MediaTagType.SD_SCR).Length
2017-09-29 14:43:59 +01:00
};
break;
case MediaTagType.SD_OCR:
if(sidecar.BlockMedia[0].SecureDigital == null)
sidecar.BlockMedia[0].SecureDigital = new SecureDigitalType();
sidecar.BlockMedia[0].SecureDigital.OCR = new DumpType
{
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.SD_OCR)).ToArray(),
Size = image.ReadDiskTag(MediaTagType.SD_OCR).Length
2017-09-29 14:43:59 +01:00
};
break;
case MediaTagType.MMC_CID:
if(sidecar.BlockMedia[0].MultiMediaCard == null)
sidecar.BlockMedia[0].MultiMediaCard = new MultiMediaCardType();
sidecar.BlockMedia[0].MultiMediaCard.CID = new DumpType
{
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.SD_CID)).ToArray(),
Size = image.ReadDiskTag(MediaTagType.SD_CID).Length
2017-09-29 14:43:59 +01:00
};
break;
case MediaTagType.MMC_CSD:
if(sidecar.BlockMedia[0].MultiMediaCard == null)
sidecar.BlockMedia[0].MultiMediaCard = new MultiMediaCardType();
sidecar.BlockMedia[0].MultiMediaCard.CSD = new DumpType
{
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.SD_CSD)).ToArray(),
Size = image.ReadDiskTag(MediaTagType.SD_CSD).Length
2017-09-29 14:43:59 +01:00
};
break;
case MediaTagType.MMC_OCR:
if(sidecar.BlockMedia[0].MultiMediaCard == null)
sidecar.BlockMedia[0].MultiMediaCard = new MultiMediaCardType();
sidecar.BlockMedia[0].MultiMediaCard.OCR = new DumpType
{
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.SD_OCR)).ToArray(),
Size = image.ReadDiskTag(MediaTagType.SD_OCR).Length
2017-09-29 14:43:59 +01:00
};
break;
case MediaTagType.MMC_ExtendedCSD:
if(sidecar.BlockMedia[0].MultiMediaCard == null)
2018-06-22 08:08:38 +01:00
sidecar.BlockMedia[0].MultiMediaCard = new MultiMediaCardType();
2017-09-29 14:43:59 +01:00
sidecar.BlockMedia[0].MultiMediaCard.ExtendedCSD = new DumpType
{
2018-12-31 13:17:27 +00:00
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.MMC_ExtendedCSD))
.ToArray(),
2017-09-29 14:43:59 +01:00
Size = image.ReadDiskTag(MediaTagType.MMC_ExtendedCSD).Length
2017-08-08 14:18:31 +01:00
};
2017-08-08 13:40:32 +01:00
break;
case MediaTagType.USB_Descriptors:
2018-06-22 08:08:38 +01:00
if(sidecar.BlockMedia[0].USB == null) sidecar.BlockMedia[0].USB = new USBType();
sidecar.BlockMedia[0].USB.Descriptors = new DumpType
{
2018-12-31 13:17:27 +00:00
Checksums = Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.USB_Descriptors))
.ToArray(),
Size = image.ReadDiskTag(MediaTagType.USB_Descriptors).Length
};
break;
case MediaTagType.SCSI_MODESENSE_6:
2018-06-22 08:08:38 +01:00
if(sidecar.BlockMedia[0].SCSI == null) sidecar.BlockMedia[0].SCSI = new SCSIType();
sidecar.BlockMedia[0].SCSI.ModeSense = new DumpType
{
Checksums =
Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.SCSI_MODESENSE_6)).ToArray(),
Size = image.ReadDiskTag(MediaTagType.SCSI_MODESENSE_6).Length
};
break;
case MediaTagType.SCSI_MODESENSE_10:
2018-06-22 08:08:38 +01:00
if(sidecar.BlockMedia[0].SCSI == null) sidecar.BlockMedia[0].SCSI = new SCSIType();
sidecar.BlockMedia[0].SCSI.ModeSense10 = new DumpType
{
Checksums =
Checksum.GetChecksums(image.ReadDiskTag(MediaTagType.SCSI_MODESENSE_10)).ToArray(),
Size = image.ReadDiskTag(MediaTagType.SCSI_MODESENSE_10).Length
};
break;
2017-08-08 13:40:32 +01:00
}
// If there is only one track, and it's the same as the image file (e.g. ".iso" files), don't re-checksum.
if(image.Id == new Guid("12345678-AAAA-BBBB-CCCC-123456789000") &&
filterId == new Guid("12345678-AAAA-BBBB-CCCC-123456789000"))
sidecar.BlockMedia[0].ContentChecksums = sidecar.BlockMedia[0].Checksums;
2017-08-08 13:40:32 +01:00
else
{
Checksum contentChkWorker = new Checksum();
// For fast debugging, skip checksum
//goto skipImageChecksum;
uint sectorsToRead = 512;
ulong sectors = image.Info.Sectors;
ulong doneSectors = 0;
2017-08-08 13:40:32 +01:00
InitProgress2();
while(doneSectors < sectors)
{
byte[] sector;
if(sectors - doneSectors >= sectorsToRead)
2017-08-08 13:40:32 +01:00
{
sector = image.ReadSectors(doneSectors, sectorsToRead);
UpdateProgress2("Hashings sector {0} of {1}", (long)doneSectors, (long)sectors);
doneSectors += sectorsToRead;
}
else
{
sector = image.ReadSectors(doneSectors, (uint)(sectors - doneSectors));
UpdateProgress2("Hashings sector {0} of {1}", (long)doneSectors, (long)sectors);
doneSectors += sectors - doneSectors;
2017-08-08 13:40:32 +01:00
}
contentChkWorker.Update(sector);
}
// For fast debugging, skip checksum
//skipImageChecksum:
2017-08-08 13:40:32 +01:00
List<ChecksumType> cntChecksums = contentChkWorker.End();
sidecar.BlockMedia[0].ContentChecksums = cntChecksums.ToArray();
EndProgress2();
}
MediaType.MediaTypeToString(image.Info.MediaType, out string dskType, out string dskSubType);
sidecar.BlockMedia[0].DiskType = dskType;
2017-08-08 13:40:32 +01:00
sidecar.BlockMedia[0].DiskSubType = dskSubType;
Statistics.AddMedia(image.Info.MediaType, false);
2017-08-08 13:40:32 +01:00
sidecar.BlockMedia[0].Dimensions = Dimensions.DimensionsFromMediaType(image.Info.MediaType);
2017-08-08 13:40:32 +01:00
sidecar.BlockMedia[0].LogicalBlocks = (long)image.Info.Sectors;
sidecar.BlockMedia[0].LogicalBlockSize = (int)image.Info.SectorSize;
2017-08-08 13:40:32 +01:00
// TODO: Detect it
sidecar.BlockMedia[0].PhysicalBlockSize = (int)image.Info.SectorSize;
2017-08-08 13:40:32 +01:00
UpdateStatus("Checking filesystems...");
List<Partition> partitions = Partitions.GetAll(image);
Partitions.AddSchemesToStats(partitions);
sidecar.BlockMedia[0].FileSystemInformation = new PartitionType[1];
if(partitions.Count > 0)
{
sidecar.BlockMedia[0].FileSystemInformation = new PartitionType[partitions.Count];
for(int i = 0; i < partitions.Count; i++)
{
2017-08-08 14:18:31 +01:00
sidecar.BlockMedia[0].FileSystemInformation[i] = new PartitionType
{
Description = partitions[i].Description,
EndSector = (int)partitions[i].End,
Name = partitions[i].Name,
Sequence = (int)partitions[i].Sequence,
2017-08-08 14:18:31 +01:00
StartSector = (int)partitions[i].Start,
Type = partitions[i].Type
2017-08-08 14:18:31 +01:00
};
2017-08-08 13:40:32 +01:00
List<FileSystemType> lstFs = new List<FileSystemType>();
foreach(IFilesystem plugin in plugins.PluginsList.Values)
2017-08-08 13:40:32 +01:00
try
{
if(!plugin.Identify(image, partitions[i])) continue;
plugin.GetInformation(image, partitions[i], out _, encoding);
lstFs.Add(plugin.XmlFsType);
Statistics.AddFilesystem(plugin.XmlFsType.Type);
2017-08-08 13:40:32 +01:00
}
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
2017-08-08 13:40:32 +01:00
catch
#pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body
2017-08-08 13:40:32 +01:00
{
//DicConsole.DebugWriteLine("Create-sidecar command", "Plugin {0} crashed", _plugin.Name);
}
2017-12-19 20:33:03 +00:00
if(lstFs.Count > 0) sidecar.BlockMedia[0].FileSystemInformation[i].FileSystems = lstFs.ToArray();
2017-08-08 13:40:32 +01:00
}
}
else
{
sidecar.BlockMedia[0].FileSystemInformation[0] =
2018-06-22 08:08:38 +01:00
new PartitionType {StartSector = 0, EndSector = (int)(image.Info.Sectors - 1)};
2017-08-08 13:40:32 +01:00
Partition wholePart = new Partition
{
Name = "Whole device",
Length = image.Info.Sectors,
Size = image.Info.Sectors * image.Info.SectorSize
2017-08-08 13:40:32 +01:00
};
List<FileSystemType> lstFs = new List<FileSystemType>();
foreach(IFilesystem plugin in plugins.PluginsList.Values)
2017-08-08 13:40:32 +01:00
try
{
if(!plugin.Identify(image, wholePart)) continue;
plugin.GetInformation(image, wholePart, out _, encoding);
lstFs.Add(plugin.XmlFsType);
Statistics.AddFilesystem(plugin.XmlFsType.Type);
2017-08-08 13:40:32 +01:00
}
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
2017-08-08 13:40:32 +01:00
catch
#pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body
2017-08-08 13:40:32 +01:00
{
//DicConsole.DebugWriteLine("Create-sidecar command", "Plugin {0} crashed", _plugin.Name);
}
2017-12-19 20:33:03 +00:00
if(lstFs.Count > 0) sidecar.BlockMedia[0].FileSystemInformation[0].FileSystems = lstFs.ToArray();
2017-08-08 13:40:32 +01:00
}
if(image.Info.Cylinders > 0 && image.Info.Heads > 0 && image.Info.SectorsPerTrack > 0)
{
sidecar.BlockMedia[0].CylindersSpecified = true;
sidecar.BlockMedia[0].HeadsSpecified = true;
sidecar.BlockMedia[0].SectorsPerTrackSpecified = true;
sidecar.BlockMedia[0].Cylinders = image.Info.Cylinders;
sidecar.BlockMedia[0].Heads = image.Info.Heads;
sidecar.BlockMedia[0].SectorsPerTrack = image.Info.SectorsPerTrack;
}
if(image.Info.ReadableMediaTags.Contains(MediaTagType.ATA_IDENTIFY))
{
Identify.IdentifyDevice? ataId = Identify.Decode(image.ReadDiskTag(MediaTagType.ATA_IDENTIFY));
if(ataId.HasValue)
if(ataId.Value.CurrentCylinders > 0 && ataId.Value.CurrentHeads > 0 &&
2017-12-19 20:33:03 +00:00
ataId.Value.CurrentSectorsPerTrack > 0)
{
sidecar.BlockMedia[0].CylindersSpecified = true;
sidecar.BlockMedia[0].HeadsSpecified = true;
sidecar.BlockMedia[0].SectorsPerTrackSpecified = true;
sidecar.BlockMedia[0].Cylinders = ataId.Value.CurrentCylinders;
sidecar.BlockMedia[0].Heads = ataId.Value.CurrentHeads;
sidecar.BlockMedia[0].SectorsPerTrack = ataId.Value.CurrentSectorsPerTrack;
}
else if(ataId.Value.Cylinders > 0 && ataId.Value.Heads > 0 && ataId.Value.SectorsPerTrack > 0)
{
sidecar.BlockMedia[0].CylindersSpecified = true;
sidecar.BlockMedia[0].HeadsSpecified = true;
sidecar.BlockMedia[0].SectorsPerTrackSpecified = true;
sidecar.BlockMedia[0].Cylinders = ataId.Value.Cylinders;
sidecar.BlockMedia[0].Heads = ataId.Value.Heads;
sidecar.BlockMedia[0].SectorsPerTrack = ataId.Value.SectorsPerTrack;
}
}
2017-08-08 13:40:32 +01:00
if(image.DumpHardware != null) sidecar.BlockMedia[0].DumpHardwareArray = image.DumpHardware.ToArray();
// TODO: This is more of a hack, redo it planned for >4.0
string trkFormat = null;
2017-12-19 20:33:03 +00:00
switch(image.Info.MediaType)
{
2017-12-21 14:30:38 +00:00
case CommonTypes.MediaType.Apple32SS:
case CommonTypes.MediaType.Apple32DS:
trkFormat = "Apple GCR (DOS 3.2)";
break;
2017-12-21 14:30:38 +00:00
case CommonTypes.MediaType.Apple33SS:
case CommonTypes.MediaType.Apple33DS:
trkFormat = "Apple GCR (DOS 3.3)";
break;
2017-12-21 14:30:38 +00:00
case CommonTypes.MediaType.AppleSonySS:
case CommonTypes.MediaType.AppleSonyDS:
trkFormat = "Apple GCR (Sony)";
break;
2017-12-21 14:30:38 +00:00
case CommonTypes.MediaType.AppleFileWare:
trkFormat = "Apple GCR (Twiggy)";
break;
2017-12-21 14:30:38 +00:00
case CommonTypes.MediaType.DOS_525_SS_DD_9:
case CommonTypes.MediaType.DOS_525_DS_DD_8:
case CommonTypes.MediaType.DOS_525_DS_DD_9:
case CommonTypes.MediaType.DOS_525_HD:
case CommonTypes.MediaType.DOS_35_SS_DD_8:
case CommonTypes.MediaType.DOS_35_SS_DD_9:
case CommonTypes.MediaType.DOS_35_DS_DD_8:
case CommonTypes.MediaType.DOS_35_DS_DD_9:
case CommonTypes.MediaType.DOS_35_HD:
case CommonTypes.MediaType.DOS_35_ED:
case CommonTypes.MediaType.DMF:
case CommonTypes.MediaType.DMF_82:
case CommonTypes.MediaType.XDF_525:
case CommonTypes.MediaType.XDF_35:
case CommonTypes.MediaType.IBM53FD_256:
case CommonTypes.MediaType.IBM53FD_512:
case CommonTypes.MediaType.IBM53FD_1024:
case CommonTypes.MediaType.RX02:
case CommonTypes.MediaType.RX03:
case CommonTypes.MediaType.RX50:
case CommonTypes.MediaType.ACORN_525_SS_DD_40:
case CommonTypes.MediaType.ACORN_525_SS_DD_80:
case CommonTypes.MediaType.ACORN_525_DS_DD:
case CommonTypes.MediaType.ACORN_35_DS_DD:
case CommonTypes.MediaType.ACORN_35_DS_HD:
case CommonTypes.MediaType.ATARI_525_ED:
case CommonTypes.MediaType.ATARI_525_DD:
case CommonTypes.MediaType.ATARI_35_SS_DD:
case CommonTypes.MediaType.ATARI_35_DS_DD:
case CommonTypes.MediaType.ATARI_35_SS_DD_11:
case CommonTypes.MediaType.ATARI_35_DS_DD_11:
case CommonTypes.MediaType.DOS_525_SS_DD_8:
case CommonTypes.MediaType.NEC_8_DD:
case CommonTypes.MediaType.NEC_525_SS:
case CommonTypes.MediaType.NEC_525_DS:
case CommonTypes.MediaType.NEC_525_HD:
case CommonTypes.MediaType.NEC_35_HD_8:
case CommonTypes.MediaType.NEC_35_HD_15:
case CommonTypes.MediaType.NEC_35_TD:
case CommonTypes.MediaType.FDFORMAT_525_DD:
case CommonTypes.MediaType.FDFORMAT_525_HD:
case CommonTypes.MediaType.FDFORMAT_35_DD:
case CommonTypes.MediaType.FDFORMAT_35_HD:
case CommonTypes.MediaType.Apricot_35:
case CommonTypes.MediaType.CompactFloppy:
trkFormat = "IBM MFM";
break;
2017-12-21 14:30:38 +00:00
case CommonTypes.MediaType.ATARI_525_SD:
case CommonTypes.MediaType.NEC_8_SD:
case CommonTypes.MediaType.ACORN_525_SS_SD_40:
case CommonTypes.MediaType.ACORN_525_SS_SD_80:
case CommonTypes.MediaType.RX01:
case CommonTypes.MediaType.IBM23FD:
case CommonTypes.MediaType.IBM33FD_128:
case CommonTypes.MediaType.IBM33FD_256:
case CommonTypes.MediaType.IBM33FD_512:
case CommonTypes.MediaType.IBM43FD_128:
case CommonTypes.MediaType.IBM43FD_256:
trkFormat = "IBM FM";
break;
2017-12-21 14:30:38 +00:00
case CommonTypes.MediaType.CBM_35_DD:
trkFormat = "Commodore MFM";
break;
2017-12-21 14:30:38 +00:00
case CommonTypes.MediaType.CBM_AMIGA_35_HD:
case CommonTypes.MediaType.CBM_AMIGA_35_DD:
trkFormat = "Amiga MFM";
break;
2017-12-21 14:30:38 +00:00
case CommonTypes.MediaType.CBM_1540:
case CommonTypes.MediaType.CBM_1540_Ext:
case CommonTypes.MediaType.CBM_1571:
trkFormat = "Commodore GCR";
break;
2017-12-21 14:30:38 +00:00
case CommonTypes.MediaType.SHARP_525_9:
case CommonTypes.MediaType.SHARP_35_9: break;
case CommonTypes.MediaType.ECMA_99_15:
case CommonTypes.MediaType.ECMA_99_26:
case CommonTypes.MediaType.ECMA_99_8:
trkFormat = "ISO MFM";
break;
2017-12-21 14:30:38 +00:00
case CommonTypes.MediaType.ECMA_54:
case CommonTypes.MediaType.ECMA_59:
case CommonTypes.MediaType.ECMA_66:
case CommonTypes.MediaType.ECMA_69_8:
case CommonTypes.MediaType.ECMA_69_15:
case CommonTypes.MediaType.ECMA_69_26:
case CommonTypes.MediaType.ECMA_70:
case CommonTypes.MediaType.ECMA_78:
case CommonTypes.MediaType.ECMA_78_2:
trkFormat = "ISO FM";
break;
default:
trkFormat = "Unknown";
break;
}
#region SuperCardPro
string scpFilePath = Path.Combine(Path.GetDirectoryName(imagePath),
2017-12-19 20:33:03 +00:00
Path.GetFileNameWithoutExtension(imagePath) + ".scp");
if(File.Exists(scpFilePath))
{
SuperCardPro scpImage = new SuperCardPro();
ZZZNoFilter scpFilter = new ZZZNoFilter();
scpFilter.Open(scpFilePath);
if(image.Info.Heads <= 2 && scpImage.Identify(scpFilter))
{
try { scpImage.Open(scpFilter); }
2017-12-19 20:33:03 +00:00
catch(NotImplementedException) { }
2018-06-22 08:08:38 +01:00
if(image.Info.Heads == 2 && scpImage.Header.heads == 0 || image.Info.Heads == 1 &&
(scpImage.Header.heads == 1 || scpImage.Header.heads == 2))
if(scpImage.Header.end + 1 >= image.Info.Cylinders)
{
List<BlockTrackType> scpBlockTrackTypes = new List<BlockTrackType>();
long currentSector = 0;
Stream scpStream = scpFilter.GetDataForkStream();
for(byte t = scpImage.Header.start; t <= scpImage.Header.end; t++)
{
BlockTrackType scpBlockTrackType = new BlockTrackType
{
Cylinder = t / image.Info.Heads,
Head = t % image.Info.Heads,
2018-06-22 08:08:38 +01:00
Image = new ImageType
{
format = scpImage.Format,
Value = Path.GetFileName(scpFilePath),
offset = scpImage.Header.offsets[t]
}
};
if(scpBlockTrackType.Cylinder < image.Info.Cylinders)
{
scpBlockTrackType.StartSector = currentSector;
currentSector += image.Info.SectorsPerTrack;
scpBlockTrackType.EndSector = currentSector - 1;
scpBlockTrackType.Sectors = image.Info.SectorsPerTrack;
scpBlockTrackType.BytesPerSector = (int)image.Info.SectorSize;
scpBlockTrackType.Format = trkFormat;
}
if(scpImage.ScpTracks.TryGetValue(t, out SuperCardPro.TrackHeader scpTrack))
{
byte[] trackContents =
2018-06-22 08:08:38 +01:00
new byte[scpTrack.Entries.Last().dataOffset +
scpTrack.Entries.Last().trackLength - scpImage.Header.offsets[t] + 1];
scpStream.Position = scpImage.Header.offsets[t];
scpStream.Read(trackContents, 0, trackContents.Length);
scpBlockTrackType.Size = trackContents.Length;
scpBlockTrackType.Checksums = Checksum.GetChecksums(trackContents).ToArray();
}
scpBlockTrackTypes.Add(scpBlockTrackType);
}
sidecar.BlockMedia[0].Track =
scpBlockTrackTypes.OrderBy(t => t.Cylinder).ThenBy(t => t.Head).ToArray();
}
else
2017-12-19 20:33:03 +00:00
DicConsole
.ErrorWriteLine("SuperCardPro image do not contain same number of tracks ({0}) than disk image ({1}), ignoring...",
scpImage.Header.end + 1, image.Info.Cylinders);
else
2017-12-19 20:33:03 +00:00
DicConsole
.ErrorWriteLine("SuperCardPro image do not contain same number of heads ({0}) than disk image ({1}), ignoring...",
2, image.Info.Heads);
}
}
#endregion
2017-12-19 20:33:03 +00:00
#region KryoFlux
2018-06-22 08:08:38 +01:00
string kfFile = null;
string basename = Path.Combine(Path.GetDirectoryName(imagePath),
2017-12-19 20:33:03 +00:00
Path.GetFileNameWithoutExtension(imagePath));
bool kfDir = false;
if(Directory.Exists(basename))
{
string[] possibleKfStarts = Directory.GetFiles(basename, "*.raw", SearchOption.TopDirectoryOnly);
if(possibleKfStarts.Length > 0)
{
kfFile = possibleKfStarts[0];
kfDir = true;
}
}
2018-06-22 08:08:38 +01:00
else if(File.Exists(basename + "00.0.raw")) kfFile = basename + "00.0.raw";
else if(File.Exists(basename + "00.1.raw")) kfFile = basename + "00.1.raw";
if(kfFile != null)
{
KryoFlux kfImage = new KryoFlux();
2017-12-21 14:30:38 +00:00
ZZZNoFilter kfFilter = new ZZZNoFilter();
kfFilter.Open(kfFile);
if(image.Info.Heads <= 2 && kfImage.Identify(kfFilter))
{
try { kfImage.Open(kfFilter); }
2017-12-19 20:33:03 +00:00
catch(NotImplementedException) { }
2018-06-22 08:08:38 +01:00
if(kfImage.Info.Heads == image.Info.Heads)
if(kfImage.Info.Cylinders >= image.Info.Cylinders)
{
List<BlockTrackType> kfBlockTrackTypes = new List<BlockTrackType>();
2017-12-19 20:33:03 +00:00
long currentSector = 0;
foreach(KeyValuePair<byte, IFilter> kvp in kfImage.tracks)
{
BlockTrackType kfBlockTrackType = new BlockTrackType
{
Cylinder = kvp.Key / image.Info.Heads,
Head = kvp.Key % image.Info.Heads,
2018-06-22 08:08:38 +01:00
Image = new ImageType
{
format = kfImage.Format,
2018-06-22 08:08:38 +01:00
Value = kfDir
? Path
.Combine(Path.GetFileName(Path.GetDirectoryName(kvp.Value.GetBasePath())),
kvp.Value.GetFilename())
: kvp.Value.GetFilename(),
offset = 0
}
};
if(kfBlockTrackType.Cylinder < image.Info.Cylinders)
{
kfBlockTrackType.StartSector = currentSector;
currentSector += image.Info.SectorsPerTrack;
kfBlockTrackType.EndSector = currentSector - 1;
kfBlockTrackType.Sectors = image.Info.SectorsPerTrack;
kfBlockTrackType.BytesPerSector = (int)image.Info.SectorSize;
kfBlockTrackType.Format = trkFormat;
}
Stream kfStream = kvp.Value.GetDataForkStream();
byte[] trackContents = new byte[kfStream.Length];
2018-06-22 08:08:38 +01:00
kfStream.Position = 0;
kfStream.Read(trackContents, 0, trackContents.Length);
kfBlockTrackType.Size = trackContents.Length;
kfBlockTrackType.Checksums = Checksum.GetChecksums(trackContents).ToArray();
kfBlockTrackTypes.Add(kfBlockTrackType);
}
sidecar.BlockMedia[0].Track =
kfBlockTrackTypes.OrderBy(t => t.Cylinder).ThenBy(t => t.Head).ToArray();
}
else
2017-12-19 20:33:03 +00:00
DicConsole
.ErrorWriteLine("KryoFlux image do not contain same number of tracks ({0}) than disk image ({1}), ignoring...",
kfImage.Info.Cylinders, image.Info.Cylinders);
else
2017-12-19 20:33:03 +00:00
DicConsole
.ErrorWriteLine("KryoFluximage do not contain same number of heads ({0}) than disk image ({1}), ignoring...",
kfImage.Info.Heads, image.Info.Heads);
}
}
#endregion
#region DiscFerret
string dfiFilePath = Path.Combine(Path.GetDirectoryName(imagePath),
2017-12-19 20:33:03 +00:00
Path.GetFileNameWithoutExtension(imagePath) + ".dfi");
if(!File.Exists(dfiFilePath)) return;
DiscFerret dfiImage = new DiscFerret();
2017-12-21 14:30:38 +00:00
ZZZNoFilter dfiFilter = new ZZZNoFilter();
dfiFilter.Open(dfiFilePath);
if(!dfiImage.Identify(dfiFilter)) return;
try { dfiImage.Open(dfiFilter); }
catch(NotImplementedException) { }
2018-06-22 08:08:38 +01:00
if(image.Info.Heads == dfiImage.Info.Heads)
if(dfiImage.Info.Cylinders >= image.Info.Cylinders)
{
List<BlockTrackType> dfiBlockTrackTypes = new List<BlockTrackType>();
long currentSector = 0;
Stream dfiStream = dfiFilter.GetDataForkStream();
foreach(int t in dfiImage.TrackOffsets.Keys)
{
BlockTrackType dfiBlockTrackType = new BlockTrackType
{
Cylinder = t / image.Info.Heads,
Head = t % image.Info.Heads,
Image = new ImageType {format = dfiImage.Format, Value = Path.GetFileName(dfiFilePath)}
};
if(dfiBlockTrackType.Cylinder < image.Info.Cylinders)
{
dfiBlockTrackType.StartSector = currentSector;
currentSector += image.Info.SectorsPerTrack;
dfiBlockTrackType.EndSector = currentSector - 1;
dfiBlockTrackType.Sectors = image.Info.SectorsPerTrack;
dfiBlockTrackType.BytesPerSector = (int)image.Info.SectorSize;
dfiBlockTrackType.Format = trkFormat;
}
if(dfiImage.TrackOffsets.TryGetValue(t, out long offset) &&
dfiImage.TrackLengths.TryGetValue(t, out long length))
{
dfiBlockTrackType.Image.offset = offset;
2018-06-22 08:08:38 +01:00
byte[] trackContents = new byte[length];
dfiStream.Position = offset;
dfiStream.Read(trackContents, 0, trackContents.Length);
dfiBlockTrackType.Size = trackContents.Length;
dfiBlockTrackType.Checksums = Checksum.GetChecksums(trackContents).ToArray();
}
dfiBlockTrackTypes.Add(dfiBlockTrackType);
}
sidecar.BlockMedia[0].Track =
dfiBlockTrackTypes.OrderBy(t => t.Cylinder).ThenBy(t => t.Head).ToArray();
}
else
DicConsole
.ErrorWriteLine("DiscFerret image do not contain same number of tracks ({0}) than disk image ({1}), ignoring...",
dfiImage.Info.Cylinders, image.Info.Cylinders);
else
DicConsole
.ErrorWriteLine("DiscFerret image do not contain same number of heads ({0}) than disk image ({1}), ignoring...",
dfiImage.Info.Heads, image.Info.Heads);
#endregion
2017-12-19 20:33:03 +00:00
// TODO: Implement support for getting CHS from SCSI mode pages
2017-08-08 13:40:32 +01:00
}
}
2017-12-19 20:33:03 +00:00
}