diff --git a/DiscImageChef.Core/Sidecar/BlockMedia.cs b/DiscImageChef.Core/Sidecar/BlockMedia.cs index 9bd88209..56f391a7 100644 --- a/DiscImageChef.Core/Sidecar/BlockMedia.cs +++ b/DiscImageChef.Core/Sidecar/BlockMedia.cs @@ -419,31 +419,24 @@ namespace DiscImageChef.Core } // TODO: This is more of a hack, redo it planned for >4.0 - #region SuperCardPro - string scpFilePath = Path.Combine(Path.GetDirectoryName(imagePath), - Path.GetFileNameWithoutExtension(imagePath) + ".scp"); - ImagePlugins.SuperCardPro scpImage = new SuperCardPro(); - Filters.ZZZNoFilter scpFilter = new ZZZNoFilter(); - scpFilter.Open(scpFilePath); - - string scpFormat = null; + string trkFormat = null; switch(image.ImageInfo.mediaType) { case MediaType.Apple32SS: case MediaType.Apple32DS: - scpFormat = "Apple GCR (DOS 3.2)"; + trkFormat = "Apple GCR (DOS 3.2)"; break; case MediaType.Apple33SS: case MediaType.Apple33DS: - scpFormat = "Apple GCR (DOS 3.3)"; + trkFormat = "Apple GCR (DOS 3.3)"; break; case MediaType.AppleSonySS: case MediaType.AppleSonyDS: - scpFormat = "Apple GCR (Sony)"; + trkFormat = "Apple GCR (Sony)"; break; case MediaType.AppleFileWare: - scpFormat = "Apple GCR (Twiggy)"; + trkFormat = "Apple GCR (Twiggy)"; break; case MediaType.DOS_525_SS_DD_9: case MediaType.DOS_525_DS_DD_8: @@ -490,7 +483,7 @@ namespace DiscImageChef.Core case MediaType.FDFORMAT_35_HD: case MediaType.Apricot_35: case MediaType.CompactFloppy: - scpFormat = "IBM MFM"; + trkFormat = "IBM MFM"; break; case MediaType.ATARI_525_SD: case MediaType.NEC_8_SD: @@ -503,19 +496,19 @@ namespace DiscImageChef.Core case MediaType.IBM33FD_512: case MediaType.IBM43FD_128: case MediaType.IBM43FD_256: - scpFormat = "IBM FM"; + trkFormat = "IBM FM"; break; case MediaType.CBM_35_DD: - scpFormat = "Commodore MFM"; + trkFormat = "Commodore MFM"; break; case MediaType.CBM_AMIGA_35_HD: case MediaType.CBM_AMIGA_35_DD: - scpFormat = "Amiga MFM"; + trkFormat = "Amiga MFM"; break; case MediaType.CBM_1540: case MediaType.CBM_1540_Ext: case MediaType.CBM_1571: - scpFormat = "Commodore GCR"; + trkFormat = "Commodore GCR"; break; case MediaType.SHARP_525: case MediaType.SHARP_525_9: @@ -529,7 +522,7 @@ namespace DiscImageChef.Core case MediaType.ECMA_125: case MediaType.ECMA_147: case MediaType.ECMA_99_8: - scpFormat = "ISO MFM"; + trkFormat = "ISO MFM"; break; case MediaType.ECMA_54: case MediaType.ECMA_59: @@ -540,78 +533,186 @@ namespace DiscImageChef.Core case MediaType.ECMA_70: case MediaType.ECMA_78: case MediaType.ECMA_78_2: - scpFormat = "ISO FM"; + trkFormat = "ISO FM"; break; default: - scpFormat = "Unknown"; + trkFormat = "Unknown"; break; } - if(image.ImageInfo.heads <= 2 && File.Exists(scpFilePath) && scpImage.IdentifyImage(scpFilter)) + #region SuperCardPro + string scpFilePath = Path.Combine(Path.GetDirectoryName(imagePath), + Path.GetFileNameWithoutExtension(imagePath) + ".scp"); + + if(File.Exists(scpFilePath)) { - try - { - scpImage.OpenImage(scpFilter); - } - catch(NotImplementedException) - { - } + ImagePlugins.SuperCardPro scpImage = new SuperCardPro(); + Filters.ZZZNoFilter scpFilter = new ZZZNoFilter(); + scpFilter.Open(scpFilePath); - if((image.ImageInfo.heads == 2 && scpImage.header.heads == 0) || - (image.ImageInfo.heads == 1 && (scpImage.header.heads == 1 || scpImage.header.heads == 2))) + if(image.ImageInfo.heads <= 2 && scpImage.IdentifyImage(scpFilter)) { - if(scpImage.header.end + 1 >= image.ImageInfo.cylinders) + + try { - ImageType scpImageType = new ImageType(); - scpImageType.format = "SuperCardPro"; - scpImageType.Value = Path.GetFileName(scpFilePath); - List scpBlockTrackTypes = new List(); - long currentSector = 0; - Stream scpStream = scpFilter.GetDataForkStream(); + scpImage.OpenImage(scpFilter); + } + catch(NotImplementedException) + { + } - for(byte t = scpImage.header.start; t <= scpImage.header.end; t++) + if((image.ImageInfo.heads == 2 && scpImage.header.heads == 0) || + (image.ImageInfo.heads == 1 && (scpImage.header.heads == 1 || scpImage.header.heads == 2))) + { + if(scpImage.header.end + 1 >= image.ImageInfo.cylinders) { - BlockTrackType scpBlockTrackType = new BlockTrackType(); - scpBlockTrackType.Cylinder = t / image.ImageInfo.heads; - scpBlockTrackType.Head = t % image.ImageInfo.heads; - scpBlockTrackType.Image = scpImageType; - scpBlockTrackType.Image.offset = scpImage.header.offsets[t]; + List scpBlockTrackTypes = new List(); + long currentSector = 0; + Stream scpStream = scpFilter.GetDataForkStream(); - if(scpBlockTrackType.Cylinder < image.ImageInfo.cylinders) + for(byte t = scpImage.header.start; t <= scpImage.header.end; t++) { - scpBlockTrackType.StartSector = currentSector; - currentSector += image.ImageInfo.sectorsPerTrack; - scpBlockTrackType.EndSector = currentSector - 1; - scpBlockTrackType.Sectors = image.ImageInfo.sectorsPerTrack; - scpBlockTrackType.BytesPerSector = (int)image.ImageInfo.sectorSize; - scpBlockTrackType.Format = scpFormat; + BlockTrackType scpBlockTrackType = new BlockTrackType(); + scpBlockTrackType.Cylinder = t / image.ImageInfo.heads; + scpBlockTrackType.Head = t % image.ImageInfo.heads; + scpBlockTrackType.Image = new ImageType(); + scpBlockTrackType.Image.format = scpImage.GetImageFormat(); + scpBlockTrackType.Image.Value = Path.GetFileName(scpFilePath); + scpBlockTrackType.Image.offset = scpImage.header.offsets[t]; + + if(scpBlockTrackType.Cylinder < image.ImageInfo.cylinders) + { + scpBlockTrackType.StartSector = currentSector; + currentSector += image.ImageInfo.sectorsPerTrack; + scpBlockTrackType.EndSector = currentSector - 1; + scpBlockTrackType.Sectors = image.ImageInfo.sectorsPerTrack; + scpBlockTrackType.BytesPerSector = (int)image.ImageInfo.sectorSize; + scpBlockTrackType.Format = trkFormat; + } + + if(scpImage.tracks.TryGetValue(t, out SuperCardPro.TrackHeader scpTrack)) + { + byte[] trackContents = + 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); } - if(scpImage.tracks.TryGetValue(t, out SuperCardPro.TrackHeader scpTrack)) - { - byte[] trackContents = - 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(); } - - sidecar.BlockMedia[0].Track = - scpBlockTrackTypes.OrderBy(t => t.Cylinder).ThenBy(t => t.Head).ToArray(); + else + DicConsole.ErrorWriteLine( + "SuperCardPro image do not contain same number of tracks ({0}) than disk image ({1}), ignoring...", + scpImage.header.end + 1, image.ImageInfo.cylinders); } else - DicConsole.ErrorWriteLine("SuperCardPro image do not contain same number of tracks ({0}) than disk image ({1}), ignoring...", scpImage.header.end + 1, image.ImageInfo.cylinders); + DicConsole.ErrorWriteLine( + "SuperCardPro image do not contain same number of heads ({0}) than disk image ({1}), ignoring...", + 2, image.ImageInfo.heads); } - else - DicConsole.ErrorWriteLine("SuperCardPro image do not contain same number of heads ({0}) than disk image ({1}), ignoring...", 2, image.ImageInfo.heads); } #endregion + #region KryoFlux + string kfFile = null; + string basename = Path.Combine(Path.GetDirectoryName(imagePath), + 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; + } + } + 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) + { + ImagePlugins.KryoFlux kfImage = new KryoFlux(); + Filters.ZZZNoFilter kfFilter = new ZZZNoFilter(); + kfFilter.Open(kfFile); + if(image.ImageInfo.heads <= 2 && kfImage.IdentifyImage(kfFilter)) + { + try + { + kfImage.OpenImage(kfFilter); + } + catch(NotImplementedException) + { + } + + if(kfImage.ImageInfo.heads == image.ImageInfo.heads) + { + if(kfImage.ImageInfo.cylinders >= image.ImageInfo.cylinders) + { + List kfBlockTrackTypes = new List(); + + long currentSector = 0; + + foreach(KeyValuePair kvp in kfImage.tracks) + { + BlockTrackType kfBlockTrackType = new BlockTrackType(); + kfBlockTrackType.Cylinder = kvp.Key / image.ImageInfo.heads; + kfBlockTrackType.Head = kvp.Key % image.ImageInfo.heads; + kfBlockTrackType.Image = new ImageType(); + kfBlockTrackType.Image.format = kfImage.GetImageFormat(); + kfBlockTrackType.Image.Value = + kfDir + ? Path.Combine(Path.GetFileName(Path.GetDirectoryName(kvp.Value.GetBasePath())), kvp.Value.GetFilename()) + : kvp.Value.GetFilename(); + kfBlockTrackType.Image.offset = 0; + + if(kfBlockTrackType.Cylinder < image.ImageInfo.cylinders) + { + kfBlockTrackType.StartSector = currentSector; + currentSector += image.ImageInfo.sectorsPerTrack; + kfBlockTrackType.EndSector = currentSector - 1; + kfBlockTrackType.Sectors = image.ImageInfo.sectorsPerTrack; + kfBlockTrackType.BytesPerSector = (int)image.ImageInfo.sectorSize; + kfBlockTrackType.Format = trkFormat; + } + + Stream kfStream = kvp.Value.GetDataForkStream(); + byte[] trackContents = new byte[kfStream.Length]; + 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 + DicConsole.ErrorWriteLine( + "KryoFlux image do not contain same number of tracks ({0}) than disk image ({1}), ignoring...", + kfImage.ImageInfo.cylinders, image.ImageInfo.cylinders); + } + else + DicConsole.ErrorWriteLine( + "KryoFluximage do not contain same number of heads ({0}) than disk image ({1}), ignoring...", + kfImage.ImageInfo.heads, image.ImageInfo.heads); + } + } + #endregion + // TODO: Implement support for getting CHS from SCSI mode pages } } diff --git a/DiscImageChef.DiscImages/DiscImageChef.DiscImages.csproj b/DiscImageChef.DiscImages/DiscImageChef.DiscImages.csproj index 464c1c21..036108d9 100644 --- a/DiscImageChef.DiscImages/DiscImageChef.DiscImages.csproj +++ b/DiscImageChef.DiscImages/DiscImageChef.DiscImages.csproj @@ -51,6 +51,7 @@ + diff --git a/DiscImageChef.DiscImages/KryoFlux.cs b/DiscImageChef.DiscImages/KryoFlux.cs new file mode 100644 index 00000000..1ddeb3cc --- /dev/null +++ b/DiscImageChef.DiscImages/KryoFlux.cs @@ -0,0 +1,598 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : KryoFlux.cs +// Author(s) : Natalia Portillo +// +// Component : Disc image plugins. +// +// --[ Description ] ---------------------------------------------------------- +// +// Manages KryoFlux disk images. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2017 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using DiscImageChef.CommonTypes; +using DiscImageChef.Console; +using DiscImageChef.Filters; + +namespace DiscImageChef.ImagePlugins +{ + public class KryoFlux : ImagePlugin + { + #region Internal Structures + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct OobBlock + { + public BlockIds blockId; + public OobTypes blockType; + public ushort length; + } + #endregion Internal Structures + + #region Internal Constants + public enum BlockIds : byte + { + Flux2 = 0x00, + Flux2_1 = 0x01, + Flux2_2 = 0x02, + Flux2_3 = 0x03, + Flux2_4 = 0x04, + Flux2_5 = 0x05, + Flux2_6 = 0x06, + Flux2_7 = 0x07, + Nop1 = 0x08, + Nop2 = 0x09, + Nop3 = 0x0A, + Ovl16 = 0x0B, + Flux3 = 0x0C, + Oob = 0x0D + } + + public enum OobTypes : byte + { + Invalid = 0x00, + StreamInfo = 0x01, + Index = 0x02, + StreamEnd = 0x03, + KFInfo = 0x04, + EOF = 0x0D + } + + const string hostDate = "host_date"; + const string hostTime = "host_time"; + const string kfName = "name"; + const string kfVersion= "version"; + const string kfDate = "date"; + const string kfTime = "time"; + const string kfHwId = "hwid"; + const string kfHwRv = "hwrv"; + const string kfSck = "sck"; + const string kfIck = "ick"; + #endregion Internal Constants + + #region Internal variables + // TODO: These variables have been made public so create-sidecar can access to this information until I define an API >4.0 + public SortedDictionary tracks; + #endregion Internal variables + + public KryoFlux() + { + Name = "KryoFlux STREAM"; + PluginUUID = new Guid("4DBC95E4-93EE-4F7A-9492-919887E60EFE"); + ImageInfo = new ImageInfo() + { + readableSectorTags = new List(), + readableMediaTags = new List(), + imageHasPartitions = false, + imageHasSessions = false, + imageVersion = null, + imageApplication = null, + imageApplicationVersion = null, + imageCreator = null, + imageComments = null, + mediaManufacturer = null, + mediaModel = null, + mediaSerialNumber = null, + mediaBarcode = null, + mediaPartNumber = null, + mediaSequence = 0, + lastMediaSequence = 0, + driveManufacturer = null, + driveModel = null, + driveSerialNumber = null, + driveFirmwareRevision = null + }; + } + + #region Public methods + public override bool IdentifyImage(Filter imageFilter) + { + OobBlock header = new OobBlock(); + Stream stream = imageFilter.GetDataForkStream(); + stream.Seek(0, SeekOrigin.Begin); + if(stream.Length < Marshal.SizeOf(header)) + return false; + + byte[] hdr = new byte[Marshal.SizeOf(header)]; + stream.Read(hdr, 0, Marshal.SizeOf(header)); + + IntPtr hdrPtr = Marshal.AllocHGlobal(Marshal.SizeOf(header)); + Marshal.Copy(hdr, 0, hdrPtr, Marshal.SizeOf(header)); + header = (OobBlock)Marshal.PtrToStructure(hdrPtr, typeof(OobBlock)); + Marshal.FreeHGlobal(hdrPtr); + + OobBlock footer = new OobBlock(); + stream.Seek(-Marshal.SizeOf(footer), SeekOrigin.End); + + hdr = new byte[Marshal.SizeOf(footer)]; + stream.Read(hdr, 0, Marshal.SizeOf(footer)); + + hdrPtr = Marshal.AllocHGlobal(Marshal.SizeOf(footer)); + Marshal.Copy(hdr, 0, hdrPtr, Marshal.SizeOf(footer)); + footer = (OobBlock)Marshal.PtrToStructure(hdrPtr, typeof(OobBlock)); + Marshal.FreeHGlobal(hdrPtr); + + return header.blockId == BlockIds.Oob && header.blockType == OobTypes.KFInfo && + footer.blockId == BlockIds.Oob && footer.blockType == OobTypes.EOF && footer.length == 0x0D0D; + } + + public override bool OpenImage(Filter imageFilter) + { + OobBlock header = new OobBlock(); + Stream stream = imageFilter.GetDataForkStream(); + stream.Seek(0, SeekOrigin.Begin); + if(stream.Length < Marshal.SizeOf(header)) + return false; + + byte[] hdr = new byte[Marshal.SizeOf(header)]; + stream.Read(hdr, 0, Marshal.SizeOf(header)); + + IntPtr hdrPtr = Marshal.AllocHGlobal(Marshal.SizeOf(header)); + Marshal.Copy(hdr, 0, hdrPtr, Marshal.SizeOf(header)); + header = (OobBlock)Marshal.PtrToStructure(hdrPtr, typeof(OobBlock)); + Marshal.FreeHGlobal(hdrPtr); + + OobBlock footer = new OobBlock(); + stream.Seek(-Marshal.SizeOf(footer), SeekOrigin.End); + + hdr = new byte[Marshal.SizeOf(footer)]; + stream.Read(hdr, 0, Marshal.SizeOf(footer)); + + hdrPtr = Marshal.AllocHGlobal(Marshal.SizeOf(footer)); + Marshal.Copy(hdr, 0, hdrPtr, Marshal.SizeOf(footer)); + footer = (OobBlock)Marshal.PtrToStructure(hdrPtr, typeof(OobBlock)); + Marshal.FreeHGlobal(hdrPtr); + + if(header.blockId != BlockIds.Oob || header.blockType != OobTypes.KFInfo || + footer.blockId != BlockIds.Oob || footer.blockType != OobTypes.EOF || + footer.length != 0x0D0D) return false; + + #region TODO: This is supposing NoFilter, shouldn't + tracks = new SortedDictionary(); + byte step = 1; + byte heads = 2; + bool topHead = false; + string basename = Path.Combine(imageFilter.GetParentFolder(), + imageFilter.GetFilename().Substring(0, imageFilter.GetFilename().Length - 8)); + + for(byte t = 0; t < 166; t += step) + { + int cylinder = t / heads; + int head = topHead ? 1 : t % heads; + string trackfile = Directory.Exists(basename) + ? Path.Combine(basename, string.Format("{0:D2}.{1:D1}.raw", cylinder, head)) + : string.Format("{0}{1:D2}.{2:D1}.raw", basename, cylinder, head); + + if(!File.Exists(trackfile)) + { + if(cylinder == 0) + { + if(head == 0) + { + DicConsole.DebugWriteLine("KryoFlux plugin", "Cannot find cyl 0 hd 0, supposing only top head was dumped"); + topHead = true; + heads = 1; + continue; + } + + DicConsole.DebugWriteLine("KryoFlux plugin", "Cannot find cyl 0 hd 1, supposing only bottom head was dumped"); + heads = 1; + continue; + } + else if(cylinder == 1) + { + DicConsole.DebugWriteLine("KryoFlux plugin", "Cannot find cyl 1, supposing double stepping"); + step = 2; + continue; + } + else + { + DicConsole.DebugWriteLine("KryoFlux plugin", "Arrived end of disk at cylinder {0}", cylinder); + step = 2; + break; + } + } + + ZZZNoFilter trackFilter = new ZZZNoFilter(); + trackFilter.Open(trackfile); + if(!trackFilter.IsOpened()) + throw new IOException("Could not open KryoFlux track file."); + + ImageInfo.imageCreationTime = DateTime.MaxValue; + ImageInfo.imageLastModificationTime = DateTime.MinValue; + + Stream trackStream = trackFilter.GetDataForkStream(); + while(trackStream.Position < trackStream.Length) + { + byte blockId = (byte)trackStream.ReadByte(); + switch(blockId) + { + case (byte)BlockIds.Oob: + { + trackStream.Position--; + OobBlock oobBlk = new OobBlock(); + + byte[] oob = new byte[Marshal.SizeOf(oobBlk)]; + trackStream.Read(oob, 0, Marshal.SizeOf(oobBlk)); + + IntPtr oobPtr = Marshal.AllocHGlobal(Marshal.SizeOf(oobBlk)); + Marshal.Copy(oob, 0, oobPtr, Marshal.SizeOf(oobBlk)); + oobBlk = (OobBlock)Marshal.PtrToStructure(oobPtr, typeof(OobBlock)); + Marshal.FreeHGlobal(oobPtr); + + if(oobBlk.blockType == OobTypes.EOF) + { + trackStream.Position = trackStream.Length; + break; + } + + if(oobBlk.blockType != OobTypes.KFInfo) + { + trackStream.Position += oobBlk.length; + break; + } + + byte[] kfinfo = new byte[oobBlk.length]; + trackStream.Read(kfinfo, 0, oobBlk.length); + string kfinfoStr = StringHandlers.CToString(kfinfo); + string[] lines = kfinfoStr.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries); + + DateTime blockDate = DateTime.Now; + DateTime blockTime = DateTime.Now; + bool foundDate = false; + + foreach(string line in lines) + { + string[] kvp = line.Split('='); + if(kvp.Length != 2) + continue; + + kvp[0] = kvp[0].Trim(); + kvp[1] = kvp[1].Trim(); + DicConsole.DebugWriteLine("KryoFlux plugin", "\"{0}\" = \"{1}\"", kvp[0], kvp[1]); + + if(kvp[0] == hostDate) + { + if(DateTime.TryParseExact(kvp[1], "yyyy.MM.dd", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, + out blockDate)) + foundDate = true; + } + else if(kvp[0] == hostTime) + { + DateTime.TryParseExact(kvp[1], "HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, + out blockTime); + } + else if(kvp[0] == kfName) + ImageInfo.imageApplication = kvp[1]; + else if(kvp[0] == kfVersion) + ImageInfo.imageApplicationVersion = kvp[1]; + } + + if(foundDate) + { + DateTime blockTimestamp = new DateTime(blockDate.Year, blockDate.Month, blockDate.Day, + blockTime.Hour, blockTime.Minute, blockTime.Second); + DicConsole.DebugWriteLine("KryoFlux plugin", "Found timestamp: {0}", blockTimestamp); + if(blockTimestamp < ImageInfo.imageCreationTime) + ImageInfo.imageCreationTime = blockTimestamp; + if(blockTimestamp > ImageInfo.imageLastModificationTime) + ImageInfo.imageLastModificationTime= blockTimestamp; + } + + break; + } + case (byte)BlockIds.Flux2: + case (byte)BlockIds.Flux2_1: + case (byte)BlockIds.Flux2_2: + case (byte)BlockIds.Flux2_3: + case (byte)BlockIds.Flux2_4: + case (byte)BlockIds.Flux2_5: + case (byte)BlockIds.Flux2_6: + case (byte)BlockIds.Flux2_7: + case (byte)BlockIds.Nop2: + trackStream.Position++; + continue; + case (byte)BlockIds.Nop3: + case (byte)BlockIds.Flux3: + trackStream.Position += 2; + continue; + default: + continue; + } + } + + tracks.Add(t, trackFilter); + } + + ImageInfo.heads = heads; + ImageInfo.cylinders = (uint)(tracks.Count / heads); + + #endregion TODO: This is supposing NoFilter, shouldn't + + throw new NotImplementedException("Flux decoding is not yet implemented."); + } + + public override bool ImageHasPartitions() + { + return ImageInfo.imageHasPartitions; + } + + public override ulong GetImageSize() + { + return ImageInfo.imageSize; + } + + public override ulong GetSectors() + { + return ImageInfo.sectors; + } + + public override uint GetSectorSize() + { + return ImageInfo.sectorSize; + } + + public override byte[] ReadDiskTag(MediaTagType tag) + { + throw new NotImplementedException("Flux decoding is not yet implemented."); + } + + public override byte[] ReadSector(ulong sectorAddress) + { + return ReadSectors(sectorAddress, 1); + } + + public override byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag) + { + throw new NotImplementedException("Flux decoding is not yet implemented."); + } + + public override byte[] ReadSectors(ulong sectorAddress, uint length) + { + throw new NotImplementedException("Flux decoding is not yet implemented."); + } + + public override byte[] ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag) + { + throw new NotImplementedException("Flux decoding is not yet implemented."); + } + + public override byte[] ReadSectorLong(ulong sectorAddress) + { + throw new NotImplementedException("Flux decoding is not yet implemented."); + } + + public override byte[] ReadSectorLong(ulong sectorAddress, uint track) + { + throw new FeatureUnsupportedImageException("Feature not supported by image format"); + } + + public override byte[] ReadSectorsLong(ulong sectorAddress, uint length) + { + throw new NotImplementedException("Flux decoding is not yet implemented."); + } + + public override string GetImageFormat() + { + return "KryoFlux STREAM"; + } + + public override string GetImageVersion() + { + return ImageInfo.imageVersion; + } + + public override string GetImageApplication() + { + return ImageInfo.imageApplication; + } + + public override string GetImageApplicationVersion() + { + return ImageInfo.imageApplicationVersion; + } + + public override string GetImageCreator() + { + return ImageInfo.imageCreator; + } + + public override DateTime GetImageCreationTime() + { + return ImageInfo.imageCreationTime; + } + + public override DateTime GetImageLastModificationTime() + { + return ImageInfo.imageLastModificationTime; + } + + public override string GetImageName() + { + return ImageInfo.imageName; + } + + public override string GetImageComments() + { + return ImageInfo.imageComments; + } + + public override string GetMediaManufacturer() + { + return ImageInfo.mediaManufacturer; + } + + public override string GetMediaModel() + { + return ImageInfo.mediaModel; + } + + public override string GetMediaSerialNumber() + { + return ImageInfo.mediaSerialNumber; + } + + public override string GetMediaBarcode() + { + return ImageInfo.mediaBarcode; + } + + public override string GetMediaPartNumber() + { + return ImageInfo.mediaPartNumber; + } + + public override MediaType GetMediaType() + { + return ImageInfo.mediaType; + } + + public override int GetMediaSequence() + { + return ImageInfo.mediaSequence; + } + + public override int GetLastDiskSequence() + { + return ImageInfo.lastMediaSequence; + } + + public override string GetDriveManufacturer() + { + return ImageInfo.driveManufacturer; + } + + public override string GetDriveModel() + { + return ImageInfo.driveModel; + } + + public override string GetDriveSerialNumber() + { + return ImageInfo.driveSerialNumber; + } + + public override bool? VerifySector(ulong sectorAddress) + { + throw new NotImplementedException("Flux decoding is not yet implemented."); + } + + public override bool? VerifySectors(ulong sectorAddress, uint length, out List FailingLBAs, out List UnknownLBAs) + { + throw new NotImplementedException("Flux decoding is not yet implemented."); + } + #endregion Public methods + + #region Unsupported features + public override byte[] ReadSector(ulong sectorAddress, uint track) + { + throw new FeatureUnsupportedImageException("Feature not supported by image format"); + } + + public override byte[] ReadSectorTag(ulong sectorAddress, uint track, SectorTagType tag) + { + throw new FeatureUnsupportedImageException("Feature not supported by image format"); + } + public override byte[] ReadSectors(ulong sectorAddress, uint length, uint track) + { + throw new FeatureUnsupportedImageException("Feature not supported by image format"); + } + + public override byte[] ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag) + { + throw new FeatureUnsupportedImageException("Feature not supported by image format"); + } + + public override byte[] ReadSectorsLong(ulong sectorAddress, uint length, uint track) + { + throw new FeatureUnsupportedImageException("Feature not supported by image format"); + } + + public override List GetPartitions() + { + throw new FeatureUnsupportedImageException("Feature not supported by image format"); + } + + public override List GetTracks() + { + throw new FeatureUnsupportedImageException("Feature not supported by image format"); + } + + public override List GetSessionTracks(Session session) + { + throw new FeatureUnsupportedImageException("Feature not supported by image format"); + } + + public override List GetSessionTracks(ushort session) + { + throw new FeatureUnsupportedImageException("Feature not supported by image format"); + } + + public override List GetSessions() + { + throw new FeatureUnsupportedImageException("Feature not supported by image format"); + } + + public override bool? VerifySector(ulong sectorAddress, uint track) + { + throw new FeatureUnsupportedImageException("Feature not supported by image format"); + } + + public override bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List FailingLBAs, out List UnknownLBAs) + { + throw new FeatureUnsupportedImageException("Feature not supported by image format"); + } + + public override bool? VerifyMediaImage() + { + throw new FeatureUnsupportedImageException("Feature not supported by image format"); + } + #endregion Unsupported features + } +} \ No newline at end of file diff --git a/DiscImageChef.DiscImages/SuperCardPro.cs b/DiscImageChef.DiscImages/SuperCardPro.cs index fd7c1073..739cd2d2 100644 --- a/DiscImageChef.DiscImages/SuperCardPro.cs +++ b/DiscImageChef.DiscImages/SuperCardPro.cs @@ -441,7 +441,7 @@ namespace DiscImageChef.ImagePlugins throw new NotImplementedException("Flux decoding is not yet implemented."); } - public override bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List FailingLBAs, out List UnknownLBAs) + public override bool? VerifySectors(ulong sectorAddress, uint length, out List FailingLBAs, out List UnknownLBAs) { throw new NotImplementedException("Flux decoding is not yet implemented."); } @@ -507,7 +507,7 @@ namespace DiscImageChef.ImagePlugins throw new FeatureUnsupportedImageException("Feature not supported by image format"); } - public override bool? VerifySectors(ulong sectorAddress, uint length, out List FailingLBAs, out List UnknownLBAs) + public override bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List FailingLBAs, out List UnknownLBAs) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); } diff --git a/README.md b/README.md index 31180464..9147f328 100644 --- a/README.md +++ b/README.md @@ -215,4 +215,5 @@ Supported filters Partially supported disk image formats ====================================== This disk image formats cannot be read, but their contents can be checksummed on sidecar creation +* KryoFlux STREAM * SuperCardPro \ No newline at end of file