Beispiel #1
0
        public bool Close()
        {
            if (!IsWriting)
            {
                ErrorMessage = "Image is not opened for writing";

                return(false);
            }

            _writingStream.Seek(0x40 + (17 * 16 * 256), SeekOrigin.Begin);
            byte[] tmp = new byte[256];
            _writingStream.Read(tmp, 0, tmp.Length);

            bool isDos = tmp[0x01] == 17 && tmp[0x02] < 16 && tmp[0x27] <= 122 && tmp[0x34] == 35 && tmp[0x35] == 16 &&
                         tmp[0x36] == 0 && tmp[0x37] == 1;

            _imageHeader = new A2ImgHeader
            {
                Blocks     = (uint)(_imageInfo.Sectors * _imageInfo.SectorSize) / 512,
                Creator    = CREATOR_AARU,
                DataOffset = 0x40,
                DataSize   = (uint)(_imageInfo.Sectors * _imageInfo.SectorSize),
                Flags      = (uint)(_imageInfo.LastMediaSequence != 0
                                   ? VALID_VOLUME_NUMBER + (_imageInfo.MediaSequence & 0xFF) : 0),
                HeaderSize  = 0x40,
                ImageFormat = isDos ? SectorOrder.Dos : SectorOrder.ProDos,
                Magic       = MAGIC,
                Version     = 1
            };

            if (!string.IsNullOrEmpty(_imageInfo.Comments))
            {
                _writingStream.Seek(0, SeekOrigin.End);
                tmp = Encoding.UTF8.GetBytes(_imageInfo.Comments);
                _imageHeader.CommentOffset = (uint)_writingStream.Position;
                _imageHeader.CommentSize   = (uint)(tmp.Length + 1);
                _writingStream.Write(tmp, 0, tmp.Length);
                _writingStream.WriteByte(0);
            }

            byte[] hdr    = new byte[Marshal.SizeOf <A2ImgHeader>()];
            IntPtr hdrPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(Marshal.SizeOf <A2ImgHeader>());

            System.Runtime.InteropServices.Marshal.StructureToPtr(_imageHeader, hdrPtr, true);
            System.Runtime.InteropServices.Marshal.Copy(hdrPtr, hdr, 0, hdr.Length);
            System.Runtime.InteropServices.Marshal.FreeHGlobal(hdrPtr);

            _writingStream.Seek(0, SeekOrigin.Begin);
            _writingStream.Write(hdr, 0, hdr.Length);

            _writingStream.Flush();
            _writingStream.Close();

            IsWriting    = false;
            ErrorMessage = "";

            return(true);
        }
Beispiel #2
0
        public bool Identify(IFilter imageFilter)
        {
            Stream stream = imageFilter.GetDataForkStream();

            stream.Seek(0, SeekOrigin.Begin);

            if (stream.Length < 65)
            {
                return(false);
            }

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

            A2ImgHeader hdr = Marshal.SpanToStructureLittleEndian <A2ImgHeader>(header);

            if (hdr.Magic != MAGIC)
            {
                return(false);
            }

            if (hdr.DataOffset > stream.Length)
            {
                return(false);
            }

            // There seems to be incorrect endian in some images on the wild
            if (hdr.DataSize == 0x00800C00)
            {
                hdr.DataSize = 0x000C8000;
            }

            if (hdr.DataOffset + hdr.DataSize > stream.Length)
            {
                return(false);
            }

            if (hdr.CommentOffset > stream.Length)
            {
                return(false);
            }

            if (hdr.CommentOffset + hdr.CommentSize > stream.Length)
            {
                return(false);
            }

            if (hdr.CreatorSpecificOffset > stream.Length)
            {
                return(false);
            }

            return(hdr.CreatorSpecificOffset + hdr.CreatorSpecificSize <= stream.Length);
        }
Beispiel #3
0
        public bool Open(IFilter imageFilter)
        {
            Stream stream = imageFilter.GetDataForkStream();

            stream.Seek(0, SeekOrigin.Begin);

            imageHeader = new A2ImgHeader();

            byte[] header = new byte[64];
            stream.Read(header, 0, 64);
            byte[] magic   = new byte[4];
            byte[] creator = new byte[4];

            Array.Copy(header, 0, magic, 0, 4);
            Array.Copy(header, 4, creator, 0, 4);

            imageHeader = Marshal.SpanToStructureLittleEndian <A2ImgHeader>(header);

            if (imageHeader.DataSize == 0x00800C00)
            {
                imageHeader.DataSize = 0x000C8000;
                AaruConsole.DebugWriteLine("2MG plugin", "Detected incorrect endian on data size field, correcting.");
            }

            AaruConsole.DebugWriteLine("2MG plugin", "ImageHeader.magic = \"{0}\"", Encoding.ASCII.GetString(magic));

            AaruConsole.DebugWriteLine("2MG plugin", "ImageHeader.creator = \"{0}\"",
                                       Encoding.ASCII.GetString(creator));

            AaruConsole.DebugWriteLine("2MG plugin", "ImageHeader.headerSize = {0}", imageHeader.HeaderSize);
            AaruConsole.DebugWriteLine("2MG plugin", "ImageHeader.version = {0}", imageHeader.Version);
            AaruConsole.DebugWriteLine("2MG plugin", "ImageHeader.imageFormat = {0}", imageHeader.ImageFormat);
            AaruConsole.DebugWriteLine("2MG plugin", "ImageHeader.flags = 0x{0:X8}", imageHeader.Flags);
            AaruConsole.DebugWriteLine("2MG plugin", "ImageHeader.blocks = {0}", imageHeader.Blocks);
            AaruConsole.DebugWriteLine("2MG plugin", "ImageHeader.dataOffset = 0x{0:X8}", imageHeader.DataOffset);
            AaruConsole.DebugWriteLine("2MG plugin", "ImageHeader.dataSize = {0}", imageHeader.DataSize);
            AaruConsole.DebugWriteLine("2MG plugin", "ImageHeader.commentOffset = 0x{0:X8}", imageHeader.CommentOffset);
            AaruConsole.DebugWriteLine("2MG plugin", "ImageHeader.commentSize = {0}", imageHeader.CommentSize);

            AaruConsole.DebugWriteLine("2MG plugin", "ImageHeader.creatorSpecificOffset = 0x{0:X8}",
                                       imageHeader.CreatorSpecificOffset);

            AaruConsole.DebugWriteLine("2MG plugin", "ImageHeader.creatorSpecificSize = {0}",
                                       imageHeader.CreatorSpecificSize);

            AaruConsole.DebugWriteLine("2MG plugin", "ImageHeader.reserved1 = 0x{0:X8}", imageHeader.Reserved1);
            AaruConsole.DebugWriteLine("2MG plugin", "ImageHeader.reserved2 = 0x{0:X8}", imageHeader.Reserved2);
            AaruConsole.DebugWriteLine("2MG plugin", "ImageHeader.reserved3 = 0x{0:X8}", imageHeader.Reserved3);
            AaruConsole.DebugWriteLine("2MG plugin", "ImageHeader.reserved4 = 0x{0:X8}", imageHeader.Reserved4);

            if (imageHeader.DataSize == 0 &&
                imageHeader.Blocks == 0 &&
                imageHeader.ImageFormat != SectorOrder.ProDos)
            {
                return(false);
            }

            byte[] tmp;
            int[]  offsets;

            switch (imageHeader.ImageFormat)
            {
            case SectorOrder.Nibbles:
                tmp = new byte[imageHeader.DataSize];
                stream.Seek(imageHeader.DataOffset, SeekOrigin.Begin);
                stream.Read(tmp, 0, tmp.Length);
                var nibPlugin = new AppleNib();
                var noFilter  = new ZZZNoFilter();
                noFilter.Open(tmp);
                nibPlugin.Open(noFilter);
                decodedImage         = nibPlugin.ReadSectors(0, (uint)nibPlugin.Info.Sectors);
                imageInfo.Sectors    = nibPlugin.Info.Sectors;
                imageInfo.SectorSize = nibPlugin.Info.SectorSize;

                break;

            case SectorOrder.Dos when imageHeader.DataSize == 143360:
            case SectorOrder.ProDos when imageHeader.DataSize == 143360:
                stream.Seek(imageHeader.DataOffset, SeekOrigin.Begin);
                tmp = new byte[imageHeader.DataSize];
                stream.Read(tmp, 0, tmp.Length);

                bool isDos = tmp[0x11001] == 17 && tmp[0x11002] < 16 && tmp[0x11027] <= 122 && tmp[0x11034] == 35 &&
                             tmp[0x11035] == 16 && tmp[0x11036] == 0 && tmp[0x11037] == 1;

                decodedImage = new byte[imageHeader.DataSize];

                offsets = imageHeader.ImageFormat == SectorOrder.Dos
                                  ? isDos
                                        ? deinterleave
                                        : interleave
                                  : isDos
                                      ? interleave
                                      : deinterleave;

                for (int t = 0; t < 35; t++)
                {
                    for (int s = 0; s < 16; s++)
                    {
                        Array.Copy(tmp, (t * 16 * 256) + (s * 256), decodedImage,
                                   (t * 16 * 256) + (offsets[s] * 256), 256);
                    }
                }

                imageInfo.Sectors    = 560;
                imageInfo.SectorSize = 256;

                break;

            case SectorOrder.Dos when imageHeader.DataSize == 819200:
                stream.Seek(imageHeader.DataOffset, SeekOrigin.Begin);
                tmp = new byte[imageHeader.DataSize];
                stream.Read(tmp, 0, tmp.Length);
                decodedImage = new byte[imageHeader.DataSize];
                offsets      = interleave;

                for (int t = 0; t < 200; t++)
                {
                    for (int s = 0; s < 16; s++)
                    {
                        Array.Copy(tmp, (t * 16 * 256) + (s * 256), decodedImage,
                                   (t * 16 * 256) + (offsets[s] * 256), 256);
                    }
                }

                imageInfo.Sectors    = 1600;
                imageInfo.SectorSize = 512;

                break;

            default:
                decodedImage         = null;
                imageInfo.SectorSize = 512;
                imageInfo.Sectors    = imageHeader.DataSize / 512;

                break;
            }

            imageInfo.ImageSize = imageHeader.DataSize;

            switch (imageHeader.Creator)
            {
            case CREATOR_ASIMOV:
                imageInfo.Application = "ASIMOV2";

                break;

            case CREATOR_BERNIE:
                imageInfo.Application = "Bernie ][ the Rescue";

                break;

            case CREATOR_CATAKIG:
                imageInfo.Application = "Catakig";

                break;

            case CREATOR_SHEPPY:
                imageInfo.Application = "Sheppy's ImageMaker";

                break;

            case CREATOR_SWEET:
                imageInfo.Application = "Sweet16";

                break;

            case CREATOR_XGS:
                imageInfo.Application = "XGS";

                break;

            case CREATOR_CIDER:
                imageInfo.Application = "CiderPress";

                break;

            case CREATOR_DIC:
                imageInfo.Application = "DiscImageChef";

                break;

            case CREATOR_AARU:
                imageInfo.Application = "Aaru";

                break;

            default:
                imageInfo.Application = $"Unknown creator code \"{Encoding.ASCII.GetString(creator)}\"";

                break;
            }

            imageInfo.Version = imageHeader.Version.ToString();

            if (imageHeader.CommentOffset != 0 &&
                imageHeader.CommentSize != 0)
            {
                stream.Seek(imageHeader.CommentOffset, SeekOrigin.Begin);

                byte[] comments = new byte[imageHeader.CommentSize];
                stream.Read(comments, 0, (int)imageHeader.CommentSize);
                imageInfo.Comments = Encoding.ASCII.GetString(comments);
            }

            imageInfo.CreationTime         = imageFilter.GetCreationTime();
            imageInfo.LastModificationTime = imageFilter.GetLastWriteTime();
            imageInfo.MediaTitle           = Path.GetFileNameWithoutExtension(imageFilter.GetFilename());
            imageInfo.MediaType            = GetMediaType();

            a2MgImageFilter = imageFilter;

            imageInfo.XmlMediaType = XmlMediaType.BlockMedia;

            AaruConsole.VerboseWriteLine("2MG image contains a disk of type {0}", imageInfo.MediaType);

            if (!string.IsNullOrEmpty(imageInfo.Comments))
            {
                AaruConsole.VerboseWriteLine("2MG comments: {0}", imageInfo.Comments);
            }

            switch (imageInfo.MediaType)
            {
            case MediaType.Apple32SS:
                imageInfo.Cylinders       = 35;
                imageInfo.Heads           = 1;
                imageInfo.SectorsPerTrack = 13;

                break;

            case MediaType.Apple32DS:
                imageInfo.Cylinders       = 35;
                imageInfo.Heads           = 2;
                imageInfo.SectorsPerTrack = 13;

                break;

            case MediaType.Apple33SS:
                imageInfo.Cylinders       = 35;
                imageInfo.Heads           = 1;
                imageInfo.SectorsPerTrack = 16;

                break;

            case MediaType.Apple33DS:
                imageInfo.Cylinders       = 35;
                imageInfo.Heads           = 2;
                imageInfo.SectorsPerTrack = 16;

                break;

            case MediaType.AppleSonySS:
                imageInfo.Cylinders = 80;
                imageInfo.Heads     = 1;

                // Variable sectors per track, this suffices
                imageInfo.SectorsPerTrack = 10;

                break;

            case MediaType.AppleSonyDS:
                imageInfo.Cylinders = 80;
                imageInfo.Heads     = 2;

                // Variable sectors per track, this suffices
                imageInfo.SectorsPerTrack = 10;

                break;

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

                break;
            }

            return(true);
        }