// /*************************************************************************** // The Disc Image Chef // ---------------------------------------------------------------------------- // // Filename : Read.cs // Author(s) : Natalia Portillo // // Component : Disk image plugins. // // --[ Description ] ---------------------------------------------------------- // // Reads KryoFlux STREAM 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-2018 Natalia Portillo // ****************************************************************************/ using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Runtime.InteropServices; using DiscImageChef.CommonTypes.Enums; using DiscImageChef.CommonTypes.Interfaces; using DiscImageChef.Console; using DiscImageChef.Filters; namespace DiscImageChef.DiscImages { public partial class KryoFlux { public bool Open(IFilter 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; // 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, $"{cylinder:D2}.{head:D1}.raw") : $"{basename}{cylinder:D2}.{head:D1}.raw"; 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); break; } ZZZNoFilter trackFilter = new ZZZNoFilter(); trackFilter.Open(trackfile); if(!trackFilter.IsOpened()) throw new IOException("Could not open KryoFlux track file."); imageInfo.CreationTime = DateTime.MaxValue; imageInfo.LastModificationTime = 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[] kvp in lines.Select(line => line.Split('=')).Where(kvp => kvp.Length == 2)) { kvp[0] = kvp[0].Trim(); kvp[1] = kvp[1].Trim(); DicConsole.DebugWriteLine("KryoFlux plugin", "\"{0}\" = \"{1}\"", kvp[0], kvp[1]); switch(kvp[0]) { case hostDate: if(DateTime.TryParseExact(kvp[1], "yyyy.MM.dd", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out blockDate)) foundDate = true; break; case hostTime: DateTime.TryParseExact(kvp[1], "HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out blockTime); break; case kfName: imageInfo.Application = kvp[1]; break; case kfVersion: imageInfo.ApplicationVersion = kvp[1]; break; } } 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 < Info.CreationTime) imageInfo.CreationTime = blockTimestamp; if(blockTimestamp > Info.LastModificationTime) imageInfo.LastModificationTime = 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); throw new NotImplementedException("Flux decoding is not yet implemented."); } public byte[] ReadDiskTag(MediaTagType tag) { throw new NotImplementedException("Flux decoding is not yet implemented."); } public byte[] ReadSector(ulong sectorAddress) { return ReadSectors(sectorAddress, 1); } public byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag) { throw new NotImplementedException("Flux decoding is not yet implemented."); } public byte[] ReadSectors(ulong sectorAddress, uint length) { throw new NotImplementedException("Flux decoding is not yet implemented."); } public byte[] ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag) { throw new NotImplementedException("Flux decoding is not yet implemented."); } public byte[] ReadSectorLong(ulong sectorAddress) { throw new NotImplementedException("Flux decoding is not yet implemented."); } public byte[] ReadSectorsLong(ulong sectorAddress, uint length) { throw new NotImplementedException("Flux decoding is not yet implemented."); } public bool? VerifySector(ulong sectorAddress) { throw new NotImplementedException("Flux decoding is not yet implemented."); } public bool? VerifySectors(ulong sectorAddress, uint length, out List failingLbas, out List unknownLbas) { throw new NotImplementedException("Flux decoding is not yet implemented."); } } }