Beispiel #1
0
        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);
        }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        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);
        }