public bool Open(IFilter imageFilter) { Stream stream = imageFilter.GetDataForkStream(); stream.Seek(0, SeekOrigin.Begin); var cmt = new MemoryStream(); stream.Seek(0x1F, SeekOrigin.Begin); for (uint i = 0; i < stream.Length; i++) { byte b = (byte)stream.ReadByte(); if (b == 0x1A) { break; } cmt.WriteByte(b); } imageInfo.Comments = StringHandlers.CToString(cmt.ToArray()); sectorsData = new List <byte[]>(); byte currentCylinder = 0; imageInfo.Cylinders = 1; imageInfo.Heads = 1; ulong currentLba = 0; TransferRate mode = TransferRate.TwoHundred; while (stream.Position + 5 < stream.Length) { mode = (TransferRate)stream.ReadByte(); byte cylinder = (byte)stream.ReadByte(); byte head = (byte)stream.ReadByte(); byte spt = (byte)stream.ReadByte(); byte n = (byte)stream.ReadByte(); byte[] idmap = new byte[spt]; byte[] cylmap = new byte[spt]; byte[] headmap = new byte[spt]; ushort[] bps = new ushort[spt]; if (cylinder != currentCylinder) { currentCylinder = cylinder; imageInfo.Cylinders++; } if ((head & 1) == 1) { imageInfo.Heads = 2; } stream.Read(idmap, 0, idmap.Length); if ((head & SECTOR_CYLINDER_MAP_MASK) == SECTOR_CYLINDER_MAP_MASK) { stream.Read(cylmap, 0, cylmap.Length); } if ((head & SECTOR_HEAD_MAP_MASK) == SECTOR_HEAD_MAP_MASK) { stream.Read(headmap, 0, headmap.Length); } if (n == 0xFF) { byte[] bpsbytes = new byte[spt * 2]; stream.Read(bpsbytes, 0, bpsbytes.Length); for (int i = 0; i < spt; i++) { bps[i] = BitConverter.ToUInt16(bpsbytes, i * 2); } } else { for (int i = 0; i < spt; i++) { bps[i] = (ushort)(128 << n); } } if (spt > imageInfo.SectorsPerTrack) { imageInfo.SectorsPerTrack = spt; } SortedDictionary <byte, byte[]> track = new SortedDictionary <byte, byte[]>(); for (int i = 0; i < spt; i++) { var type = (SectorType)stream.ReadByte(); byte[] data = new byte[bps[i]]; // TODO; Handle disks with different bps in track 0 if (bps[i] > imageInfo.SectorSize) { imageInfo.SectorSize = bps[i]; } switch (type) { case SectorType.Unavailable: if (!track.ContainsKey(idmap[i])) { track.Add(idmap[i], data); } break; case SectorType.Normal: case SectorType.Deleted: case SectorType.Error: case SectorType.DeletedError: stream.Read(data, 0, data.Length); if (!track.ContainsKey(idmap[i])) { track.Add(idmap[i], data); } imageInfo.ImageSize += (ulong)data.Length; break; case SectorType.Compressed: case SectorType.CompressedDeleted: case SectorType.CompressedError: case SectorType.CompressedDeletedError: byte filling = (byte)stream.ReadByte(); ArrayHelpers.ArrayFill(data, filling); if (!track.ContainsKey(idmap[i])) { track.Add(idmap[i], data); } break; default: throw new ImageNotSupportedException($"Invalid sector type {(byte)type}"); } } foreach (KeyValuePair <byte, byte[]> kvp in track) { sectorsData.Add(kvp.Value); currentLba++; } } imageInfo.Application = "IMD"; // TODO: The header is the date of dump or the date of the application compilation? imageInfo.CreationTime = imageFilter.GetCreationTime(); imageInfo.LastModificationTime = imageFilter.GetLastWriteTime(); imageInfo.MediaTitle = Path.GetFileNameWithoutExtension(imageFilter.GetFilename()); imageInfo.Comments = StringHandlers.CToString(cmt.ToArray()); imageInfo.Sectors = currentLba; imageInfo.MediaType = MediaType.Unknown; MediaEncoding mediaEncoding = MediaEncoding.MFM; if (mode == TransferRate.TwoHundred || mode == TransferRate.ThreeHundred || mode == TransferRate.FiveHundred) { mediaEncoding = MediaEncoding.FM; } imageInfo.MediaType = Geometry.GetMediaType(((ushort)imageInfo.Cylinders, (byte)imageInfo.Heads, (ushort)imageInfo.SectorsPerTrack, imageInfo.SectorSize, mediaEncoding, false)); switch (imageInfo.MediaType) { case MediaType.NEC_525_HD when mode == TransferRate.FiveHundredMfm: imageInfo.MediaType = MediaType.NEC_35_HD_8; break; case MediaType.DOS_525_HD when mode == TransferRate.FiveHundredMfm: imageInfo.MediaType = MediaType.NEC_35_HD_15; break; case MediaType.RX50 when mode == TransferRate.FiveHundredMfm: imageInfo.MediaType = MediaType.ATARI_35_SS_DD; break; } imageInfo.XmlMediaType = XmlMediaType.BlockMedia; AaruConsole.VerboseWriteLine("IMD image contains a disk of type {0}", imageInfo.MediaType); if (!string.IsNullOrEmpty(imageInfo.Comments)) { AaruConsole.VerboseWriteLine("IMD comments: {0}", imageInfo.Comments); } return(true); }
public bool Open(IFilter imageFilter) { Stream stream = imageFilter.GetDataForkStream(); stream.Seek(0, SeekOrigin.Begin); byte[] hdr = new byte[133]; stream.Read(hdr, 0, 133); header = new CopyQmHeader(); IntPtr hdrPtr = Marshal.AllocHGlobal(133); Marshal.Copy(hdr, 0, hdrPtr, 133); header = (CopyQmHeader)Marshal.PtrToStructure(hdrPtr, typeof(CopyQmHeader)); Marshal.FreeHGlobal(hdrPtr); DicConsole.DebugWriteLine("CopyQM plugin", "header.magic = 0x{0:X4}", header.magic); DicConsole.DebugWriteLine("CopyQM plugin", "header.mark = 0x{0:X2}", header.mark); DicConsole.DebugWriteLine("CopyQM plugin", "header.sectorSize = {0}", header.sectorSize); DicConsole.DebugWriteLine("CopyQM plugin", "header.sectorPerCluster = {0}", header.sectorPerCluster); DicConsole.DebugWriteLine("CopyQM plugin", "header.reservedSectors = {0}", header.reservedSectors); DicConsole.DebugWriteLine("CopyQM plugin", "header.fatCopy = {0}", header.fatCopy); DicConsole.DebugWriteLine("CopyQM plugin", "header.rootEntries = {0}", header.rootEntries); DicConsole.DebugWriteLine("CopyQM plugin", "header.sectors = {0}", header.sectors); DicConsole.DebugWriteLine("CopyQM plugin", "header.mediaType = 0x{0:X2}", header.mediaType); DicConsole.DebugWriteLine("CopyQM plugin", "header.sectorsPerFat = {0}", header.sectorsPerFat); DicConsole.DebugWriteLine("CopyQM plugin", "header.sectorsPerTrack = {0}", header.sectorsPerTrack); DicConsole.DebugWriteLine("CopyQM plugin", "header.heads = {0}", header.heads); DicConsole.DebugWriteLine("CopyQM plugin", "header.hidden = {0}", header.hidden); DicConsole.DebugWriteLine("CopyQM plugin", "header.sectorsBig = {0}", header.sectorsBig); DicConsole.DebugWriteLine("CopyQM plugin", "header.description = {0}", header.description); DicConsole.DebugWriteLine("CopyQM plugin", "header.blind = {0}", header.blind); DicConsole.DebugWriteLine("CopyQM plugin", "header.density = {0}", header.density); DicConsole.DebugWriteLine("CopyQM plugin", "header.imageCylinders = {0}", header.imageCylinders); DicConsole.DebugWriteLine("CopyQM plugin", "header.totalCylinders = {0}", header.totalCylinders); DicConsole.DebugWriteLine("CopyQM plugin", "header.crc = 0x{0:X8}", header.crc); DicConsole.DebugWriteLine("CopyQM plugin", "header.volumeLabel = {0}", header.volumeLabel); DicConsole.DebugWriteLine("CopyQM plugin", "header.time = 0x{0:X4}", header.time); DicConsole.DebugWriteLine("CopyQM plugin", "header.date = 0x{0:X4}", header.date); DicConsole.DebugWriteLine("CopyQM plugin", "header.commentLength = {0}", header.commentLength); DicConsole.DebugWriteLine("CopyQM plugin", "header.secbs = {0}", header.secbs); DicConsole.DebugWriteLine("CopyQM plugin", "header.unknown = 0x{0:X4}", header.unknown); DicConsole.DebugWriteLine("CopyQM plugin", "header.interleave = {0}", header.interleave); DicConsole.DebugWriteLine("CopyQM plugin", "header.skew = {0}", header.skew); DicConsole.DebugWriteLine("CopyQM plugin", "header.drive = {0}", header.drive); byte[] cmt = new byte[header.commentLength]; stream.Read(cmt, 0, header.commentLength); imageInfo.Comments = StringHandlers.CToString(cmt); decodedImage = new MemoryStream(); calculatedDataCrc = 0; while (stream.Position + 2 < stream.Length) { byte[] runLengthBytes = new byte[2]; if (stream.Read(runLengthBytes, 0, 2) != 2) { break; } short runLength = BitConverter.ToInt16(runLengthBytes, 0); if (runLength < 0) { byte repeatedByte = (byte)stream.ReadByte(); byte[] repeatedArray = new byte[runLength * -1]; ArrayHelpers.ArrayFill(repeatedArray, repeatedByte); for (int i = 0; i < runLength * -1; i++) { decodedImage.WriteByte(repeatedByte); calculatedDataCrc = copyQmCrcTable[(repeatedByte ^ calculatedDataCrc) & 0x3F] ^ (calculatedDataCrc >> 8); } } else if (runLength > 0) { byte[] nonRepeated = new byte[runLength]; stream.Read(nonRepeated, 0, runLength); decodedImage.Write(nonRepeated, 0, runLength); foreach (byte c in nonRepeated) { calculatedDataCrc = copyQmCrcTable[(c ^ calculatedDataCrc) & 0x3F] ^ (calculatedDataCrc >> 8); } } } // In case there is omitted data long sectors = header.sectorsPerTrack * header.heads * header.totalCylinders; long fillingLen = sectors * header.sectorSize - decodedImage.Length; if (fillingLen > 0) { byte[] filling = new byte[fillingLen]; ArrayHelpers.ArrayFill(filling, (byte)0xF6); decodedImage.Write(filling, 0, filling.Length); } int sum = 0; for (int i = 0; i < hdr.Length - 1; i++) { sum += hdr[i]; } headerChecksumOk = ((-1 * sum) & 0xFF) == header.headerChecksum; DicConsole.DebugWriteLine("CopyQM plugin", "Calculated header checksum = 0x{0:X2}, {1}", (-1 * sum) & 0xFF, headerChecksumOk); DicConsole.DebugWriteLine("CopyQM plugin", "Calculated data CRC = 0x{0:X8}, {1}", calculatedDataCrc, calculatedDataCrc == header.crc); imageInfo.Application = "CopyQM"; imageInfo.CreationTime = DateHandlers.DosToDateTime(header.date, header.time); imageInfo.LastModificationTime = imageInfo.CreationTime; imageInfo.MediaTitle = header.volumeLabel; imageInfo.ImageSize = (ulong)(stream.Length - 133 - header.commentLength); imageInfo.Sectors = (ulong)sectors; imageInfo.SectorSize = header.sectorSize; imageInfo.MediaType = Geometry.GetMediaType(((ushort)header.totalCylinders, (byte)header.heads, header.sectorsPerTrack, (uint)header.sectorSize, MediaEncoding.MFM, false)); switch (imageInfo.MediaType) { case MediaType.NEC_525_HD when header.drive == COPYQM_35_HD || header.drive == COPYQM_35_ED: imageInfo.MediaType = MediaType.NEC_35_HD_8; break; case MediaType.DOS_525_HD when header.drive == COPYQM_35_HD || header.drive == COPYQM_35_ED: imageInfo.MediaType = MediaType.NEC_35_HD_15; break; case MediaType.RX50 when header.drive == COPYQM_525_DD || header.drive == COPYQM_525_HD: imageInfo.MediaType = MediaType.ATARI_35_SS_DD; break; } imageInfo.XmlMediaType = XmlMediaType.BlockMedia; decodedDisk = decodedImage.ToArray(); decodedImage.Close(); DicConsole.VerboseWriteLine("CopyQM image contains a disk of type {0}", imageInfo.MediaType); if (!string.IsNullOrEmpty(imageInfo.Comments)) { DicConsole.VerboseWriteLine("CopyQM comments: {0}", imageInfo.Comments); } imageInfo.Heads = header.heads; imageInfo.Cylinders = header.totalCylinders; imageInfo.SectorsPerTrack = header.sectorsPerTrack; return(true); }
public bool Open(IFilter imageFilter) { Stream stream = imageFilter.GetDataForkStream(); stream.Seek(0, SeekOrigin.Begin); var type = (DiskType)stream.ReadByte(); byte tracks; switch (type) { case DiskType.MD1DD8: case DiskType.MD1DD: case DiskType.MD2DD8: case DiskType.MD2DD: tracks = 80; break; case DiskType.MF2DD: case DiskType.MD2HD: case DiskType.MF2HD: tracks = 160; break; default: throw new ImageNotSupportedException($"Incorrect disk type {(byte)type}"); } byte[] trackBytes = new byte[tracks]; stream.Read(trackBytes, 0, tracks); var cmpr = (Compression)stream.ReadByte(); if (cmpr != Compression.None) { throw new FeatureSupportedButNotImplementedImageException("Compressed images are not supported."); } int tracksize = 0; switch (type) { case DiskType.MD1DD8: case DiskType.MD2DD8: tracksize = 8 * 512; break; case DiskType.MD1DD: case DiskType.MD2DD: case DiskType.MF2DD: tracksize = 9 * 512; break; case DiskType.MD2HD: tracksize = 15 * 512; break; case DiskType.MF2HD: tracksize = 18 * 512; break; } int headstep = 1; if (type == DiskType.MD1DD || type == DiskType.MD1DD8) { headstep = 2; } var decodedImage = new MemoryStream(); for (int i = 0; i < tracks; i += headstep) { byte[] track = new byte[tracksize]; if ((TrackType)trackBytes[i] == TrackType.Copied) { stream.Read(track, 0, tracksize); } else { ArrayHelpers.ArrayFill(track, (byte)0xF6); } decodedImage.Write(track, 0, tracksize); } _imageInfo.Application = "CisCopy"; _imageInfo.CreationTime = imageFilter.GetCreationTime(); _imageInfo.LastModificationTime = imageFilter.GetLastWriteTime(); _imageInfo.MediaTitle = imageFilter.GetFilename(); _imageInfo.ImageSize = (ulong)(stream.Length - 2 - trackBytes.Length); _imageInfo.SectorSize = 512; switch (type) { case DiskType.MD1DD8: _imageInfo.MediaType = MediaType.DOS_525_SS_DD_8; _imageInfo.Sectors = 40 * 1 * 8; _imageInfo.Heads = 1; _imageInfo.Cylinders = 40; _imageInfo.SectorsPerTrack = 8; break; case DiskType.MD2DD8: _imageInfo.MediaType = MediaType.DOS_525_DS_DD_8; _imageInfo.Sectors = 40 * 2 * 8; _imageInfo.Heads = 2; _imageInfo.Cylinders = 40; _imageInfo.SectorsPerTrack = 8; break; case DiskType.MD1DD: _imageInfo.MediaType = MediaType.DOS_525_SS_DD_9; _imageInfo.Sectors = 40 * 1 * 9; _imageInfo.Heads = 1; _imageInfo.Cylinders = 40; _imageInfo.SectorsPerTrack = 9; break; case DiskType.MD2DD: _imageInfo.MediaType = MediaType.DOS_525_DS_DD_9; _imageInfo.Sectors = 40 * 2 * 9; _imageInfo.Heads = 2; _imageInfo.Cylinders = 40; _imageInfo.SectorsPerTrack = 9; break; case DiskType.MF2DD: _imageInfo.MediaType = MediaType.DOS_35_DS_DD_9; _imageInfo.Sectors = 80 * 2 * 9; _imageInfo.Heads = 2; _imageInfo.Cylinders = 80; _imageInfo.SectorsPerTrack = 9; break; case DiskType.MD2HD: _imageInfo.MediaType = MediaType.DOS_525_HD; _imageInfo.Sectors = 80 * 2 * 15; _imageInfo.Heads = 2; _imageInfo.Cylinders = 80; _imageInfo.SectorsPerTrack = 15; break; case DiskType.MF2HD: _imageInfo.MediaType = MediaType.DOS_35_HD; _imageInfo.Sectors = 80 * 2 * 18; _imageInfo.Heads = 2; _imageInfo.Cylinders = 80; _imageInfo.SectorsPerTrack = 18; break; } _imageInfo.XmlMediaType = XmlMediaType.BlockMedia; _decodedDisk = decodedImage.ToArray(); decodedImage.Close(); AaruConsole.VerboseWriteLine("CisCopy image contains a disk of type {0}", _imageInfo.MediaType); return(true); }