Esempio n. 1
0
        public bool Open(IFilter imageFilter)
        {
            Stream stream = imageFilter.GetDataForkStream();

            stream.Seek(0, SeekOrigin.Begin);

            // Even if disk name is supposedly ASCII, I'm pretty sure most emulators allow Shift-JIS to be used :p
            var shiftjis = Encoding.GetEncoding("shift_jis");

            if (stream.Length < Marshal.SizeOf <D88Header>())
            {
                return(false);
            }

            byte[] hdrB = new byte[Marshal.SizeOf <D88Header>()];
            stream.Read(hdrB, 0, hdrB.Length);
            D88Header d88Hdr = Marshal.ByteArrayToStructureLittleEndian <D88Header>(hdrB);

            AaruConsole.DebugWriteLine("D88 plugin", "d88hdr.name = \"{0}\"",
                                       StringHandlers.CToString(d88Hdr.name, shiftjis));

            AaruConsole.DebugWriteLine("D88 plugin", "d88hdr.reserved is empty? = {0}",
                                       d88Hdr.reserved.SequenceEqual(_reservedEmpty));

            AaruConsole.DebugWriteLine("D88 plugin", "d88hdr.write_protect = 0x{0:X2}", d88Hdr.write_protect);

            AaruConsole.DebugWriteLine("D88 plugin", "d88hdr.disk_type = {0} ({1})", d88Hdr.disk_type,
                                       (byte)d88Hdr.disk_type);

            AaruConsole.DebugWriteLine("D88 plugin", "d88hdr.disk_size = {0}", d88Hdr.disk_size);

            if (d88Hdr.disk_size != stream.Length)
            {
                return(false);
            }

            if (d88Hdr.disk_type != DiskType.D2 &&
                d88Hdr.disk_type != DiskType.Dd2 &&
                d88Hdr.disk_type != DiskType.Hd2)
            {
                return(false);
            }

            if (!d88Hdr.reserved.SequenceEqual(_reservedEmpty))
            {
                return(false);
            }

            int trkCounter = 0;

            foreach (int t in d88Hdr.track_table)
            {
                if (t > 0)
                {
                    trkCounter++;
                }

                if (t < 0 ||
                    t > stream.Length)
                {
                    return(false);
                }
            }

            AaruConsole.DebugWriteLine("D88 plugin", "{0} tracks", trkCounter);

            if (trkCounter == 0)
            {
                return(false);
            }

            hdrB = new byte[Marshal.SizeOf <SectorHeader>()];
            stream.Seek(d88Hdr.track_table[0], SeekOrigin.Begin);
            stream.Read(hdrB, 0, hdrB.Length);

            SectorHeader sechdr = Marshal.ByteArrayToStructureLittleEndian <SectorHeader>(hdrB);

            AaruConsole.DebugWriteLine("D88 plugin", "sechdr.c = {0}", sechdr.c);
            AaruConsole.DebugWriteLine("D88 plugin", "sechdr.h = {0}", sechdr.h);
            AaruConsole.DebugWriteLine("D88 plugin", "sechdr.r = {0}", sechdr.r);
            AaruConsole.DebugWriteLine("D88 plugin", "sechdr.n = {0}", sechdr.n);
            AaruConsole.DebugWriteLine("D88 plugin", "sechdr.spt = {0}", sechdr.spt);
            AaruConsole.DebugWriteLine("D88 plugin", "sechdr.density = {0}", sechdr.density);
            AaruConsole.DebugWriteLine("D88 plugin", "sechdr.deleted_mark = {0}", sechdr.deleted_mark);
            AaruConsole.DebugWriteLine("D88 plugin", "sechdr.status = {0}", sechdr.status);
            AaruConsole.DebugWriteLine("D88 plugin", "sechdr.size_of_data = {0}", sechdr.size_of_data);

            short             spt = sechdr.spt;
            IBMSectorSizeCode bps = sechdr.n;
            bool allEqual         = true;

            _sectorsData = new List <byte[]>();

            for (int i = 0; i < trkCounter; i++)
            {
                stream.Seek(d88Hdr.track_table[i], SeekOrigin.Begin);
                stream.Read(hdrB, 0, hdrB.Length);
                SortedDictionary <byte, byte[]> sectors = new SortedDictionary <byte, byte[]>();

                sechdr = Marshal.ByteArrayToStructureLittleEndian <SectorHeader>(hdrB);

                if (sechdr.spt != spt ||
                    sechdr.n != bps)
                {
                    AaruConsole.DebugWriteLine("D88 plugin",
                                               "Disk tracks are not same size. spt = {0} (expected {1}), bps = {2} (expected {3}) at track {4} sector {5}",
                                               sechdr.spt, spt, sechdr.n, bps, i, 0);

                    allEqual = false;
                }

                short  maxJ = sechdr.spt;
                byte[] secB;

                for (short j = 1; j < maxJ; j++)
                {
                    secB = new byte[sechdr.size_of_data];
                    stream.Read(secB, 0, secB.Length);
                    sectors.Add(sechdr.r, secB);
                    stream.Read(hdrB, 0, hdrB.Length);

                    sechdr = Marshal.ByteArrayToStructureLittleEndian <SectorHeader>(hdrB);

                    if (sechdr.spt == spt &&
                        sechdr.n == bps)
                    {
                        continue;
                    }

                    AaruConsole.DebugWriteLine("D88 plugin",
                                               "Disk tracks are not same size. spt = {0} (expected {1}), bps = {2} (expected {3}) at track {4} sector {5}",
                                               sechdr.spt, spt, sechdr.n, bps, i, j, sechdr.deleted_mark);

                    allEqual = false;
                }

                secB = new byte[sechdr.size_of_data];
                stream.Read(secB, 0, secB.Length);
                sectors.Add(sechdr.r, secB);

                foreach (KeyValuePair <byte, byte[]> kvp in sectors)
                {
                    _sectorsData.Add(kvp.Value);
                }
            }

            AaruConsole.DebugWriteLine("D88 plugin", "{0} sectors", _sectorsData.Count);

            _imageInfo.MediaType = MediaType.Unknown;

            if (allEqual)
            {
                if (trkCounter == 154 &&
                    spt == 26 &&
                    bps == IBMSectorSizeCode.EighthKilo)
                {
                    _imageInfo.MediaType = MediaType.NEC_8_SD;
                }
                else if (bps == IBMSectorSizeCode.QuarterKilo)
                {
                    switch (trkCounter)
                    {
                    case 80 when spt == 16:
                        _imageInfo.MediaType = MediaType.NEC_525_SS;

                        break;

                    case 154 when spt == 26:
                        _imageInfo.MediaType = MediaType.NEC_8_DD;

                        break;

                    case 160 when spt == 16:
                        _imageInfo.MediaType = MediaType.NEC_525_DS;

                        break;
                    }
                }
                else if (trkCounter == 154 &&
                         spt == 8 &&
                         bps == IBMSectorSizeCode.Kilo)
                {
                    _imageInfo.MediaType = MediaType.NEC_525_HD;
                }
                else if (bps == IBMSectorSizeCode.HalfKilo)
                {
                    switch (d88Hdr.track_table.Length)
                    {
                    case 40:
                    {
                        switch (spt)
                        {
                        case 8:
                            _imageInfo.MediaType = MediaType.DOS_525_SS_DD_8;

                            break;

                        case 9:
                            _imageInfo.MediaType = MediaType.DOS_525_SS_DD_9;

                            break;
                        }
                    }

                    break;

                    case 80:
                    {
                        switch (spt)
                        {
                        case 8:
                            _imageInfo.MediaType = MediaType.DOS_525_DS_DD_8;

                            break;

                        case 9:
                            _imageInfo.MediaType = MediaType.DOS_525_DS_DD_9;

                            break;
                        }
                    }

                    break;

                    case 160:
                    {
                        switch (spt)
                        {
                        case 15:
                            _imageInfo.MediaType = MediaType.NEC_35_HD_15;

                            break;

                        case 9:
                            _imageInfo.MediaType = MediaType.DOS_35_DS_DD_9;

                            break;

                        case 18:
                            _imageInfo.MediaType = MediaType.DOS_35_HD;

                            break;

                        case 36:
                            _imageInfo.MediaType = MediaType.DOS_35_ED;

                            break;
                        }
                    }

                    break;

                    case 480:
                        if (spt == 38)
                        {
                            _imageInfo.MediaType = MediaType.NEC_35_TD;
                        }

                        break;
                    }
                }
            }

            AaruConsole.DebugWriteLine("D88 plugin", "MediaType: {0}", _imageInfo.MediaType);

            _imageInfo.ImageSize            = (ulong)d88Hdr.disk_size;
            _imageInfo.CreationTime         = imageFilter.GetCreationTime();
            _imageInfo.LastModificationTime = imageFilter.GetLastWriteTime();
            _imageInfo.MediaTitle           = Path.GetFileNameWithoutExtension(imageFilter.GetFilename());
            _imageInfo.Sectors      = (ulong)_sectorsData.Count;
            _imageInfo.Comments     = StringHandlers.CToString(d88Hdr.name, shiftjis);
            _imageInfo.XmlMediaType = XmlMediaType.BlockMedia;
            _imageInfo.SectorSize   = (uint)(128 << (int)bps);

            switch (_imageInfo.MediaType)
            {
            case MediaType.NEC_525_SS:
                _imageInfo.Cylinders       = 80;
                _imageInfo.Heads           = 1;
                _imageInfo.SectorsPerTrack = 16;

                break;

            case MediaType.NEC_8_SD:
            case MediaType.NEC_8_DD:
                _imageInfo.Cylinders       = 77;
                _imageInfo.Heads           = 2;
                _imageInfo.SectorsPerTrack = 26;

                break;

            case MediaType.NEC_525_DS:
                _imageInfo.Cylinders       = 80;
                _imageInfo.Heads           = 2;
                _imageInfo.SectorsPerTrack = 16;

                break;

            case MediaType.NEC_525_HD:
                _imageInfo.Cylinders       = 77;
                _imageInfo.Heads           = 2;
                _imageInfo.SectorsPerTrack = 8;

                break;

            case MediaType.DOS_525_SS_DD_8:
                _imageInfo.Cylinders       = 40;
                _imageInfo.Heads           = 1;
                _imageInfo.SectorsPerTrack = 8;

                break;

            case MediaType.DOS_525_SS_DD_9:
                _imageInfo.Cylinders       = 40;
                _imageInfo.Heads           = 1;
                _imageInfo.SectorsPerTrack = 9;

                break;

            case MediaType.DOS_525_DS_DD_8:
                _imageInfo.Cylinders       = 40;
                _imageInfo.Heads           = 2;
                _imageInfo.SectorsPerTrack = 8;

                break;

            case MediaType.DOS_525_DS_DD_9:
                _imageInfo.Cylinders       = 40;
                _imageInfo.Heads           = 2;
                _imageInfo.SectorsPerTrack = 9;

                break;

            case MediaType.NEC_35_HD_15:
                _imageInfo.Cylinders       = 80;
                _imageInfo.Heads           = 2;
                _imageInfo.SectorsPerTrack = 15;

                break;

            case MediaType.DOS_35_DS_DD_9:
                _imageInfo.Cylinders       = 80;
                _imageInfo.Heads           = 2;
                _imageInfo.SectorsPerTrack = 9;

                break;

            case MediaType.DOS_35_HD:
                _imageInfo.Cylinders       = 80;
                _imageInfo.Heads           = 2;
                _imageInfo.SectorsPerTrack = 18;

                break;

            case MediaType.DOS_35_ED:
                _imageInfo.Cylinders       = 80;
                _imageInfo.Heads           = 2;
                _imageInfo.SectorsPerTrack = 36;

                break;

            case MediaType.NEC_35_TD:
                _imageInfo.Cylinders       = 240;
                _imageInfo.Heads           = 2;
                _imageInfo.SectorsPerTrack = 38;

                break;
            }

            return(true);
        }
Esempio n. 2
0
        public bool Open(IFilter imageFilter)
        {
            _header = new Header();
            byte[] headerBytes = new byte[12];
            _inStream = imageFilter.GetDataForkStream();
            var stream = new MemoryStream();

            _inStream.Seek(0, SeekOrigin.Begin);

            _inStream.Read(headerBytes, 0, 12);
            stream.Write(headerBytes, 0, 12);

            _header.Signature = BitConverter.ToUInt16(headerBytes, 0);

            if (_header.Signature != TD_MAGIC &&
                _header.Signature != TD_ADV_COMP_MAGIC)
            {
                return(false);
            }

            _header.Sequence      = headerBytes[2];
            _header.DiskSet       = headerBytes[3];
            _header.Version       = headerBytes[4];
            _header.DataRate      = headerBytes[5];
            _header.DriveType     = headerBytes[6];
            _header.Stepping      = headerBytes[7];
            _header.DosAllocation = headerBytes[8];
            _header.Sides         = headerBytes[9];
            _header.Crc           = BitConverter.ToUInt16(headerBytes, 10);

            _imageInfo.MediaTitle  = Path.GetFileNameWithoutExtension(imageFilter.GetFilename());
            _imageInfo.Version     = $"{(_header.Version & 0xF0) >> 4}.{_header.Version & 0x0F}";
            _imageInfo.Application = _imageInfo.Version;

            byte[] headerBytesForCrc = new byte[10];
            Array.Copy(headerBytes, headerBytesForCrc, 10);
            ushort calculatedHeaderCrc = TeleDiskCrc(0x0000, headerBytesForCrc);

            AaruConsole.DebugWriteLine("TeleDisk plugin", "header.signature = 0x{0:X4}", _header.Signature);
            AaruConsole.DebugWriteLine("TeleDisk plugin", "header.sequence = 0x{0:X2}", _header.Sequence);
            AaruConsole.DebugWriteLine("TeleDisk plugin", "header.diskSet = 0x{0:X2}", _header.DiskSet);
            AaruConsole.DebugWriteLine("TeleDisk plugin", "header.version = 0x{0:X2}", _header.Version);
            AaruConsole.DebugWriteLine("TeleDisk plugin", "header.dataRate = 0x{0:X2}", _header.DataRate);
            AaruConsole.DebugWriteLine("TeleDisk plugin", "header.driveType = 0x{0:X2}", _header.DriveType);
            AaruConsole.DebugWriteLine("TeleDisk plugin", "header.stepping = 0x{0:X2}", _header.Stepping);
            AaruConsole.DebugWriteLine("TeleDisk plugin", "header.dosAllocation = 0x{0:X2}", _header.DosAllocation);
            AaruConsole.DebugWriteLine("TeleDisk plugin", "header.sides = 0x{0:X2}", _header.Sides);
            AaruConsole.DebugWriteLine("TeleDisk plugin", "header.crc = 0x{0:X4}", _header.Crc);
            AaruConsole.DebugWriteLine("TeleDisk plugin", "calculated header crc = 0x{0:X4}", calculatedHeaderCrc);

            // We need more checks as the magic is too simply.
            // This may deny legal images

            // That would be much of a coincidence
            if (_header.Crc != calculatedHeaderCrc)
            {
                _aDiskCrcHasFailed = true;
                AaruConsole.DebugWriteLine("TeleDisk plugin", "Calculated CRC does not coincide with stored one.");
            }

            if (_header.Sequence != 0x00)
            {
                return(false);
            }

            if (_header.DataRate != DATA_RATE_250KBPS &&
                _header.DataRate != DATA_RATE_300KBPS &&
                _header.DataRate != DATA_RATE_500KBPS)
            {
                return(false);
            }

            if (_header.DriveType != DRIVE_TYPE_35_DD &&
                _header.DriveType != DRIVE_TYPE_35_ED &&
                _header.DriveType != DRIVE_TYPE_35_HD &&
                _header.DriveType != DRIVE_TYPE_525_DD &&
                _header.DriveType != DRIVE_TYPE_525_HD &&
                _header.DriveType != DRIVE_TYPE_525_HD_DD_DISK &&
                _header.DriveType != DRIVE_TYPE_8_INCH)
            {
                return(false);
            }

            if (_header.Signature == TD_ADV_COMP_MAGIC)
            {
                int rd;
                _inStream.Seek(12, SeekOrigin.Begin);
                stream.Seek(12, SeekOrigin.Begin);
                var lzh = new TeleDiskLzh(_inStream);

                do
                {
                    if ((rd = lzh.Decode(out byte[] obuf, BUFSZ)) > 0)
                    {
                        stream.Write(obuf, 0, rd);
                    }
                }while(rd == BUFSZ);
            }
            else
            {
                // Not using Stream.CopyTo() because it's failing with LZIP
                byte[] copybuf = new byte[_inStream.Length];
                _inStream.Seek(0, SeekOrigin.Begin);
                _inStream.Read(copybuf, 0, copybuf.Length);
                stream.Seek(0, SeekOrigin.Begin);
                stream.Write(copybuf, 0, copybuf.Length);
            }

            stream.Seek(12, SeekOrigin.Begin);

            _imageInfo.CreationTime = DateTime.MinValue;

            if ((_header.Stepping & COMMENT_BLOCK_PRESENT) == COMMENT_BLOCK_PRESENT)
            {
                _commentHeader = new CommentBlockHeader();

                byte[] commentHeaderBytes = new byte[10];

                stream.Read(commentHeaderBytes, 0, 10);
                _commentHeader.Crc    = BitConverter.ToUInt16(commentHeaderBytes, 0);
                _commentHeader.Length = BitConverter.ToUInt16(commentHeaderBytes, 2);
                _commentHeader.Year   = commentHeaderBytes[4];
                _commentHeader.Month  = commentHeaderBytes[5];
                _commentHeader.Day    = commentHeaderBytes[6];
                _commentHeader.Hour   = commentHeaderBytes[7];
                _commentHeader.Minute = commentHeaderBytes[8];
                _commentHeader.Second = commentHeaderBytes[9];

                _commentBlock = new byte[_commentHeader.Length];
                stream.Read(_commentBlock, 0, _commentHeader.Length);

                byte[] commentBlockForCrc = new byte[_commentHeader.Length + 8];
                Array.Copy(commentHeaderBytes, 2, commentBlockForCrc, 0, 8);
                Array.Copy(_commentBlock, 0, commentBlockForCrc, 8, _commentHeader.Length);

                ushort cmtcrc = TeleDiskCrc(0, commentBlockForCrc);

                AaruConsole.DebugWriteLine("TeleDisk plugin", "Comment header");
                AaruConsole.DebugWriteLine("TeleDisk plugin", "\tcommentheader.crc = 0x{0:X4}", _commentHeader.Crc);
                AaruConsole.DebugWriteLine("TeleDisk plugin", "\tCalculated CRC = 0x{0:X4}", cmtcrc);

                AaruConsole.DebugWriteLine("TeleDisk plugin", "\tcommentheader.length = {0} bytes",
                                           _commentHeader.Length);

                AaruConsole.DebugWriteLine("TeleDisk plugin", "\tcommentheader.year = {0}", _commentHeader.Year);
                AaruConsole.DebugWriteLine("TeleDisk plugin", "\tcommentheader.month = {0}", _commentHeader.Month);
                AaruConsole.DebugWriteLine("TeleDisk plugin", "\tcommentheader.day = {0}", _commentHeader.Day);
                AaruConsole.DebugWriteLine("TeleDisk plugin", "\tcommentheader.hour = {0}", _commentHeader.Hour);
                AaruConsole.DebugWriteLine("TeleDisk plugin", "\tcommentheader.minute = {0}", _commentHeader.Minute);
                AaruConsole.DebugWriteLine("TeleDisk plugin", "\tcommentheader.second = {0}", _commentHeader.Second);

                _aDiskCrcHasFailed |= cmtcrc != _commentHeader.Crc;

                for (int i = 0; i < _commentBlock.Length; i++)
                {
                    // Replace NULLs, used by TeleDisk as newline markers, with UNIX newline marker
                    if (_commentBlock[i] == 0x00)
                    {
                        _commentBlock[i] = 0x0A;
                    }
                }

                _imageInfo.Comments = Encoding.ASCII.GetString(_commentBlock);

                AaruConsole.DebugWriteLine("TeleDisk plugin", "Comment");
                AaruConsole.DebugWriteLine("TeleDisk plugin", "{0}", _imageInfo.Comments);

                _imageInfo.CreationTime = new DateTime(_commentHeader.Year + 1900, _commentHeader.Month + 1,
                                                       _commentHeader.Day, _commentHeader.Hour, _commentHeader.Minute,
                                                       _commentHeader.Second, DateTimeKind.Unspecified);
            }

            if (_imageInfo.CreationTime == DateTime.MinValue)
            {
                _imageInfo.CreationTime = imageFilter.GetCreationTime();
            }

            _imageInfo.LastModificationTime = imageFilter.GetLastWriteTime();

            AaruConsole.DebugWriteLine("TeleDisk plugin", "Image created on {0}", _imageInfo.CreationTime);
            AaruConsole.DebugWriteLine("TeleDisk plugin", "Image modified on {0}", _imageInfo.LastModificationTime);

            AaruConsole.DebugWriteLine("TeleDisk plugin", "Parsing image");

            _totalDiskSize       = 0;
            _imageInfo.ImageSize = 0;

            int  totalCylinders = -1;
            int  totalHeads     = -1;
            int  maxSector      = -1;
            int  totalSectors   = 0;
            long currentPos     = stream.Position;

            _imageInfo.SectorSize      = uint.MaxValue;
            _imageInfo.SectorsPerTrack = uint.MaxValue;

            // Count cylinders
            while (true)
            {
                var teleDiskTrack = new TrackHeader
                {
                    Sectors  = (byte)stream.ReadByte(),
                    Cylinder = (byte)stream.ReadByte(),
                    Head     = (byte)stream.ReadByte(),
                    Crc      = (byte)stream.ReadByte()
                };

                if (teleDiskTrack.Cylinder > totalCylinders)
                {
                    totalCylinders = teleDiskTrack.Cylinder;
                }

                if (teleDiskTrack.Head > totalHeads)
                {
                    totalHeads = teleDiskTrack.Head;
                }

                if (teleDiskTrack.Sectors == 0xFF) // End of disk image
                {
                    break;
                }

                for (byte processedSectors = 0; processedSectors < teleDiskTrack.Sectors; processedSectors++)
                {
                    var    teleDiskSector = new SectorHeader();
                    var    teleDiskData   = new DataHeader();
                    byte[] dataSizeBytes  = new byte[2];

                    teleDiskSector.Cylinder     = (byte)stream.ReadByte();
                    teleDiskSector.Head         = (byte)stream.ReadByte();
                    teleDiskSector.SectorNumber = (byte)stream.ReadByte();
                    teleDiskSector.SectorSize   = (byte)stream.ReadByte();
                    teleDiskSector.Flags        = (byte)stream.ReadByte();
                    teleDiskSector.Crc          = (byte)stream.ReadByte();

                    if (teleDiskSector.SectorNumber > maxSector)
                    {
                        maxSector = teleDiskSector.SectorNumber;
                    }

                    if ((teleDiskSector.Flags & FLAGS_SECTOR_DATALESS) != FLAGS_SECTOR_DATALESS &&
                        (teleDiskSector.Flags & FLAGS_SECTOR_SKIPPED) != FLAGS_SECTOR_SKIPPED)
                    {
                        stream.Read(dataSizeBytes, 0, 2);
                        teleDiskData.DataSize = BitConverter.ToUInt16(dataSizeBytes, 0);
                        teleDiskData.DataSize--; // Sydex decided to including dataEncoding byte as part of it
                        teleDiskData.DataEncoding = (byte)stream.ReadByte();
                        byte[] data = new byte[teleDiskData.DataSize];
                        stream.Read(data, 0, teleDiskData.DataSize);
                    }

                    if (128 << teleDiskSector.SectorSize < _imageInfo.SectorSize)
                    {
                        _imageInfo.SectorSize = (uint)(128 << teleDiskSector.SectorSize);
                    }

                    totalSectors++;
                }
            }

            totalCylinders++;
            totalHeads++;

            if (totalCylinders <= 0 ||
                totalHeads <= 0)
            {
                throw new ImageNotSupportedException("No cylinders or heads found");
            }

            bool hasLeadOutOnHead0 = false;
            bool hasLeadOutOnHead1 = false;

            _imageInfo.Cylinders = (ushort)totalCylinders;
            _imageInfo.Heads     = (byte)totalHeads;

            // Count sectors per track
            stream.Seek(currentPos, SeekOrigin.Begin);

            while (true)
            {
                var teleDiskTrack = new TrackHeader
                {
                    Sectors  = (byte)stream.ReadByte(),
                    Cylinder = (byte)stream.ReadByte(),
                    Head     = (byte)stream.ReadByte(),
                    Crc      = (byte)stream.ReadByte()
                };

                if (teleDiskTrack.Sectors == 0xFF) // End of disk image
                {
                    break;
                }

                if (teleDiskTrack.Sectors < _imageInfo.SectorsPerTrack)
                {
                    if (teleDiskTrack.Cylinder + 1 == totalCylinders)
                    {
                        hasLeadOutOnHead0 |= teleDiskTrack.Head == 0;
                        hasLeadOutOnHead1 |= teleDiskTrack.Head == 1;

                        if (_imageInfo.Cylinders == totalCylinders)
                        {
                            _imageInfo.Cylinders--;
                        }
                    }
                    else
                    {
                        _imageInfo.SectorsPerTrack = teleDiskTrack.Sectors;
                    }
                }

                for (byte processedSectors = 0; processedSectors < teleDiskTrack.Sectors; processedSectors++)
                {
                    var    teleDiskSector = new SectorHeader();
                    var    teleDiskData   = new DataHeader();
                    byte[] dataSizeBytes  = new byte[2];

                    teleDiskSector.Cylinder     = (byte)stream.ReadByte();
                    teleDiskSector.Head         = (byte)stream.ReadByte();
                    teleDiskSector.SectorNumber = (byte)stream.ReadByte();
                    teleDiskSector.SectorSize   = (byte)stream.ReadByte();
                    teleDiskSector.Flags        = (byte)stream.ReadByte();
                    teleDiskSector.Crc          = (byte)stream.ReadByte();

                    if ((teleDiskSector.Flags & FLAGS_SECTOR_DATALESS) == FLAGS_SECTOR_DATALESS ||
                        (teleDiskSector.Flags & FLAGS_SECTOR_SKIPPED) == FLAGS_SECTOR_SKIPPED)
                    {
                        continue;
                    }

                    stream.Read(dataSizeBytes, 0, 2);
                    teleDiskData.DataSize = BitConverter.ToUInt16(dataSizeBytes, 0);
                    teleDiskData.DataSize--; // Sydex decided to including dataEncoding byte as part of it
                    teleDiskData.DataEncoding = (byte)stream.ReadByte();
                    byte[] data = new byte[teleDiskData.DataSize];
                    stream.Read(data, 0, teleDiskData.DataSize);
                }
            }

            _sectorsData = new byte[totalCylinders][][][];

            // Total sectors per track
            uint[][] spts = new uint[totalCylinders][];

            AaruConsole.DebugWriteLine("TeleDisk plugin",
                                       "Found {0} cylinders and {1} heads with a maximum sector number of {2}",
                                       totalCylinders, totalHeads, maxSector);

            // Create heads
            for (int i = 0; i < totalCylinders; i++)
            {
                _sectorsData[i] = new byte[totalHeads][][];
                spts[i]         = new uint[totalHeads];

                for (int j = 0; j < totalHeads; j++)
                {
                    _sectorsData[i][j] = new byte[maxSector + 1][];
                }
            }

            // Decode the image
            stream.Seek(currentPos, SeekOrigin.Begin);

            while (true)
            {
                var    teleDiskTrack = new TrackHeader();
                byte[] tdTrackForCrc = new byte[3];

                teleDiskTrack.Sectors  = (byte)stream.ReadByte();
                teleDiskTrack.Cylinder = (byte)stream.ReadByte();
                teleDiskTrack.Head     = (byte)stream.ReadByte();
                teleDiskTrack.Crc      = (byte)stream.ReadByte();

                tdTrackForCrc[0] = teleDiskTrack.Sectors;
                tdTrackForCrc[1] = teleDiskTrack.Cylinder;
                tdTrackForCrc[2] = teleDiskTrack.Head;

                byte tdTrackCalculatedCrc = (byte)(TeleDiskCrc(0, tdTrackForCrc) & 0xFF);

                AaruConsole.DebugWriteLine("TeleDisk plugin", "Track follows");
                AaruConsole.DebugWriteLine("TeleDisk plugin", "\tTrack cylinder: {0}\t", teleDiskTrack.Cylinder);
                AaruConsole.DebugWriteLine("TeleDisk plugin", "\tTrack head: {0}\t", teleDiskTrack.Head);
                AaruConsole.DebugWriteLine("TeleDisk plugin", "\tSectors in track: {0}\t", teleDiskTrack.Sectors);

                AaruConsole.DebugWriteLine("TeleDisk plugin", "\tTrack header CRC: 0x{0:X2} (calculated 0x{1:X2})\t",
                                           teleDiskTrack.Crc, tdTrackCalculatedCrc);

                _aDiskCrcHasFailed |= tdTrackCalculatedCrc != teleDiskTrack.Crc;

                if (teleDiskTrack.Sectors == 0xFF) // End of disk image
                {
                    AaruConsole.DebugWriteLine("TeleDisk plugin", "End of disk image arrived");

                    AaruConsole.DebugWriteLine("TeleDisk plugin", "Total of {0} data sectors, for {1} bytes",
                                               totalSectors, _totalDiskSize);

                    break;
                }

                for (byte processedSectors = 0; processedSectors < teleDiskTrack.Sectors; processedSectors++)
                {
                    var    teleDiskSector = new SectorHeader();
                    var    teleDiskData   = new DataHeader();
                    byte[] dataSizeBytes  = new byte[2];
                    byte[] decodedData;

                    teleDiskSector.Cylinder     = (byte)stream.ReadByte();
                    teleDiskSector.Head         = (byte)stream.ReadByte();
                    teleDiskSector.SectorNumber = (byte)stream.ReadByte();
                    teleDiskSector.SectorSize   = (byte)stream.ReadByte();
                    teleDiskSector.Flags        = (byte)stream.ReadByte();
                    teleDiskSector.Crc          = (byte)stream.ReadByte();

                    AaruConsole.DebugWriteLine("TeleDisk plugin", "\tSector follows");

                    AaruConsole.DebugWriteLine("TeleDisk plugin", "\t\tAddressMark cylinder: {0}",
                                               teleDiskSector.Cylinder);

                    AaruConsole.DebugWriteLine("TeleDisk plugin", "\t\tAddressMark head: {0}", teleDiskSector.Head);

                    AaruConsole.DebugWriteLine("TeleDisk plugin", "\t\tAddressMark sector number: {0}",
                                               teleDiskSector.SectorNumber);

                    AaruConsole.DebugWriteLine("TeleDisk plugin", "\t\tSector size: {0}", teleDiskSector.SectorSize);
                    AaruConsole.DebugWriteLine("TeleDisk plugin", "\t\tSector flags: 0x{0:X2}", teleDiskSector.Flags);

                    AaruConsole.DebugWriteLine("TeleDisk plugin", "\t\tSector CRC (plus headers): 0x{0:X2}",
                                               teleDiskSector.Crc);

                    uint lba = (uint)((teleDiskSector.Cylinder * _header.Sides * _imageInfo.SectorsPerTrack) +
                                      (teleDiskSector.Head * _imageInfo.SectorsPerTrack) +
                                      (teleDiskSector.SectorNumber - 1));

                    if ((teleDiskSector.Flags & FLAGS_SECTOR_DATALESS) != FLAGS_SECTOR_DATALESS &&
                        (teleDiskSector.Flags & FLAGS_SECTOR_SKIPPED) != FLAGS_SECTOR_SKIPPED)
                    {
                        stream.Read(dataSizeBytes, 0, 2);
                        teleDiskData.DataSize = BitConverter.ToUInt16(dataSizeBytes, 0);
                        teleDiskData.DataSize--; // Sydex decided to including dataEncoding byte as part of it
                        _imageInfo.ImageSize     += teleDiskData.DataSize;
                        teleDiskData.DataEncoding = (byte)stream.ReadByte();
                        byte[] data = new byte[teleDiskData.DataSize];
                        stream.Read(data, 0, teleDiskData.DataSize);

                        AaruConsole.DebugWriteLine("TeleDisk plugin", "\t\tData size (in-image): {0}",
                                                   teleDiskData.DataSize);

                        AaruConsole.DebugWriteLine("TeleDisk plugin", "\t\tData encoding: 0x{0:X2}",
                                                   teleDiskData.DataEncoding);

                        decodedData = DecodeTeleDiskData(teleDiskSector.SectorSize, teleDiskData.DataEncoding, data);

                        byte tdSectorCalculatedCrc = (byte)(TeleDiskCrc(0, decodedData) & 0xFF);

                        if (tdSectorCalculatedCrc != teleDiskSector.Crc)
                        {
                            AaruConsole.DebugWriteLine("TeleDisk plugin",
                                                       "Sector {0}:{3}:{4} calculated CRC 0x{1:X2} differs from stored CRC 0x{2:X2}",
                                                       teleDiskTrack.Cylinder, tdSectorCalculatedCrc,
                                                       teleDiskSector.Crc, teleDiskTrack.Cylinder,
                                                       teleDiskSector.SectorNumber);

                            if ((teleDiskSector.Flags & FLAGS_SECTOR_NO_ID) != FLAGS_SECTOR_NO_ID)
                            {
                                _sectorsWhereCrcHasFailed.Add(lba);
                            }
                        }
                    }
                    else
                    {
                        decodedData = new byte[128 << teleDiskSector.SectorSize];
                    }

                    AaruConsole.DebugWriteLine("TeleDisk plugin", "\t\tLBA: {0}", lba);

                    if ((teleDiskSector.Flags & FLAGS_SECTOR_NO_ID) == FLAGS_SECTOR_NO_ID)
                    {
                        continue;
                    }

                    if (_sectorsData[teleDiskTrack.Cylinder][teleDiskTrack.Head][teleDiskSector.SectorNumber] != null)
                    {
                        AaruConsole.DebugWriteLine("TeleDisk plugin",
                                                   (teleDiskSector.Flags & FLAGS_SECTOR_DUPLICATE) ==
                                                   FLAGS_SECTOR_DUPLICATE
                                                       ? "\t\tSector {0} on cylinder {1} head {2} is duplicate, and marked so"
                                                       : "\t\tSector {0} on cylinder {1} head {2} is duplicate, but is not marked so",
                                                   teleDiskSector.SectorNumber, teleDiskSector.Cylinder,
                                                   teleDiskSector.Head);
                    }
                    else
                    {
                        _sectorsData[teleDiskTrack.Cylinder][teleDiskTrack.Head][teleDiskSector.SectorNumber] =
                            decodedData;

                        _totalDiskSize += (uint)decodedData.Length;
                    }
                }
            }

            var leadOutMs = new MemoryStream();

            if (hasLeadOutOnHead0)
            {
                for (int i = 0; i < _sectorsData[totalCylinders - 1][0].Length; i++)
                {
                    if (_sectorsData[totalCylinders - 1][0][i] != null)
                    {
                        leadOutMs.Write(_sectorsData[totalCylinders - 1][0][i], 0,
                                        _sectorsData[totalCylinders - 1][0][i].Length);
                    }
                }
            }

            if (hasLeadOutOnHead1)
            {
                for (int i = 0; i < _sectorsData[totalCylinders - 1][1].Length; i++)
                {
                    if (_sectorsData[totalCylinders - 1][1][i] != null)
                    {
                        leadOutMs.Write(_sectorsData[totalCylinders - 1][1][i], 0,
                                        _sectorsData[totalCylinders - 1][1][i].Length);
                    }
                }
            }

            if (leadOutMs.Length != 0)
            {
                _leadOut = leadOutMs.ToArray();
                _imageInfo.ReadableMediaTags.Add(MediaTagType.Floppy_LeadOut);
            }

            _imageInfo.Sectors   = _imageInfo.Cylinders * _imageInfo.Heads * _imageInfo.SectorsPerTrack;
            _imageInfo.MediaType = DecodeTeleDiskDiskType();

            _imageInfo.XmlMediaType = XmlMediaType.BlockMedia;

            AaruConsole.VerboseWriteLine("TeleDisk image contains a disk of type {0}", _imageInfo.MediaType);

            if (!string.IsNullOrEmpty(_imageInfo.Comments))
            {
                AaruConsole.VerboseWriteLine("TeleDisk comments: {0}", _imageInfo.Comments);
            }

            _inStream.Dispose();
            stream.Dispose();

            return(true);
        }
Esempio n. 3
0
        private ArrayList readTrackHeader(Stream f)
        {
            byte[] buf = new byte[7];
            ArrayList sectorHeaderList = new ArrayList();

            f.Read(buf, 0, 4);   // data offset in data block
            int dataOffset = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);

            f.Read(buf, 0, 2);   // reserved

            f.Read(buf, 0, 1);   // sector count
            int sectorCount = buf[0];

            for (int i = 0; i < sectorCount; i++)
            {
                f.Read(buf, 0, 7);
                SectorHeader sh = new SectorHeader();
                sh.C = buf[0];
                sh.H = buf[1];
                sh.R = buf[2];
                sh.N = buf[3];
                sh.Flags = buf[4];
                sh.DataOffset = dataOffset + (buf[5] | (buf[6] << 8));
                sectorHeaderList.Add(sh);
            }
            return sectorHeaderList;
        }
Esempio n. 4
0
File: Read.cs Progetto: paulyc/Aaru
        public bool Open(IFilter imageFilter)
        {
            string comments = string.Empty;
            Stream stream   = imageFilter.GetDataForkStream();

            stream.Seek(0, SeekOrigin.Begin);

            byte[] header = new byte[32];
            stream.Read(header, 0, 32);

            FileHeader fheader = Marshal.ByteArrayToStructureLittleEndian <FileHeader>(header);

            AaruConsole.DebugWriteLine("d2f plugin",
                                       "Detected WC DISK IMAGE with {0} heads, {1} tracks and {2} sectors per track.",
                                       fheader.heads, fheader.cylinders, fheader.sectorsPerTrack);

            _imageInfo.Cylinders       = fheader.cylinders;
            _imageInfo.SectorsPerTrack = fheader.sectorsPerTrack;
            _imageInfo.SectorSize      = 512; // only 512 bytes per sector supported
            _imageInfo.Heads           = fheader.heads;
            _imageInfo.Sectors         = _imageInfo.Heads * _imageInfo.Cylinders * _imageInfo.SectorsPerTrack;
            _imageInfo.ImageSize       = _imageInfo.Sectors * _imageInfo.SectorSize;

            _imageInfo.XmlMediaType = XmlMediaType.BlockMedia;

            _imageInfo.CreationTime         = imageFilter.GetCreationTime();
            _imageInfo.LastModificationTime = imageFilter.GetLastWriteTime();
            _imageInfo.MediaTitle           = Path.GetFileNameWithoutExtension(imageFilter.GetFilename());

            _imageInfo.MediaType = Geometry.GetMediaType(((ushort)_imageInfo.Cylinders, (byte)_imageInfo.Heads,
                                                          (ushort)_imageInfo.SectorsPerTrack, 512, MediaEncoding.MFM,
                                                          false));

            /* buffer the entire disk in memory */
            for (int cyl = 0; cyl < _imageInfo.Cylinders; cyl++)
            {
                for (int head = 0; head < _imageInfo.Heads; head++)
                {
                    ReadTrack(stream, cyl, head);
                }
            }

            /* if there are extra tracks, read them as well */
            if (fheader.extraTracks[0] == 1)
            {
                AaruConsole.DebugWriteLine("d2f plugin", "Extra track 1 (head 0) present, reading");
                ReadTrack(stream, (int)_imageInfo.Cylinders, 0);
            }

            if (fheader.extraTracks[1] == 1)
            {
                AaruConsole.DebugWriteLine("d2f plugin", "Extra track 1 (head 1) present, reading");
                ReadTrack(stream, (int)_imageInfo.Cylinders, 1);
            }

            if (fheader.extraTracks[2] == 1)
            {
                AaruConsole.DebugWriteLine("d2f plugin", "Extra track 2 (head 0) present, reading");
                ReadTrack(stream, (int)_imageInfo.Cylinders + 1, 0);
            }

            if (fheader.extraTracks[3] == 1)
            {
                AaruConsole.DebugWriteLine("d2f plugin", "Extra track 2 (head 1) present, reading");
                ReadTrack(stream, (int)_imageInfo.Cylinders + 1, 1);
            }

            /* adjust number of cylinders */
            if (fheader.extraTracks[0] == 1 ||
                fheader.extraTracks[1] == 1)
            {
                _imageInfo.Cylinders++;
            }

            if (fheader.extraTracks[2] == 1 ||
                fheader.extraTracks[3] == 1)
            {
                _imageInfo.Cylinders++;
            }

            /* read the comment and directory data if present */
            if (fheader.extraFlags.HasFlag(ExtraFlag.Comment))
            {
                AaruConsole.DebugWriteLine("d2f plugin", "Comment present, reading");
                byte[] sheaderBuffer = new byte[6];
                stream.Read(sheaderBuffer, 0, 6);

                SectorHeader sheader = Marshal.ByteArrayToStructureLittleEndian <SectorHeader>(sheaderBuffer);

                if (sheader.flag != SectorFlag.Comment)
                {
                    throw new InvalidDataException($"Invalid sector type '{sheader.flag.ToString()}' encountered");
                }

                byte[] comm = new byte[sheader.crc];
                stream.Read(comm, 0, sheader.crc);
                comments += Encoding.ASCII.GetString(comm) + Environment.NewLine;
            }

            if (fheader.extraFlags.HasFlag(ExtraFlag.Directory))
            {
                AaruConsole.DebugWriteLine("d2f plugin", "Directory listing present, reading");
                byte[] sheaderBuffer = new byte[6];
                stream.Read(sheaderBuffer, 0, 6);

                SectorHeader sheader = Marshal.ByteArrayToStructureLittleEndian <SectorHeader>(sheaderBuffer);

                if (sheader.flag != SectorFlag.Directory)
                {
                    throw new InvalidDataException($"Invalid sector type '{sheader.flag.ToString()}' encountered");
                }

                byte[] dir = new byte[sheader.crc];
                stream.Read(dir, 0, sheader.crc);
                comments += Encoding.ASCII.GetString(dir);
            }

            if (comments.Length > 0)
            {
                _imageInfo.Comments = comments;
            }

            // save some variables for later use
            _fileHeader    = fheader;
            _wcImageFilter = imageFilter;

            return(true);
        }