Exemplo n.º 1
0
        public void Open(string path)
        {
            var fs = new FileStream(path, FileMode.Open, FileAccess.Read);

            fs.Seek(0, SeekOrigin.Begin);

            byte[] hdrB = new byte[128];
            fs.Read(hdrB, 0, 128);
            _header = Marshal.ByteArrayToStructureBigEndian <Header>(hdrB);

            uint blocks = 1;

            blocks += (uint)(_header.secondaryHeaderLength / 128);

            if (_header.secondaryHeaderLength % 128 > 0)
            {
                blocks++;
            }

            _dataForkOff = blocks * 128;
            blocks      += _header.dataLength / 128;

            if (_header.dataLength % 128 > 0)
            {
                blocks++;
            }

            _rsrcForkOff = blocks * 128;

            _filename      = StringHandlers.PascalToString(_header.filename, Encoding.GetEncoding("macintosh"));
            _creationTime  = DateHandlers.MacToDateTime(_header.creationTime);
            _lastWriteTime = DateHandlers.MacToDateTime(_header.modificationTime);

            fs.Close();
            _opened   = true;
            _isPath   = true;
            _basePath = path;
        }
Exemplo n.º 2
0
        public void Open(byte[] buffer)
        {
            var ms = new MemoryStream(buffer);

            ms.Seek(0, SeekOrigin.Begin);

            byte[] hdrB = new byte[128];
            ms.Read(hdrB, 0, 128);
            _header = Marshal.ByteArrayToStructureBigEndian <Header>(hdrB);

            uint blocks = 1;

            blocks += (uint)(_header.secondaryHeaderLength / 128);

            if (_header.secondaryHeaderLength % 128 > 0)
            {
                blocks++;
            }

            _dataForkOff = blocks * 128;
            blocks      += _header.dataLength / 128;

            if (_header.dataLength % 128 > 0)
            {
                blocks++;
            }

            _rsrcForkOff = blocks * 128;

            _filename      = StringHandlers.PascalToString(_header.filename, Encoding.GetEncoding("macintosh"));
            _creationTime  = DateHandlers.MacToDateTime(_header.creationTime);
            _lastWriteTime = DateHandlers.MacToDateTime(_header.modificationTime);

            ms.Close();
            _opened  = true;
            _isBytes = true;
            _bytes   = buffer;
        }
Exemplo n.º 3
0
        public Errno ReadDir(string path, out List <string> contents)
        {
            contents = null;
            if (!mounted)
            {
                return(Errno.AccessDenied);
            }

            if (!string.IsNullOrEmpty(path) && string.Compare(path, "/", StringComparison.OrdinalIgnoreCase) != 0)
            {
                return(Errno.NotSupported);
            }

            contents = fileEntries.Select(ent => StringHandlers.PascalToString(ent.Filename, Encoding)).ToList();

            if (debug)
            {
                contents.Add("$");
                contents.Add("$Boot");
            }

            contents.Sort();
            return(Errno.NoError);
        }
Exemplo n.º 4
0
        public void Open(Stream stream)
        {
            stream.Seek(0, SeekOrigin.Begin);

            byte[] hdr_b = new byte[128];
            stream.Read(hdr_b, 0, 128);
            header = Marshal.ByteArrayToStructureBigEndian <MacBinaryHeader>(hdr_b);

            uint blocks = 1;

            blocks += (uint)(header.secondaryHeaderLength / 128);

            if (header.secondaryHeaderLength % 128 > 0)
            {
                blocks++;
            }

            dataForkOff = blocks * 128;
            blocks     += header.dataLength / 128;

            if (header.dataLength % 128 > 0)
            {
                blocks++;
            }

            rsrcForkOff = blocks * 128;

            filename      = StringHandlers.PascalToString(header.filename, Encoding.GetEncoding("macintosh"));
            creationTime  = DateHandlers.MacToDateTime(header.creationTime);
            lastWriteTime = DateHandlers.MacToDateTime(header.modificationTime);

            stream.Seek(0, SeekOrigin.Begin);
            opened      = true;
            isStream    = true;
            this.stream = stream;
        }
Exemplo n.º 5
0
        public Errno Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding,
                           Dictionary <string, string> options, string @namespace)
        {
            device         = imagePlugin;
            partitionStart = partition.Start;
            Encoding       = encoding ?? Encoding.GetEncoding("macintosh");
            if (options == null)
            {
                options = GetDefaultOptions();
            }
            if (options.TryGetValue("debug", out string debugString))
            {
                bool.TryParse(debugString, out debug);
            }
            volMDB = new MFS_MasterDirectoryBlock();

            mdbBlocks  = device.ReadSector(2 + partitionStart);
            bootBlocks = device.ReadSector(0 + partitionStart);

            volMDB.drSigWord = BigEndianBitConverter.ToUInt16(mdbBlocks, 0x000);
            if (volMDB.drSigWord != MFS_MAGIC)
            {
                return(Errno.InvalidArgument);
            }

            volMDB.drCrDate   = BigEndianBitConverter.ToUInt32(mdbBlocks, 0x002);
            volMDB.drLsBkUp   = BigEndianBitConverter.ToUInt32(mdbBlocks, 0x006);
            volMDB.drAtrb     = BigEndianBitConverter.ToUInt16(mdbBlocks, 0x00A);
            volMDB.drNmFls    = BigEndianBitConverter.ToUInt16(mdbBlocks, 0x00C);
            volMDB.drDirSt    = BigEndianBitConverter.ToUInt16(mdbBlocks, 0x00E);
            volMDB.drBlLen    = BigEndianBitConverter.ToUInt16(mdbBlocks, 0x010);
            volMDB.drNmAlBlks = BigEndianBitConverter.ToUInt16(mdbBlocks, 0x012);
            volMDB.drAlBlkSiz = BigEndianBitConverter.ToUInt32(mdbBlocks, 0x014);
            volMDB.drClpSiz   = BigEndianBitConverter.ToUInt32(mdbBlocks, 0x018);
            volMDB.drAlBlSt   = BigEndianBitConverter.ToUInt16(mdbBlocks, 0x01C);
            volMDB.drNxtFNum  = BigEndianBitConverter.ToUInt32(mdbBlocks, 0x01E);
            volMDB.drFreeBks  = BigEndianBitConverter.ToUInt16(mdbBlocks, 0x022);
            volMDB.drVNSiz    = mdbBlocks[0x024];
            byte[] variableSize = new byte[volMDB.drVNSiz + 1];
            Array.Copy(mdbBlocks, 0x024, variableSize, 0, volMDB.drVNSiz + 1);
            volMDB.drVN = StringHandlers.PascalToString(variableSize, Encoding);

            directoryBlocks = device.ReadSectors(volMDB.drDirSt + partitionStart, volMDB.drBlLen);
            int       bytesInBlockMap        = volMDB.drNmAlBlks * 12 / 8 + volMDB.drNmAlBlks * 12 % 8;
            const int BYTES_BEFORE_BLOCK_MAP = 64;
            int       bytesInWholeMdb        = bytesInBlockMap + BYTES_BEFORE_BLOCK_MAP;
            int       sectorsInWholeMdb      = bytesInWholeMdb / (int)device.Info.SectorSize +
                                               bytesInWholeMdb % (int)device.Info.SectorSize;

            byte[] wholeMdb = device.ReadSectors(partitionStart + 2, (uint)sectorsInWholeMdb);
            blockMapBytes = new byte[bytesInBlockMap];
            Array.Copy(wholeMdb, BYTES_BEFORE_BLOCK_MAP, blockMapBytes, 0, blockMapBytes.Length);

            int offset = 0;

            blockMap = new uint[volMDB.drNmAlBlks + 2 + 1];
            for (int i = 2; i < volMDB.drNmAlBlks + 2; i += 8)
            {
                uint tmp1 = 0;
                uint tmp2 = 0;
                uint tmp3 = 0;

                if (offset + 4 <= blockMapBytes.Length)
                {
                    tmp1 = BigEndianBitConverter.ToUInt32(blockMapBytes, offset);
                }
                if (offset + 4 + 4 <= blockMapBytes.Length)
                {
                    tmp2 = BigEndianBitConverter.ToUInt32(blockMapBytes, offset + 4);
                }
                if (offset + 8 + 4 <= blockMapBytes.Length)
                {
                    tmp3 = BigEndianBitConverter.ToUInt32(blockMapBytes, offset + 8);
                }

                if (i < blockMap.Length)
                {
                    blockMap[i] = (tmp1 & 0xFFF00000) >> 20;
                }
                if (i + 2 < blockMap.Length)
                {
                    blockMap[i + 1] = (tmp1 & 0xFFF00) >> 8;
                }
                if (i + 3 < blockMap.Length)
                {
                    blockMap[i + 2] = ((tmp1 & 0xFF) << 4) + ((tmp2 & 0xF0000000) >> 28);
                }
                if (i + 4 < blockMap.Length)
                {
                    blockMap[i + 3] = (tmp2 & 0xFFF0000) >> 16;
                }
                if (i + 5 < blockMap.Length)
                {
                    blockMap[i + 4] = (tmp2 & 0xFFF0) >> 4;
                }
                if (i + 6 < blockMap.Length)
                {
                    blockMap[i + 5] = ((tmp2 & 0xF) << 8) + ((tmp3 & 0xFF000000) >> 24);
                }
                if (i + 7 < blockMap.Length)
                {
                    blockMap[i + 6] = (tmp3 & 0xFFF000) >> 12;
                }
                if (i + 8 < blockMap.Length)
                {
                    blockMap[i + 7] = tmp3 & 0xFFF;
                }

                offset += 12;
            }

            if (device.Info.ReadableSectorTags.Contains(SectorTagType.AppleSectorTag))
            {
                mdbTags       = device.ReadSectorTag(2 + partitionStart, SectorTagType.AppleSectorTag);
                bootTags      = device.ReadSectorTag(0 + partitionStart, SectorTagType.AppleSectorTag);
                directoryTags = device.ReadSectorsTag(volMDB.drDirSt + partitionStart, volMDB.drBlLen,
                                                      SectorTagType.AppleSectorTag);
                bitmapTags = device.ReadSectorsTag(partitionStart + 2, (uint)sectorsInWholeMdb,
                                                   SectorTagType.AppleSectorTag);
            }

            sectorsPerBlock = (int)(volMDB.drAlBlkSiz / device.Info.SectorSize);

            if (!FillDirectory())
            {
                return(Errno.InvalidArgument);
            }

            mounted = true;

            ushort bbSig = BigEndianBitConverter.ToUInt16(bootBlocks, 0x000);

            if (bbSig != MFSBB_MAGIC)
            {
                bootBlocks = null;
            }

            XmlFsType = new FileSystemType();
            if (volMDB.drLsBkUp > 0)
            {
                XmlFsType.BackupDate          = DateHandlers.MacToDateTime(volMDB.drLsBkUp);
                XmlFsType.BackupDateSpecified = true;
            }

            XmlFsType.Bootable    = bbSig == MFSBB_MAGIC;
            XmlFsType.Clusters    = volMDB.drNmAlBlks;
            XmlFsType.ClusterSize = volMDB.drAlBlkSiz;
            if (volMDB.drCrDate > 0)
            {
                XmlFsType.CreationDate          = DateHandlers.MacToDateTime(volMDB.drCrDate);
                XmlFsType.CreationDateSpecified = true;
            }

            XmlFsType.Files                 = volMDB.drNmFls;
            XmlFsType.FilesSpecified        = true;
            XmlFsType.FreeClusters          = volMDB.drFreeBks;
            XmlFsType.FreeClustersSpecified = true;
            XmlFsType.Type       = "MFS";
            XmlFsType.VolumeName = volMDB.drVN;

            return(Errno.NoError);
        }
Exemplo n.º 6
0
Arquivo: Info.cs Projeto: paulyc/Aaru
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding = encoding ?? new Apple2();
            var sbInformation = new StringBuilder();

            information = "";
            _multiplier = (uint)(imagePlugin.Info.SectorSize == 256 ? 2 : 1);

            if (imagePlugin.Info.Sectors < 3)
            {
                return;
            }

            // Blocks 0 and 1 are boot code
            byte[] volBlock = imagePlugin.ReadSectors((_multiplier * 2) + partition.Start, _multiplier);

            // On Apple //, it's little endian
            // TODO: Fix
            //BigEndianBitConverter.IsLittleEndian =
            //    multiplier == 2 ? !BitConverter.IsLittleEndian : BitConverter.IsLittleEndian;

            var volEntry = new PascalVolumeEntry
            {
                FirstBlock = BigEndianBitConverter.ToInt16(volBlock, 0x00),
                LastBlock  = BigEndianBitConverter.ToInt16(volBlock, 0x02),
                EntryType  = (PascalFileKind)BigEndianBitConverter.ToInt16(volBlock, 0x04),
                VolumeName = new byte[8],
                Blocks     = BigEndianBitConverter.ToInt16(volBlock, 0x0E),
                Files      = BigEndianBitConverter.ToInt16(volBlock, 0x10),
                Dummy      = BigEndianBitConverter.ToInt16(volBlock, 0x12),
                LastBoot   = BigEndianBitConverter.ToInt16(volBlock, 0x14),
                Tail       = BigEndianBitConverter.ToInt32(volBlock, 0x16)
            };

            Array.Copy(volBlock, 0x06, volEntry.VolumeName, 0, 8);

            // First block is always 0 (even is it's sector 2)
            if (volEntry.FirstBlock != 0)
            {
                return;
            }

            // Last volume record block must be after first block, and before end of device
            if (volEntry.LastBlock <= volEntry.FirstBlock ||
                (ulong)volEntry.LastBlock > (imagePlugin.Info.Sectors / _multiplier) - 2)
            {
                return;
            }

            // Volume record entry type must be volume or secure
            if (volEntry.EntryType != PascalFileKind.Volume &&
                volEntry.EntryType != PascalFileKind.Secure)
            {
                return;
            }

            // Volume name is max 7 characters
            if (volEntry.VolumeName[0] > 7)
            {
                return;
            }

            // Volume blocks is equal to volume sectors
            if (volEntry.Blocks < 0 ||
                (ulong)volEntry.Blocks != imagePlugin.Info.Sectors / _multiplier)
            {
                return;
            }

            // There can be not less than zero files
            if (volEntry.Files < 0)
            {
                return;
            }

            sbInformation.AppendFormat("Volume record spans from block {0} to block {1}", volEntry.FirstBlock,
                                       volEntry.LastBlock).AppendLine();

            sbInformation.
            AppendFormat("Volume name: {0}", StringHandlers.PascalToString(volEntry.VolumeName, Encoding)).
            AppendLine();

            sbInformation.AppendFormat("Volume has {0} blocks", volEntry.Blocks).AppendLine();
            sbInformation.AppendFormat("Volume has {0} files", volEntry.Files).AppendLine();

            sbInformation.
            AppendFormat("Volume last booted at {0}", DateHandlers.UcsdPascalToDateTime(volEntry.LastBoot)).
            AppendLine();

            information = sbInformation.ToString();

            XmlFsType = new FileSystemType
            {
                Bootable       = !ArrayHelpers.ArrayIsNullOrEmpty(imagePlugin.ReadSectors(partition.Start, _multiplier * 2)),
                Clusters       = (ulong)volEntry.Blocks,
                ClusterSize    = imagePlugin.Info.SectorSize,
                Files          = (ulong)volEntry.Files,
                FilesSpecified = true,
                Type           = "UCSD Pascal",
                VolumeName     = StringHandlers.PascalToString(volEntry.VolumeName, Encoding)
            };
        }
Exemplo n.º 7
0
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding    = encoding ?? new MacRoman();
            information = "";

            var sb = new StringBuilder();

            var mdb = new MasterDirectoryBlock();

            byte[] mdbSector = imagePlugin.ReadSector(2 + partition.Start);
            byte[] bbSector  = imagePlugin.ReadSector(0 + partition.Start);

            mdb.drSigWord = BigEndianBitConverter.ToUInt16(mdbSector, 0x000);

            if (mdb.drSigWord != MFS_MAGIC)
            {
                return;
            }

            mdb.drCrDate   = BigEndianBitConverter.ToUInt32(mdbSector, 0x002);
            mdb.drLsBkUp   = BigEndianBitConverter.ToUInt32(mdbSector, 0x006);
            mdb.drAtrb     = (AppleCommon.VolumeAttributes)BigEndianBitConverter.ToUInt16(mdbSector, 0x00A);
            mdb.drNmFls    = BigEndianBitConverter.ToUInt16(mdbSector, 0x00C);
            mdb.drDirSt    = BigEndianBitConverter.ToUInt16(mdbSector, 0x00E);
            mdb.drBlLen    = BigEndianBitConverter.ToUInt16(mdbSector, 0x010);
            mdb.drNmAlBlks = BigEndianBitConverter.ToUInt16(mdbSector, 0x012);
            mdb.drAlBlkSiz = BigEndianBitConverter.ToUInt32(mdbSector, 0x014);
            mdb.drClpSiz   = BigEndianBitConverter.ToUInt32(mdbSector, 0x018);
            mdb.drAlBlSt   = BigEndianBitConverter.ToUInt16(mdbSector, 0x01C);
            mdb.drNxtFNum  = BigEndianBitConverter.ToUInt32(mdbSector, 0x01E);
            mdb.drFreeBks  = BigEndianBitConverter.ToUInt16(mdbSector, 0x022);
            mdb.drVNSiz    = mdbSector[0x024];
            byte[] variableSize = new byte[mdb.drVNSiz + 1];
            Array.Copy(mdbSector, 0x024, variableSize, 0, mdb.drVNSiz + 1);
            mdb.drVN = StringHandlers.PascalToString(variableSize, Encoding);

            sb.AppendLine("Apple Macintosh File System");
            sb.AppendLine();
            sb.AppendLine("Master Directory Block:");
            sb.AppendFormat("Creation date: {0}", DateHandlers.MacToDateTime(mdb.drCrDate)).AppendLine();
            sb.AppendFormat("Last backup date: {0}", DateHandlers.MacToDateTime(mdb.drLsBkUp)).AppendLine();

            if (mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.HardwareLock))
            {
                sb.AppendLine("Volume is locked by hardware.");
            }

            sb.AppendLine(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.Unmounted) ? "Volume was unmonted."
                              : "Volume is mounted.");

            if (mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.SparedBadBlocks))
            {
                sb.AppendLine("Volume has spared bad blocks.");
            }

            if (mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.DoesNotNeedCache))
            {
                sb.AppendLine("Volume does not need cache.");
            }

            if (mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.BootInconsistent))
            {
                sb.AppendLine("Boot volume is inconsistent.");
            }

            if (mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.ReusedIds))
            {
                sb.AppendLine("There are reused CNIDs.");
            }

            if (mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.Inconsistent))
            {
                sb.AppendLine("Volume is seriously inconsistent.");
            }

            if (mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.SoftwareLock))
            {
                sb.AppendLine("Volume is locked by software.");
            }

            sb.AppendFormat("{0} files on volume", mdb.drNmFls).AppendLine();
            sb.AppendFormat("First directory sector: {0}", mdb.drDirSt).AppendLine();
            sb.AppendFormat("{0} sectors in directory.", mdb.drBlLen).AppendLine();
            sb.AppendFormat("{0} volume allocation blocks.", mdb.drNmAlBlks + 1).AppendLine();
            sb.AppendFormat("Size of allocation blocks: {0} bytes", mdb.drAlBlkSiz).AppendLine();
            sb.AppendFormat("{0} bytes to allocate.", mdb.drClpSiz).AppendLine();
            sb.AppendFormat("First allocation block (#2) starts in sector {0}.", mdb.drAlBlSt).AppendLine();
            sb.AppendFormat("Next unused file number: {0}", mdb.drNxtFNum).AppendLine();
            sb.AppendFormat("{0} unused allocation blocks.", mdb.drFreeBks).AppendLine();
            sb.AppendFormat("Volume name: {0}", mdb.drVN).AppendLine();

            string bootBlockInfo = AppleCommon.GetBootBlockInformation(bbSector, Encoding);

            if (bootBlockInfo != null)
            {
                sb.AppendLine("Volume is bootable.");
                sb.AppendLine();
                sb.AppendLine(bootBlockInfo);
            }
            else
            {
                sb.AppendLine("Volume is not bootable.");
            }

            information = sb.ToString();

            XmlFsType = new FileSystemType();

            if (mdb.drLsBkUp > 0)
            {
                XmlFsType.BackupDate          = DateHandlers.MacToDateTime(mdb.drLsBkUp);
                XmlFsType.BackupDateSpecified = true;
            }

            XmlFsType.Bootable    = bootBlockInfo != null;
            XmlFsType.Clusters    = mdb.drNmAlBlks;
            XmlFsType.ClusterSize = mdb.drAlBlkSiz;

            if (mdb.drCrDate > 0)
            {
                XmlFsType.CreationDate          = DateHandlers.MacToDateTime(mdb.drCrDate);
                XmlFsType.CreationDateSpecified = true;
            }

            XmlFsType.Files                 = mdb.drNmFls;
            XmlFsType.FilesSpecified        = true;
            XmlFsType.FreeClusters          = mdb.drFreeBks;
            XmlFsType.FreeClustersSpecified = true;
            XmlFsType.Type       = "MFS";
            XmlFsType.VolumeName = mdb.drVN;
        }
Exemplo n.º 8
0
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding    = new LisaRoman();
            information = "";
            StringBuilder sb = new StringBuilder();

            try
            {
                if (imagePlugin.Info.ReadableSectorTags == null)
                {
                    return;
                }

                if (!imagePlugin.Info.ReadableSectorTags.Contains(SectorTagType.AppleSectorTag))
                {
                    return;
                }

                // Minimal LisaOS disk is 3.5" single sided double density, 800 sectors
                if (imagePlugin.Info.Sectors < 800)
                {
                    return;
                }

                int beforeMddf = -1;

                // LisaOS searches sectors until tag tells MDDF resides there, so we'll search 100 sectors
                for (int i = 0; i < 100; i++)
                {
                    DecodeTag(imagePlugin.ReadSectorTag((ulong)i, SectorTagType.AppleSectorTag),
                              out LisaTag.PriamTag searchTag);

                    DicConsole.DebugWriteLine("LisaFS plugin", "Sector {0}, file ID 0x{1:X4}", i, searchTag.FileId);

                    if (beforeMddf == -1 && searchTag.FileId == FILEID_LOADER_SIGNED)
                    {
                        beforeMddf = i - 1;
                    }

                    if (searchTag.FileId != FILEID_MDDF)
                    {
                        continue;
                    }

                    byte[] sector   = imagePlugin.ReadSector((ulong)i);
                    MDDF   infoMddf = new MDDF();
                    byte[] pString  = new byte[33];

                    infoMddf.fsversion = BigEndianBitConverter.ToUInt16(sector, 0x00);
                    infoMddf.volid     = BigEndianBitConverter.ToUInt64(sector, 0x02);
                    infoMddf.volnum    = BigEndianBitConverter.ToUInt16(sector, 0x0A);
                    Array.Copy(sector, 0x0C, pString, 0, 33);
                    infoMddf.volname  = StringHandlers.PascalToString(pString, Encoding);
                    infoMddf.unknown1 = sector[0x2D];
                    Array.Copy(sector, 0x2E, pString, 0, 33);
                    // Prevent garbage
                    infoMddf.password       = pString[0] <= 32 ? StringHandlers.PascalToString(pString, Encoding) : "";
                    infoMddf.unknown2       = sector[0x4F];
                    infoMddf.machine_id     = BigEndianBitConverter.ToUInt32(sector, 0x50);
                    infoMddf.master_copy_id = BigEndianBitConverter.ToUInt32(sector, 0x54);
                    uint lisaTime = BigEndianBitConverter.ToUInt32(sector, 0x58);
                    infoMddf.dtvc                         = DateHandlers.LisaToDateTime(lisaTime);
                    lisaTime                              = BigEndianBitConverter.ToUInt32(sector, 0x5C);
                    infoMddf.dtcc                         = DateHandlers.LisaToDateTime(lisaTime);
                    lisaTime                              = BigEndianBitConverter.ToUInt32(sector, 0x60);
                    infoMddf.dtvb                         = DateHandlers.LisaToDateTime(lisaTime);
                    lisaTime                              = BigEndianBitConverter.ToUInt32(sector, 0x64);
                    infoMddf.dtvs                         = DateHandlers.LisaToDateTime(lisaTime);
                    infoMddf.unknown3                     = BigEndianBitConverter.ToUInt32(sector, 0x68);
                    infoMddf.mddf_block                   = BigEndianBitConverter.ToUInt32(sector, 0x6C);
                    infoMddf.volsize_minus_one            = BigEndianBitConverter.ToUInt32(sector, 0x70);
                    infoMddf.volsize_minus_mddf_minus_one = BigEndianBitConverter.ToUInt32(sector, 0x74);
                    infoMddf.vol_size                     = BigEndianBitConverter.ToUInt32(sector, 0x78);
                    infoMddf.blocksize                    = BigEndianBitConverter.ToUInt16(sector, 0x7C);
                    infoMddf.datasize                     = BigEndianBitConverter.ToUInt16(sector, 0x7E);
                    infoMddf.unknown4                     = BigEndianBitConverter.ToUInt16(sector, 0x80);
                    infoMddf.unknown5                     = BigEndianBitConverter.ToUInt32(sector, 0x82);
                    infoMddf.unknown6                     = BigEndianBitConverter.ToUInt32(sector, 0x86);
                    infoMddf.clustersize                  = BigEndianBitConverter.ToUInt16(sector, 0x8A);
                    infoMddf.fs_size                      = BigEndianBitConverter.ToUInt32(sector, 0x8C);
                    infoMddf.unknown7                     = BigEndianBitConverter.ToUInt32(sector, 0x90);
                    infoMddf.srec_ptr                     = BigEndianBitConverter.ToUInt32(sector, 0x94);
                    infoMddf.unknown9                     = BigEndianBitConverter.ToUInt16(sector, 0x98);
                    infoMddf.srec_len                     = BigEndianBitConverter.ToUInt16(sector, 0x9A);
                    infoMddf.unknown10                    = BigEndianBitConverter.ToUInt32(sector, 0x9C);
                    infoMddf.unknown11                    = BigEndianBitConverter.ToUInt32(sector, 0xA0);
                    infoMddf.unknown12                    = BigEndianBitConverter.ToUInt32(sector, 0xA4);
                    infoMddf.unknown13                    = BigEndianBitConverter.ToUInt32(sector, 0xA8);
                    infoMddf.unknown14                    = BigEndianBitConverter.ToUInt32(sector, 0xAC);
                    infoMddf.filecount                    = BigEndianBitConverter.ToUInt16(sector, 0xB0);
                    infoMddf.unknown15                    = BigEndianBitConverter.ToUInt32(sector, 0xB2);
                    infoMddf.unknown16                    = BigEndianBitConverter.ToUInt32(sector, 0xB6);
                    infoMddf.freecount                    = BigEndianBitConverter.ToUInt32(sector, 0xBA);
                    infoMddf.unknown17                    = BigEndianBitConverter.ToUInt16(sector, 0xBE);
                    infoMddf.unknown18                    = BigEndianBitConverter.ToUInt32(sector, 0xC0);
                    infoMddf.overmount_stamp              = BigEndianBitConverter.ToUInt64(sector, 0xC4);
                    infoMddf.serialization                = BigEndianBitConverter.ToUInt32(sector, 0xCC);
                    infoMddf.unknown19                    = BigEndianBitConverter.ToUInt32(sector, 0xD0);
                    infoMddf.unknown_timestamp            = BigEndianBitConverter.ToUInt32(sector, 0xD4);
                    infoMddf.unknown20                    = BigEndianBitConverter.ToUInt32(sector, 0xD8);
                    infoMddf.unknown21                    = BigEndianBitConverter.ToUInt32(sector, 0xDC);
                    infoMddf.unknown22                    = BigEndianBitConverter.ToUInt32(sector, 0xE0);
                    infoMddf.unknown23                    = BigEndianBitConverter.ToUInt32(sector, 0xE4);
                    infoMddf.unknown24                    = BigEndianBitConverter.ToUInt32(sector, 0xE8);
                    infoMddf.unknown25                    = BigEndianBitConverter.ToUInt32(sector, 0xEC);
                    infoMddf.unknown26                    = BigEndianBitConverter.ToUInt32(sector, 0xF0);
                    infoMddf.unknown27                    = BigEndianBitConverter.ToUInt32(sector, 0xF4);
                    infoMddf.unknown28                    = BigEndianBitConverter.ToUInt32(sector, 0xF8);
                    infoMddf.unknown29                    = BigEndianBitConverter.ToUInt32(sector, 0xFC);
                    infoMddf.unknown30                    = BigEndianBitConverter.ToUInt32(sector, 0x100);
                    infoMddf.unknown31                    = BigEndianBitConverter.ToUInt32(sector, 0x104);
                    infoMddf.unknown32                    = BigEndianBitConverter.ToUInt32(sector, 0x108);
                    infoMddf.unknown33                    = BigEndianBitConverter.ToUInt32(sector, 0x10C);
                    infoMddf.unknown34                    = BigEndianBitConverter.ToUInt32(sector, 0x110);
                    infoMddf.unknown35                    = BigEndianBitConverter.ToUInt32(sector, 0x114);
                    infoMddf.backup_volid                 = BigEndianBitConverter.ToUInt64(sector, 0x118);
                    infoMddf.label_size                   = BigEndianBitConverter.ToUInt16(sector, 0x120);
                    infoMddf.fs_overhead                  = BigEndianBitConverter.ToUInt16(sector, 0x122);
                    infoMddf.result_scavenge              = BigEndianBitConverter.ToUInt16(sector, 0x124);
                    infoMddf.boot_code                    = BigEndianBitConverter.ToUInt16(sector, 0x126);
                    infoMddf.boot_environ                 = BigEndianBitConverter.ToUInt16(sector, 0x6C);
                    infoMddf.unknown36                    = BigEndianBitConverter.ToUInt32(sector, 0x12A);
                    infoMddf.unknown37                    = BigEndianBitConverter.ToUInt32(sector, 0x12E);
                    infoMddf.unknown38                    = BigEndianBitConverter.ToUInt32(sector, 0x132);
                    infoMddf.vol_sequence                 = BigEndianBitConverter.ToUInt16(sector, 0x136);
                    infoMddf.vol_left_mounted             = sector[0x138];

                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown1 = 0x{0:X2} ({0})", infoMddf.unknown1);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown2 = 0x{0:X2} ({0})", infoMddf.unknown2);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown3 = 0x{0:X8} ({0})", infoMddf.unknown3);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown4 = 0x{0:X4} ({0})", infoMddf.unknown4);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown5 = 0x{0:X8} ({0})", infoMddf.unknown5);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown6 = 0x{0:X8} ({0})", infoMddf.unknown6);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown7 = 0x{0:X8} ({0})", infoMddf.unknown7);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown9 = 0x{0:X4} ({0})", infoMddf.unknown9);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown10 = 0x{0:X8} ({0})", infoMddf.unknown10);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown11 = 0x{0:X8} ({0})", infoMddf.unknown11);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown12 = 0x{0:X8} ({0})", infoMddf.unknown12);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown13 = 0x{0:X8} ({0})", infoMddf.unknown13);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown14 = 0x{0:X8} ({0})", infoMddf.unknown14);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown15 = 0x{0:X8} ({0})", infoMddf.unknown15);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown16 = 0x{0:X8} ({0})", infoMddf.unknown16);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown17 = 0x{0:X4} ({0})", infoMddf.unknown17);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown18 = 0x{0:X8} ({0})", infoMddf.unknown18);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown19 = 0x{0:X8} ({0})", infoMddf.unknown19);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown20 = 0x{0:X8} ({0})", infoMddf.unknown20);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown21 = 0x{0:X8} ({0})", infoMddf.unknown21);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown22 = 0x{0:X8} ({0})", infoMddf.unknown22);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown23 = 0x{0:X8} ({0})", infoMddf.unknown23);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown24 = 0x{0:X8} ({0})", infoMddf.unknown24);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown25 = 0x{0:X8} ({0})", infoMddf.unknown25);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown26 = 0x{0:X8} ({0})", infoMddf.unknown26);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown27 = 0x{0:X8} ({0})", infoMddf.unknown27);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown28 = 0x{0:X8} ({0})", infoMddf.unknown28);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown29 = 0x{0:X8} ({0})", infoMddf.unknown29);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown30 = 0x{0:X8} ({0})", infoMddf.unknown30);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown31 = 0x{0:X8} ({0})", infoMddf.unknown31);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown32 = 0x{0:X8} ({0})", infoMddf.unknown32);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown33 = 0x{0:X8} ({0})", infoMddf.unknown33);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown34 = 0x{0:X8} ({0})", infoMddf.unknown34);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown35 = 0x{0:X8} ({0})", infoMddf.unknown35);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown36 = 0x{0:X8} ({0})", infoMddf.unknown36);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown37 = 0x{0:X8} ({0})", infoMddf.unknown37);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown38 = 0x{0:X8} ({0})", infoMddf.unknown38);
                    DicConsole.DebugWriteLine("LisaFS plugin", "mddf.unknown_timestamp = 0x{0:X8} ({0}, {1})",
                                              infoMddf.unknown_timestamp,
                                              DateHandlers.LisaToDateTime(infoMddf.unknown_timestamp));

                    if (infoMddf.mddf_block != i - beforeMddf)
                    {
                        return;
                    }

                    if (infoMddf.vol_size > imagePlugin.Info.Sectors)
                    {
                        return;
                    }

                    if (infoMddf.vol_size - 1 != infoMddf.volsize_minus_one)
                    {
                        return;
                    }

                    if (infoMddf.vol_size - i - 1 != infoMddf.volsize_minus_mddf_minus_one - beforeMddf)
                    {
                        return;
                    }

                    if (infoMddf.datasize > infoMddf.blocksize)
                    {
                        return;
                    }

                    if (infoMddf.blocksize < imagePlugin.Info.SectorSize)
                    {
                        return;
                    }

                    if (infoMddf.datasize != imagePlugin.Info.SectorSize)
                    {
                        return;
                    }

                    switch (infoMddf.fsversion)
                    {
                    case LISA_V1:
                        sb.AppendLine("LisaFS v1");
                        break;

                    case LISA_V2:
                        sb.AppendLine("LisaFS v2");
                        break;

                    case LISA_V3:
                        sb.AppendLine("LisaFS v3");
                        break;

                    default:
                        sb.AppendFormat("Uknown LisaFS version {0}", infoMddf.fsversion).AppendLine();
                        break;
                    }

                    sb.AppendFormat("Volume name: \"{0}\"", infoMddf.volname).AppendLine();
                    sb.AppendFormat("Volume password: \"{0}\"", infoMddf.password).AppendLine();
                    sb.AppendFormat("Volume ID: 0x{0:X16}", infoMddf.volid).AppendLine();
                    sb.AppendFormat("Backup volume ID: 0x{0:X16}", infoMddf.backup_volid).AppendLine();

                    sb.AppendFormat("Master copy ID: 0x{0:X8}", infoMddf.master_copy_id).AppendLine();

                    sb.AppendFormat("Volume is number {0} of {1}", infoMddf.volnum, infoMddf.vol_sequence).AppendLine();

                    sb.AppendFormat("Serial number of Lisa computer that created this volume: {0}", infoMddf.machine_id)
                    .AppendLine();
                    sb.AppendFormat("Serial number of Lisa computer that can use this volume's software {0}",
                                    infoMddf.serialization).AppendLine();

                    sb.AppendFormat("Volume created on {0}", infoMddf.dtvc).AppendLine();
                    sb.AppendFormat("Some timestamp, says {0}", infoMddf.dtcc).AppendLine();
                    sb.AppendFormat("Volume backed up on {0}", infoMddf.dtvb).AppendLine();
                    sb.AppendFormat("Volume scavenged on {0}", infoMddf.dtvs).AppendLine();
                    sb.AppendFormat("MDDF is in block {0}", infoMddf.mddf_block + beforeMddf).AppendLine();
                    sb.AppendFormat("There are {0} reserved blocks before volume", beforeMddf).AppendLine();
                    sb.AppendFormat("{0} blocks minus one", infoMddf.volsize_minus_one).AppendLine();
                    sb.AppendFormat("{0} blocks minus one minus MDDF offset", infoMddf.volsize_minus_mddf_minus_one)
                    .AppendLine();
                    sb.AppendFormat("{0} blocks in volume", infoMddf.vol_size).AppendLine();
                    sb.AppendFormat("{0} bytes per sector (uncooked)", infoMddf.blocksize).AppendLine();
                    sb.AppendFormat("{0} bytes per sector", infoMddf.datasize).AppendLine();
                    sb.AppendFormat("{0} blocks per cluster", infoMddf.clustersize).AppendLine();
                    sb.AppendFormat("{0} blocks in filesystem", infoMddf.fs_size).AppendLine();
                    sb.AppendFormat("{0} files in volume", infoMddf.filecount).AppendLine();
                    sb.AppendFormat("{0} blocks free", infoMddf.freecount).AppendLine();
                    sb.AppendFormat("{0} bytes in LisaInfo", infoMddf.label_size).AppendLine();
                    sb.AppendFormat("Filesystem overhead: {0}", infoMddf.fs_overhead).AppendLine();
                    sb.AppendFormat("Scanvenger result code: 0x{0:X8}", infoMddf.result_scavenge).AppendLine();
                    sb.AppendFormat("Boot code: 0x{0:X8}", infoMddf.boot_code).AppendLine();
                    sb.AppendFormat("Boot environment:  0x{0:X8}", infoMddf.boot_environ).AppendLine();
                    sb.AppendFormat("Overmount stamp: 0x{0:X16}", infoMddf.overmount_stamp).AppendLine();
                    sb.AppendFormat("S-Records start at {0} and spans for {1} blocks",
                                    infoMddf.srec_ptr + infoMddf.mddf_block + beforeMddf, infoMddf.srec_len)
                    .AppendLine();

                    sb.AppendLine(infoMddf.vol_left_mounted == 0 ? "Volume is clean" : "Volume is dirty");

                    information = sb.ToString();

                    XmlFsType = new FileSystemType();
                    if (DateTime.Compare(infoMddf.dtvb, DateHandlers.LisaToDateTime(0)) > 0)
                    {
                        XmlFsType.BackupDate          = infoMddf.dtvb;
                        XmlFsType.BackupDateSpecified = true;
                    }

                    XmlFsType.Clusters    = infoMddf.vol_size;
                    XmlFsType.ClusterSize = (uint)(infoMddf.clustersize * infoMddf.datasize);
                    if (DateTime.Compare(infoMddf.dtvc, DateHandlers.LisaToDateTime(0)) > 0)
                    {
                        XmlFsType.CreationDate          = infoMddf.dtvc;
                        XmlFsType.CreationDateSpecified = true;
                    }

                    XmlFsType.Dirty                 = infoMddf.vol_left_mounted != 0;
                    XmlFsType.Files                 = infoMddf.filecount;
                    XmlFsType.FilesSpecified        = true;
                    XmlFsType.FreeClusters          = infoMddf.freecount;
                    XmlFsType.FreeClustersSpecified = true;
                    XmlFsType.Type         = "LisaFS";
                    XmlFsType.VolumeName   = infoMddf.volname;
                    XmlFsType.VolumeSerial = $"{infoMddf.volid:X16}";

                    return;
                }
            }
            catch (Exception ex)
            {
                DicConsole.ErrorWriteLine("Exception {0}, {1}, {2}", ex.Message, ex.InnerException, ex.StackTrace);
            }
        }
Exemplo n.º 9
0
        public bool Identify(string path)
        {
            string parentFolder = Path.GetDirectoryName(path);

            parentFolder = parentFolder ?? "";

            if (!File.Exists(Path.Combine(parentFolder, FINDER_INFO)))
            {
                return(false);
            }

            if (!Directory.Exists(Path.Combine(parentFolder, RESOURCES)))
            {
                return(false);
            }

            string baseFilename = Path.GetFileName(path);

            bool dataFound = false;
            bool rsrcFound = false;

            FileStream finderDatStream =
                new FileStream(Path.Combine(parentFolder, FINDER_INFO), FileMode.Open, FileAccess.Read);

            while (finderDatStream.Position + 0x5C <= finderDatStream.Length)
            {
                PCExchangeEntry datEntry   = new PCExchangeEntry();
                byte[]          datEntry_b = new byte[Marshal.SizeOf(datEntry)];
                finderDatStream.Read(datEntry_b, 0, Marshal.SizeOf(datEntry));
                datEntry = Helpers.Marshal.ByteArrayToStructureBigEndian <PCExchangeEntry>(datEntry_b);
                // TODO: Add support for encoding on filters
                string macName =
                    StringHandlers.PascalToString(datEntry.macName, Encoding.GetEncoding("macintosh"));
                byte[] tmpDosName_b = new byte[8];
                byte[] tmpDosExt_b  = new byte[3];
                Array.Copy(datEntry.dosName, 0, tmpDosName_b, 0, 8);
                Array.Copy(datEntry.dosName, 8, tmpDosExt_b, 0, 3);
                string dosName = Encoding.ASCII.GetString(tmpDosName_b).Trim() + "." +
                                 Encoding.ASCII.GetString(tmpDosExt_b).Trim();
                string dosNameLow = dosName.ToLower(CultureInfo.CurrentCulture);

                if (baseFilename != macName && baseFilename != dosName && baseFilename != dosNameLow)
                {
                    continue;
                }

                dataFound |=
                    File.Exists(Path.Combine(parentFolder, macName ?? throw new InvalidOperationException())) ||
                    File.Exists(Path.Combine(parentFolder, dosName)) ||
                    File.Exists(Path.Combine(parentFolder, dosNameLow));

                rsrcFound |= File.Exists(Path.Combine(parentFolder, RESOURCES, dosName)) ||
                             File.Exists(Path.Combine(parentFolder, RESOURCES, dosNameLow));

                break;
            }

            finderDatStream.Close();

            return(dataFound && rsrcFound);
        }
Exemplo n.º 10
0
        bool FillDirectory()
        {
            idToFilename = new Dictionary <uint, string>();
            idToEntry    = new Dictionary <uint, MFS_FileEntry>();
            filenameToId = new Dictionary <string, uint>();

            int offset = 0;

            while (offset + 51 < directoryBlocks.Length)
            {
                MFS_FileEntry entry = new MFS_FileEntry
                {
                    flUsrWds = new byte[16],
                    flFlags  = (MFS_FileFlags)directoryBlocks[offset + 0]
                };

                if (!entry.flFlags.HasFlag(MFS_FileFlags.Used))
                {
                    break;
                }

                entry.flTyp = directoryBlocks[offset + 1];
                Array.Copy(directoryBlocks, offset + 2, entry.flUsrWds, 0, 16);
                entry.flFlNum  = BigEndianBitConverter.ToUInt32(directoryBlocks, offset + 18);
                entry.flStBlk  = BigEndianBitConverter.ToUInt16(directoryBlocks, offset + 22);
                entry.flLgLen  = BigEndianBitConverter.ToUInt32(directoryBlocks, offset + 24);
                entry.flPyLen  = BigEndianBitConverter.ToUInt32(directoryBlocks, offset + 28);
                entry.flRStBlk = BigEndianBitConverter.ToUInt16(directoryBlocks, offset + 32);
                entry.flRLgLen = BigEndianBitConverter.ToUInt32(directoryBlocks, offset + 34);
                entry.flRPyLen = BigEndianBitConverter.ToUInt32(directoryBlocks, offset + 38);
                entry.flCrDat  = BigEndianBitConverter.ToUInt32(directoryBlocks, offset + 42);
                entry.flMdDat  = BigEndianBitConverter.ToUInt32(directoryBlocks, offset + 46);
                entry.flNam    = new byte[directoryBlocks[offset + 50] + 1];
                Array.Copy(directoryBlocks, offset + 50, entry.flNam, 0, entry.flNam.Length);
                string lowerFilename = StringHandlers
                                       .PascalToString(entry.flNam, Encoding).ToLowerInvariant().Replace('/', ':');

                if (entry.flFlags.HasFlag(MFS_FileFlags.Used) && !idToFilename.ContainsKey(entry.flFlNum) &&
                    !idToEntry.ContainsKey(entry.flFlNum) && !filenameToId.ContainsKey(lowerFilename) &&
                    entry.flFlNum > 0)
                {
                    idToEntry.Add(entry.flFlNum, entry);
                    idToFilename.Add(entry.flFlNum,
                                     StringHandlers.PascalToString(entry.flNam, Encoding).Replace('/', ':'));
                    filenameToId.Add(lowerFilename, entry.flFlNum);

                    DicConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flFlags = {0}", entry.flFlags);
                    DicConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flTyp = {0}", entry.flTyp);
                    DicConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flFlNum = {0}", entry.flFlNum);
                    DicConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flStBlk = {0}", entry.flStBlk);
                    DicConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flLgLen = {0}", entry.flLgLen);
                    DicConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flPyLen = {0}", entry.flPyLen);
                    DicConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flRStBlk = {0}", entry.flRStBlk);
                    DicConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flRLgLen = {0}", entry.flRLgLen);
                    DicConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flRPyLen = {0}", entry.flRPyLen);
                    DicConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flCrDat = {0}",
                                              DateHandlers.MacToDateTime(entry.flCrDat));
                    DicConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flMdDat = {0}",
                                              DateHandlers.MacToDateTime(entry.flMdDat));
                    DicConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flNam0 = {0}",
                                              StringHandlers.PascalToString(entry.flNam, Encoding));
                }

                offset += 50 + entry.flNam.Length;

                // "Entries are always an integral number of words"
                if (offset % 2 != 0)
                {
                    offset++;
                }

                // TODO: "Entries don't cross logical block boundaries"
            }

            return(true);
        }
Exemplo n.º 11
0
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding    = encoding ?? new MacRoman();
            information = "";

            StringBuilder sb = new StringBuilder();

            MFS_MasterDirectoryBlock mdb = new MFS_MasterDirectoryBlock();
            MFS_BootBlock            bb  = new MFS_BootBlock();

            byte[] pString = new byte[16];

            byte[] mdbSector = imagePlugin.ReadSector(2 + partition.Start);
            byte[] bbSector  = imagePlugin.ReadSector(0 + partition.Start);

            BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;

            mdb.drSigWord = BigEndianBitConverter.ToUInt16(mdbSector, 0x000);
            if (mdb.drSigWord != MFS_MAGIC)
            {
                return;
            }

            mdb.drCrDate   = BigEndianBitConverter.ToUInt32(mdbSector, 0x002);
            mdb.drLsBkUp   = BigEndianBitConverter.ToUInt32(mdbSector, 0x006);
            mdb.drAtrb     = BigEndianBitConverter.ToUInt16(mdbSector, 0x00A);
            mdb.drNmFls    = BigEndianBitConverter.ToUInt16(mdbSector, 0x00C);
            mdb.drDirSt    = BigEndianBitConverter.ToUInt16(mdbSector, 0x00E);
            mdb.drBlLen    = BigEndianBitConverter.ToUInt16(mdbSector, 0x010);
            mdb.drNmAlBlks = BigEndianBitConverter.ToUInt16(mdbSector, 0x012);
            mdb.drAlBlkSiz = BigEndianBitConverter.ToUInt32(mdbSector, 0x014);
            mdb.drClpSiz   = BigEndianBitConverter.ToUInt32(mdbSector, 0x018);
            mdb.drAlBlSt   = BigEndianBitConverter.ToUInt16(mdbSector, 0x01C);
            mdb.drNxtFNum  = BigEndianBitConverter.ToUInt32(mdbSector, 0x01E);
            mdb.drFreeBks  = BigEndianBitConverter.ToUInt16(mdbSector, 0x022);
            mdb.drVNSiz    = mdbSector[0x024];
            byte[] variableSize = new byte[mdb.drVNSiz + 1];
            Array.Copy(mdbSector, 0x024, variableSize, 0, mdb.drVNSiz + 1);
            mdb.drVN = StringHandlers.PascalToString(variableSize, Encoding);

            bb.signature = BigEndianBitConverter.ToUInt16(bbSector, 0x000);

            if (bb.signature == MFSBB_MAGIC)
            {
                bb.branch       = BigEndianBitConverter.ToUInt32(bbSector, 0x002);
                bb.boot_flags   = bbSector[0x006];
                bb.boot_version = bbSector[0x007];

                bb.sec_sv_pages = BigEndianBitConverter.ToInt16(bbSector, 0x008);

                Array.Copy(mdbSector, 0x00A, pString, 0, 16);
                bb.system_name = StringHandlers.PascalToString(pString, Encoding);
                Array.Copy(mdbSector, 0x01A, pString, 0, 16);
                bb.finder_name = StringHandlers.PascalToString(pString, Encoding);
                Array.Copy(mdbSector, 0x02A, pString, 0, 16);
                bb.debug_name = StringHandlers.PascalToString(pString, Encoding);
                Array.Copy(mdbSector, 0x03A, pString, 0, 16);
                bb.disasm_name = StringHandlers.PascalToString(pString, Encoding);
                Array.Copy(mdbSector, 0x04A, pString, 0, 16);
                bb.stupscr_name = StringHandlers.PascalToString(pString, Encoding);
                Array.Copy(mdbSector, 0x05A, pString, 0, 16);
                bb.bootup_name = StringHandlers.PascalToString(pString, Encoding);
                Array.Copy(mdbSector, 0x06A, pString, 0, 16);
                bb.clipbrd_name = StringHandlers.PascalToString(pString, Encoding);

                bb.max_files  = BigEndianBitConverter.ToUInt16(bbSector, 0x07A);
                bb.queue_size = BigEndianBitConverter.ToUInt16(bbSector, 0x07C);
                bb.heap_128k  = BigEndianBitConverter.ToUInt32(bbSector, 0x07E);
                bb.heap_256k  = BigEndianBitConverter.ToUInt32(bbSector, 0x082);
                bb.heap_512k  = BigEndianBitConverter.ToUInt32(bbSector, 0x086);
            }
            else
            {
                bb.signature = 0x0000;
            }

            sb.AppendLine("Apple Macintosh File System");
            sb.AppendLine();
            sb.AppendLine("Master Directory Block:");
            sb.AppendFormat("Creation date: {0}", DateHandlers.MacToDateTime(mdb.drCrDate)).AppendLine();
            sb.AppendFormat("Last backup date: {0}", DateHandlers.MacToDateTime(mdb.drLsBkUp)).AppendLine();
            if ((mdb.drAtrb & 0x80) == 0x80)
            {
                sb.AppendLine("Volume is locked by hardware.");
            }
            if ((mdb.drAtrb & 0x8000) == 0x8000)
            {
                sb.AppendLine("Volume is locked by software.");
            }
            sb.AppendFormat("{0} files on volume", mdb.drNmFls).AppendLine();
            sb.AppendFormat("First directory sector: {0}", mdb.drDirSt).AppendLine();
            sb.AppendFormat("{0} sectors in directory.", mdb.drBlLen).AppendLine();
            sb.AppendFormat("{0} volume allocation blocks.", mdb.drNmAlBlks + 1).AppendLine();
            sb.AppendFormat("Size of allocation blocks: {0} bytes", mdb.drAlBlkSiz).AppendLine();
            sb.AppendFormat("{0} bytes to allocate.", mdb.drClpSiz).AppendLine();
            sb.AppendFormat("First allocation block (#2) starts in sector {0}.", mdb.drAlBlSt).AppendLine();
            sb.AppendFormat("Next unused file number: {0}", mdb.drNxtFNum).AppendLine();
            sb.AppendFormat("{0} unused allocation blocks.", mdb.drFreeBks).AppendLine();
            sb.AppendFormat("Volume name: {0}", mdb.drVN).AppendLine();

            if (bb.signature == MFSBB_MAGIC)
            {
                sb.AppendLine("Volume is bootable.");
                sb.AppendLine();
                sb.AppendLine("Boot Block:");
                if ((bb.boot_flags & 0x40) == 0x40)
                {
                    sb.AppendLine("Boot block should be executed.");
                }
                if ((bb.boot_flags & 0x80) == 0x80)
                {
                    sb.AppendLine("Boot block is in new unknown format.");
                }
                else
                {
                    if (bb.sec_sv_pages > 0)
                    {
                        sb.AppendLine("Allocate secondary sound buffer at boot.");
                    }
                    else if (bb.sec_sv_pages < 0)
                    {
                        sb.AppendLine("Allocate secondary sound and video buffers at boot.");
                    }

                    sb.AppendFormat("System filename: {0}", bb.system_name).AppendLine();
                    sb.AppendFormat("Finder filename: {0}", bb.finder_name).AppendLine();
                    sb.AppendFormat("Debugger filename: {0}", bb.debug_name).AppendLine();
                    sb.AppendFormat("Disassembler filename: {0}", bb.disasm_name).AppendLine();
                    sb.AppendFormat("Startup screen filename: {0}", bb.stupscr_name).AppendLine();
                    sb.AppendFormat("First program to execute at boot: {0}", bb.bootup_name).AppendLine();
                    sb.AppendFormat("Clipboard filename: {0}", bb.clipbrd_name).AppendLine();
                    sb.AppendFormat("Maximum opened files: {0}", bb.max_files * 4).AppendLine();
                    sb.AppendFormat("Event queue size: {0}", bb.queue_size).AppendLine();
                    sb.AppendFormat("Heap size with 128KiB of RAM: {0} bytes", bb.heap_128k).AppendLine();
                    sb.AppendFormat("Heap size with 256KiB of RAM: {0} bytes", bb.heap_256k).AppendLine();
                    sb.AppendFormat("Heap size with 512KiB of RAM or more: {0} bytes", bb.heap_512k).AppendLine();
                }
            }
            else
            {
                sb.AppendLine("Volume is not bootable.");
            }

            information = sb.ToString();

            XmlFsType = new FileSystemType();
            if (mdb.drLsBkUp > 0)
            {
                XmlFsType.BackupDate          = DateHandlers.MacToDateTime(mdb.drLsBkUp);
                XmlFsType.BackupDateSpecified = true;
            }

            XmlFsType.Bootable    = bb.signature == MFSBB_MAGIC;
            XmlFsType.Clusters    = mdb.drNmAlBlks;
            XmlFsType.ClusterSize = (int)mdb.drAlBlkSiz;
            if (mdb.drCrDate > 0)
            {
                XmlFsType.CreationDate          = DateHandlers.MacToDateTime(mdb.drCrDate);
                XmlFsType.CreationDateSpecified = true;
            }

            XmlFsType.Files                 = mdb.drNmFls;
            XmlFsType.FilesSpecified        = true;
            XmlFsType.FreeClusters          = mdb.drFreeBks;
            XmlFsType.FreeClustersSpecified = true;
            XmlFsType.Type       = "MFS";
            XmlFsType.VolumeName = mdb.drVN;
        }
Exemplo n.º 12
0
        /// <summary>
        ///     Mounts an Apple Lisa filesystem
        /// </summary>
        public Errno Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding,
                           Dictionary <string, string> options, string @namespace)
        {
            try
            {
                device   = imagePlugin;
                Encoding = new LisaRoman();

                // Lisa OS is unable to work on disks without tags.
                // This code is designed like that.
                // However with some effort the code may be modified to ignore them.
                if (device.Info.ReadableSectorTags == null ||
                    !device.Info.ReadableSectorTags.Contains(SectorTagType.AppleSectorTag))
                {
                    DicConsole.DebugWriteLine("LisaFS plugin", "Underlying device does not support Lisa tags");
                    return(Errno.InOutError);
                }

                // Minimal LisaOS disk is 3.5" single sided double density, 800 sectors
                if (device.Info.Sectors < 800)
                {
                    DicConsole.DebugWriteLine("LisaFS plugin", "Device is too small");
                    return(Errno.InOutError);
                }

                // MDDF cannot be at end of device, of course
                volumePrefix = device.Info.Sectors;

                // LisaOS searches sectors until tag tells MDDF resides there, so we'll search 100 sectors
                for (ulong i = 0; i < 100; i++)
                {
                    DecodeTag(device.ReadSectorTag(i, SectorTagType.AppleSectorTag), out LisaTag.PriamTag searchTag);

                    DicConsole.DebugWriteLine("LisaFS plugin", "Sector {0}, file ID 0x{1:X4}", i, searchTag.FileId);

                    if (volumePrefix == device.Info.Sectors && searchTag.FileId == FILEID_LOADER_SIGNED)
                    {
                        volumePrefix = i - 1;
                    }

                    if (searchTag.FileId != FILEID_MDDF)
                    {
                        continue;
                    }

                    devTagSize = device.ReadSectorTag(i, SectorTagType.AppleSectorTag).Length;

                    byte[] sector = device.ReadSector(i);
                    mddf = new MDDF();
                    byte[] pString = new byte[33];

                    mddf.fsversion = BigEndianBitConverter.ToUInt16(sector, 0x00);
                    mddf.volid     = BigEndianBitConverter.ToUInt64(sector, 0x02);
                    mddf.volnum    = BigEndianBitConverter.ToUInt16(sector, 0x0A);
                    Array.Copy(sector, 0x0C, pString, 0, 33);
                    mddf.volname  = StringHandlers.PascalToString(pString, Encoding);
                    mddf.unknown1 = sector[0x2D];
                    Array.Copy(sector, 0x2E, pString, 0, 33);
                    // Prevent garbage
                    mddf.password       = pString[0] <= 32 ? StringHandlers.PascalToString(pString, Encoding) : "";
                    mddf.unknown2       = sector[0x4F];
                    mddf.machine_id     = BigEndianBitConverter.ToUInt32(sector, 0x50);
                    mddf.master_copy_id = BigEndianBitConverter.ToUInt32(sector, 0x54);
                    uint lisaTime = BigEndianBitConverter.ToUInt32(sector, 0x58);
                    mddf.dtvc                         = DateHandlers.LisaToDateTime(lisaTime);
                    lisaTime                          = BigEndianBitConverter.ToUInt32(sector, 0x5C);
                    mddf.dtcc                         = DateHandlers.LisaToDateTime(lisaTime);
                    lisaTime                          = BigEndianBitConverter.ToUInt32(sector, 0x60);
                    mddf.dtvb                         = DateHandlers.LisaToDateTime(lisaTime);
                    lisaTime                          = BigEndianBitConverter.ToUInt32(sector, 0x64);
                    mddf.dtvs                         = DateHandlers.LisaToDateTime(lisaTime);
                    mddf.unknown3                     = BigEndianBitConverter.ToUInt32(sector, 0x68);
                    mddf.mddf_block                   = BigEndianBitConverter.ToUInt32(sector, 0x6C);
                    mddf.volsize_minus_one            = BigEndianBitConverter.ToUInt32(sector, 0x70);
                    mddf.volsize_minus_mddf_minus_one = BigEndianBitConverter.ToUInt32(sector, 0x74);
                    mddf.vol_size                     = BigEndianBitConverter.ToUInt32(sector, 0x78);
                    mddf.blocksize                    = BigEndianBitConverter.ToUInt16(sector, 0x7C);
                    mddf.datasize                     = BigEndianBitConverter.ToUInt16(sector, 0x7E);
                    mddf.unknown4                     = BigEndianBitConverter.ToUInt16(sector, 0x80);
                    mddf.unknown5                     = BigEndianBitConverter.ToUInt32(sector, 0x82);
                    mddf.unknown6                     = BigEndianBitConverter.ToUInt32(sector, 0x86);
                    mddf.clustersize                  = BigEndianBitConverter.ToUInt16(sector, 0x8A);
                    mddf.fs_size                      = BigEndianBitConverter.ToUInt32(sector, 0x8C);
                    mddf.unknown7                     = BigEndianBitConverter.ToUInt32(sector, 0x90);
                    mddf.srec_ptr                     = BigEndianBitConverter.ToUInt32(sector, 0x94);
                    mddf.unknown9                     = BigEndianBitConverter.ToUInt16(sector, 0x98);
                    mddf.srec_len                     = BigEndianBitConverter.ToUInt16(sector, 0x9A);
                    mddf.unknown10                    = BigEndianBitConverter.ToUInt32(sector, 0x9C);
                    mddf.unknown11                    = BigEndianBitConverter.ToUInt32(sector, 0xA0);
                    mddf.unknown12                    = BigEndianBitConverter.ToUInt32(sector, 0xA4);
                    mddf.unknown13                    = BigEndianBitConverter.ToUInt32(sector, 0xA8);
                    mddf.unknown14                    = BigEndianBitConverter.ToUInt32(sector, 0xAC);
                    mddf.filecount                    = BigEndianBitConverter.ToUInt16(sector, 0xB0);
                    mddf.unknown15                    = BigEndianBitConverter.ToUInt32(sector, 0xB2);
                    mddf.unknown16                    = BigEndianBitConverter.ToUInt32(sector, 0xB6);
                    mddf.freecount                    = BigEndianBitConverter.ToUInt32(sector, 0xBA);
                    mddf.unknown17                    = BigEndianBitConverter.ToUInt16(sector, 0xBE);
                    mddf.unknown18                    = BigEndianBitConverter.ToUInt32(sector, 0xC0);
                    mddf.overmount_stamp              = BigEndianBitConverter.ToUInt64(sector, 0xC4);
                    mddf.serialization                = BigEndianBitConverter.ToUInt32(sector, 0xCC);
                    mddf.unknown19                    = BigEndianBitConverter.ToUInt32(sector, 0xD0);
                    mddf.unknown_timestamp            = BigEndianBitConverter.ToUInt32(sector, 0xD4);
                    mddf.unknown20                    = BigEndianBitConverter.ToUInt32(sector, 0xD8);
                    mddf.unknown21                    = BigEndianBitConverter.ToUInt32(sector, 0xDC);
                    mddf.unknown22                    = BigEndianBitConverter.ToUInt32(sector, 0xE0);
                    mddf.unknown23                    = BigEndianBitConverter.ToUInt32(sector, 0xE4);
                    mddf.unknown24                    = BigEndianBitConverter.ToUInt32(sector, 0xE8);
                    mddf.unknown25                    = BigEndianBitConverter.ToUInt32(sector, 0xEC);
                    mddf.unknown26                    = BigEndianBitConverter.ToUInt32(sector, 0xF0);
                    mddf.unknown27                    = BigEndianBitConverter.ToUInt32(sector, 0xF4);
                    mddf.unknown28                    = BigEndianBitConverter.ToUInt32(sector, 0xF8);
                    mddf.unknown29                    = BigEndianBitConverter.ToUInt32(sector, 0xFC);
                    mddf.unknown30                    = BigEndianBitConverter.ToUInt32(sector, 0x100);
                    mddf.unknown31                    = BigEndianBitConverter.ToUInt32(sector, 0x104);
                    mddf.unknown32                    = BigEndianBitConverter.ToUInt32(sector, 0x108);
                    mddf.unknown33                    = BigEndianBitConverter.ToUInt32(sector, 0x10C);
                    mddf.unknown34                    = BigEndianBitConverter.ToUInt32(sector, 0x110);
                    mddf.unknown35                    = BigEndianBitConverter.ToUInt32(sector, 0x114);
                    mddf.backup_volid                 = BigEndianBitConverter.ToUInt64(sector, 0x118);
                    mddf.label_size                   = BigEndianBitConverter.ToUInt16(sector, 0x120);
                    mddf.fs_overhead                  = BigEndianBitConverter.ToUInt16(sector, 0x122);
                    mddf.result_scavenge              = BigEndianBitConverter.ToUInt16(sector, 0x124);
                    mddf.boot_code                    = BigEndianBitConverter.ToUInt16(sector, 0x126);
                    mddf.boot_environ                 = BigEndianBitConverter.ToUInt16(sector, 0x6C);
                    mddf.unknown36                    = BigEndianBitConverter.ToUInt32(sector, 0x12A);
                    mddf.unknown37                    = BigEndianBitConverter.ToUInt32(sector, 0x12E);
                    mddf.unknown38                    = BigEndianBitConverter.ToUInt32(sector, 0x132);
                    mddf.vol_sequence                 = BigEndianBitConverter.ToUInt16(sector, 0x136);
                    mddf.vol_left_mounted             = sector[0x138];

                    // Check that the MDDF is correct
                    if (mddf.mddf_block != i - volumePrefix ||
                        mddf.vol_size > device.Info.Sectors ||
                        mddf.vol_size - 1 !=
                        mddf.volsize_minus_one ||
                        mddf.vol_size - i - 1 !=
                        mddf.volsize_minus_mddf_minus_one - volumePrefix ||
                        mddf.datasize >
                        mddf.blocksize || mddf.blocksize < device.Info.SectorSize ||
                        mddf.datasize != device.Info.SectorSize)
                    {
                        DicConsole.DebugWriteLine("LisaFS plugin", "Incorrect MDDF found");
                        return(Errno.InvalidArgument);
                    }

                    // Check MDDF version
                    switch (mddf.fsversion)
                    {
                    case LISA_V1:
                        DicConsole.DebugWriteLine("LisaFS plugin", "Mounting LisaFS v1");
                        break;

                    case LISA_V2:
                        DicConsole.DebugWriteLine("LisaFS plugin", "Mounting LisaFS v2");
                        break;

                    case LISA_V3:
                        DicConsole.DebugWriteLine("LisaFS plugin", "Mounting LisaFS v3");
                        break;

                    default:
                        DicConsole.ErrorWriteLine("Cannot mount LisaFS version {0}", mddf.fsversion.ToString());
                        return(Errno.NotSupported);
                    }

                    // Initialize caches
                    extentCache     = new Dictionary <short, ExtentFile>();
                    systemFileCache = new Dictionary <short, byte[]>();
                    fileCache       = new Dictionary <short, byte[]>();
                    //catalogCache = new Dictionary<short, List<CatalogEntry>>();
                    fileSizeCache = new Dictionary <short, int>();

                    mounted = true;
                    if (options == null)
                    {
                        options = GetDefaultOptions();
                    }
                    if (options.TryGetValue("debug", out string debugString))
                    {
                        bool.TryParse(debugString, out debug);
                    }

                    if (debug)
                    {
                        printedExtents = new List <short>();
                    }

                    // Read the S-Records file
                    Errno error = ReadSRecords();
                    if (error != Errno.NoError)
                    {
                        DicConsole.ErrorWriteLine("Error {0} reading S-Records file.", error);
                        return(error);
                    }

                    directoryDtcCache = new Dictionary <short, DateTime> {
                        { DIRID_ROOT, mddf.dtcc }
                    };

                    // Read the Catalog File
                    error = ReadCatalog();

                    if (error != Errno.NoError)
                    {
                        DicConsole.DebugWriteLine("LisaFS plugin", "Cannot read Catalog File, error {0}",
                                                  error.ToString());
                        mounted = false;
                        return(error);
                    }

                    // If debug, cache system files
                    if (debug)
                    {
                        error = ReadSystemFile(FILEID_BOOT_SIGNED, out _);
                        if (error != Errno.NoError)
                        {
                            DicConsole.DebugWriteLine("LisaFS plugin", "Unable to read boot blocks");
                            mounted = false;
                            return(error);
                        }

                        error = ReadSystemFile(FILEID_LOADER_SIGNED, out _);
                        if (error != Errno.NoError)
                        {
                            DicConsole.DebugWriteLine("LisaFS plugin", "Unable to read boot loader");
                            mounted = false;
                            return(error);
                        }

                        error = ReadSystemFile((short)FILEID_MDDF, out _);
                        if (error != Errno.NoError)
                        {
                            DicConsole.DebugWriteLine("LisaFS plugin", "Unable to read MDDF");
                            mounted = false;
                            return(error);
                        }

                        error = ReadSystemFile((short)FILEID_BITMAP, out _);
                        if (error != Errno.NoError)
                        {
                            DicConsole.DebugWriteLine("LisaFS plugin", "Unable to read volume bitmap");
                            mounted = false;
                            return(error);
                        }

                        error = ReadSystemFile((short)FILEID_SRECORD, out _);
                        if (error != Errno.NoError)
                        {
                            DicConsole.DebugWriteLine("LisaFS plugin", "Unable to read S-Records file");
                            mounted = false;
                            return(error);
                        }
                    }

                    // Create XML metadata for mounted filesystem
                    XmlFsType = new FileSystemType();
                    if (DateTime.Compare(mddf.dtvb, DateHandlers.LisaToDateTime(0)) > 0)
                    {
                        XmlFsType.BackupDate          = mddf.dtvb;
                        XmlFsType.BackupDateSpecified = true;
                    }

                    XmlFsType.Clusters    = mddf.vol_size;
                    XmlFsType.ClusterSize = (uint)(mddf.clustersize * mddf.datasize);
                    if (DateTime.Compare(mddf.dtvc, DateHandlers.LisaToDateTime(0)) > 0)
                    {
                        XmlFsType.CreationDate          = mddf.dtvc;
                        XmlFsType.CreationDateSpecified = true;
                    }

                    XmlFsType.Dirty                 = mddf.vol_left_mounted != 0;
                    XmlFsType.Files                 = mddf.filecount;
                    XmlFsType.FilesSpecified        = true;
                    XmlFsType.FreeClusters          = mddf.freecount;
                    XmlFsType.FreeClustersSpecified = true;
                    XmlFsType.Type         = "LisaFS";
                    XmlFsType.VolumeName   = mddf.volname;
                    XmlFsType.VolumeSerial = $"{mddf.volid:X16}";

                    return(Errno.NoError);
                }

                DicConsole.DebugWriteLine("LisaFS plugin", "Not a Lisa filesystem");
                return(Errno.NotSupported);
            }
            catch (Exception ex)
            {
                DicConsole.ErrorWriteLine("Exception {0}, {1}, {2}", ex.Message, ex.InnerException, ex.StackTrace);
                return(Errno.InOutError);
            }
        }
Exemplo n.º 13
0
Arquivo: PFS.cs Projeto: paulyc/Aaru
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding = encoding ?? Encoding.GetEncoding("iso-8859-1");
            byte[]    rootBlockSector = imagePlugin.ReadSector(2 + partition.Start);
            RootBlock rootBlock       = Marshal.ByteArrayToStructureBigEndian <RootBlock>(rootBlockSector);

            var sbInformation = new StringBuilder();

            XmlFsType = new FileSystemType();

            switch (rootBlock.diskType)
            {
            case AFS_DISK:
            case MUAF_DISK:
                sbInformation.Append("Professional File System v1");
                XmlFsType.Type = "PFS v1";

                break;

            case PFS2_DISK:
                sbInformation.Append("Professional File System v2");
                XmlFsType.Type = "PFS v2";

                break;

            case PFS_DISK:
            case MUPFS_DISK:
                sbInformation.Append("Professional File System v3");
                XmlFsType.Type = "PFS v3";

                break;
            }

            if (rootBlock.diskType == MUAF_DISK ||
                rootBlock.diskType == MUPFS_DISK)
            {
                sbInformation.Append(", with multi-user support");
            }

            sbInformation.AppendLine();

            sbInformation.AppendFormat("Volume name: {0}", StringHandlers.PascalToString(rootBlock.diskname, Encoding)).
            AppendLine();

            sbInformation.AppendFormat("Volume has {0} free sectors of {1}", rootBlock.blocksfree, rootBlock.diskSize).
            AppendLine();

            sbInformation.AppendFormat("Volume created on {0}",
                                       DateHandlers.AmigaToDateTime(rootBlock.creationday, rootBlock.creationminute,
                                                                    rootBlock.creationtick)).AppendLine();

            if (rootBlock.extension > 0)
            {
                sbInformation.AppendFormat("Root block extension resides at block {0}", rootBlock.extension).
                AppendLine();
            }

            information = sbInformation.ToString();

            XmlFsType.CreationDate =
                DateHandlers.AmigaToDateTime(rootBlock.creationday, rootBlock.creationminute, rootBlock.creationtick);

            XmlFsType.CreationDateSpecified = true;
            XmlFsType.FreeClusters          = rootBlock.blocksfree;
            XmlFsType.FreeClustersSpecified = true;
            XmlFsType.Clusters    = rootBlock.diskSize;
            XmlFsType.ClusterSize = imagePlugin.Info.SectorSize;
            XmlFsType.VolumeName  = StringHandlers.PascalToString(rootBlock.diskname, Encoding);
        }
Exemplo n.º 14
0
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding    = encoding ?? Encoding.GetEncoding("macintosh");
            information = "";

            StringBuilder sb = new StringBuilder();

            byte[] bbSector  = null;
            byte[] mdbSector = null;
            ushort drSigWord;

            bool APMFromHDDOnCD = false;

            if (imagePlugin.Info.SectorSize == 2352 || imagePlugin.Info.SectorSize == 2448 ||
                imagePlugin.Info.SectorSize == 2048)
            {
                byte[] tmpSector = imagePlugin.ReadSectors(partition.Start, 2);

                foreach (int offset in new[] { 0, 0x200, 0x400, 0x600, 0x800, 0xA00 })
                {
                    drSigWord = BigEndianBitConverter.ToUInt16(tmpSector, offset);
                    if (drSigWord != HFS_MAGIC)
                    {
                        continue;
                    }

                    bbSector  = new byte[1024];
                    mdbSector = new byte[512];
                    if (offset >= 0x400)
                    {
                        Array.Copy(tmpSector, offset - 0x400, bbSector, 0, 1024);
                    }
                    Array.Copy(tmpSector, offset, mdbSector, 0, 512);
                    APMFromHDDOnCD = true;
                    break;
                }

                if (!APMFromHDDOnCD)
                {
                    return;
                }
            }
            else
            {
                mdbSector = imagePlugin.ReadSector(2 + partition.Start);
                drSigWord = BigEndianBitConverter.ToUInt16(mdbSector, 0);

                if (drSigWord == HFS_MAGIC)
                {
                    bbSector = imagePlugin.ReadSector(partition.Start);
                }
                else
                {
                    return;
                }
            }

            HFS_MasterDirectoryBlock MDB =
                BigEndianMarshal.ByteArrayToStructureBigEndian <HFS_MasterDirectoryBlock>(mdbSector);
            HFS_BootBlock BB = BigEndianMarshal.ByteArrayToStructureBigEndian <HFS_BootBlock>(bbSector);

            sb.AppendLine("Apple Hierarchical File System");
            sb.AppendLine();
            if (APMFromHDDOnCD)
            {
                sb.AppendLine("HFS uses 512 bytes/sector while device uses 2048 bytes/sector.").AppendLine();
            }
            sb.AppendLine("Master Directory Block:");
            sb.AppendFormat("Creation date: {0}", DateHandlers.MacToDateTime(MDB.drCrDate)).AppendLine();
            sb.AppendFormat("Last modification date: {0}", DateHandlers.MacToDateTime(MDB.drLsMod)).AppendLine();
            if (MDB.drVolBkUp > 0)
            {
                sb.AppendFormat("Last backup date: {0}", DateHandlers.MacToDateTime(MDB.drVolBkUp)).AppendLine();
                sb.AppendFormat("Backup sequence number: {0}", MDB.drVSeqNum).AppendLine();
            }
            else
            {
                sb.AppendLine("Volume has never been backed up");
            }

            if ((MDB.drAtrb & 0x80) == 0x80)
            {
                sb.AppendLine("Volume is locked by hardware.");
            }
            sb.AppendLine((MDB.drAtrb & 0x100) == 0x100 ? "Volume was unmonted." : "Volume is mounted.");
            if ((MDB.drAtrb & 0x200) == 0x200)
            {
                sb.AppendLine("Volume has spared bad blocks.");
            }
            if ((MDB.drAtrb & 0x400) == 0x400)
            {
                sb.AppendLine("Volume does not need cache.");
            }
            if ((MDB.drAtrb & 0x800) == 0x800)
            {
                sb.AppendLine("Boot volume is inconsistent.");
            }
            if ((MDB.drAtrb & 0x1000) == 0x1000)
            {
                sb.AppendLine("There are reused CNIDs.");
            }
            if ((MDB.drAtrb & 0x2000) == 0x2000)
            {
                sb.AppendLine("Volume is journaled.");
            }
            if ((MDB.drAtrb & 0x4000) == 0x4000)
            {
                sb.AppendLine("Volume is seriously inconsistent.");
            }
            if ((MDB.drAtrb & 0x8000) == 0x8000)
            {
                sb.AppendLine("Volume is locked by software.");
            }

            sb.AppendFormat("{0} files on root directory", MDB.drNmFls).AppendLine();
            sb.AppendFormat("{0} directories on root directory", MDB.drNmRtDirs).AppendLine();
            sb.AppendFormat("{0} files on volume", MDB.drFilCnt).AppendLine();
            sb.AppendFormat("{0} directories on volume", MDB.drDirCnt).AppendLine();
            sb.AppendFormat("Volume write count: {0}", MDB.drWrCnt).AppendLine();

            sb.AppendFormat("Volume bitmap starting sector (in 512-bytes): {0}", MDB.drVBMSt).AppendLine();
            sb.AppendFormat("Next allocation block: {0}.", MDB.drAllocPtr).AppendLine();
            sb.AppendFormat("{0} volume allocation blocks.", MDB.drNmAlBlks).AppendLine();
            sb.AppendFormat("{0} bytes per allocation block.", MDB.drAlBlkSiz).AppendLine();
            sb.AppendFormat("{0} bytes to allocate when extending a file.", MDB.drClpSiz).AppendLine();
            sb.AppendFormat("{0} bytes to allocate when extending a Extents B-Tree.", MDB.drXTClpSiz).AppendLine();
            sb.AppendFormat("{0} bytes to allocate when extending a Catalog B-Tree.", MDB.drCTClpSiz).AppendLine();
            sb.AppendFormat("Sector of first allocation block: {0}", MDB.drAlBlSt).AppendLine();
            sb.AppendFormat("Next unused CNID: {0}", MDB.drNxtCNID).AppendLine();
            sb.AppendFormat("{0} unused allocation blocks.", MDB.drFreeBks).AppendLine();

            sb.AppendFormat("{0} bytes in the Extents B-Tree", MDB.drXTFlSize).AppendLine();
            sb.AppendFormat("{0} bytes in the Catalog B-Tree", MDB.drCTFlSize).AppendLine();

            sb.AppendFormat("Volume name: {0}", StringHandlers.PascalToString(MDB.drVN, Encoding)).AppendLine();

            sb.AppendLine("Finder info:");
            sb.AppendFormat("CNID of bootable system's directory: {0}", MDB.drFndrInfo0).AppendLine();
            sb.AppendFormat("CNID of first-run application's directory: {0}", MDB.drFndrInfo1).AppendLine();
            sb.AppendFormat("CNID of previously opened directory: {0}", MDB.drFndrInfo2).AppendLine();
            sb.AppendFormat("CNID of bootable Mac OS 8 or 9 directory: {0}", MDB.drFndrInfo3).AppendLine();
            sb.AppendFormat("CNID of bootable Mac OS X directory: {0}", MDB.drFndrInfo5).AppendLine();
            if (MDB.drFndrInfo6 != 0 && MDB.drFndrInfo7 != 0)
            {
                sb.AppendFormat("Mac OS X Volume ID: {0:X8}{1:X8}", MDB.drFndrInfo6, MDB.drFndrInfo7).AppendLine();
            }

            if (MDB.drEmbedSigWord == HFSP_MAGIC)
            {
                sb.AppendLine("Volume wraps a HFS+ volume.");
                sb.AppendFormat("Starting block of the HFS+ volume: {0}", MDB.xdrStABNt).AppendLine();
                sb.AppendFormat("Allocations blocks of the HFS+ volume: {0}", MDB.xdrNumABlks).AppendLine();
            }
            else
            {
                sb.AppendFormat("{0} blocks in volume cache", MDB.drVCSize).AppendLine();
                sb.AppendFormat("{0} blocks in volume bitmap cache", MDB.drVBMCSize).AppendLine();
                sb.AppendFormat("{0} blocks in volume common cache", MDB.drCtlCSize).AppendLine();
            }

            if (BB.signature == HFSBB_MAGIC)
            {
                sb.AppendLine("Volume is bootable.");
                sb.AppendLine();
                sb.AppendLine("Boot Block:");
                if ((BB.boot_flags & 0x40) == 0x40)
                {
                    sb.AppendLine("Boot block should be executed.");
                }
                if ((BB.boot_flags & 0x80) == 0x80)
                {
                    sb.AppendLine("Boot block is in new unknown format.");
                }
                else
                {
                    if (BB.boot_flags > 0)
                    {
                        sb.AppendLine("Allocate secondary sound buffer at boot.");
                    }
                    else if (BB.boot_flags < 0)
                    {
                        sb.AppendLine("Allocate secondary sound and video buffers at boot.");
                    }

                    sb.AppendFormat("System filename: {0}", StringHandlers.PascalToString(BB.system_name, Encoding))
                    .AppendLine();
                    sb.AppendFormat("Finder filename: {0}", StringHandlers.PascalToString(BB.finder_name, Encoding))
                    .AppendLine();
                    sb.AppendFormat("Debugger filename: {0}", StringHandlers.PascalToString(BB.debug_name, Encoding))
                    .AppendLine();
                    sb.AppendFormat("Disassembler filename: {0}",
                                    StringHandlers.PascalToString(BB.disasm_name, Encoding)).AppendLine();
                    sb.AppendFormat("Startup screen filename: {0}",
                                    StringHandlers.PascalToString(BB.stupscr_name, Encoding)).AppendLine();
                    sb.AppendFormat("First program to execute at boot: {0}",
                                    StringHandlers.PascalToString(BB.bootup_name, Encoding)).AppendLine();
                    sb.AppendFormat("Clipboard filename: {0}", StringHandlers.PascalToString(BB.clipbrd_name, Encoding))
                    .AppendLine();
                    sb.AppendFormat("Maximum opened files: {0}", BB.max_files * 4).AppendLine();
                    sb.AppendFormat("Event queue size: {0}", BB.queue_size).AppendLine();
                    sb.AppendFormat("Heap size with 128KiB of RAM: {0} bytes", BB.heap_128k).AppendLine();
                    sb.AppendFormat("Heap size with 256KiB of RAM: {0} bytes", BB.heap_256k).AppendLine();
                    sb.AppendFormat("Heap size with 512KiB of RAM or more: {0} bytes", BB.heap_512k).AppendLine();
                }
            }
            else if (MDB.drFndrInfo0 != 0 || MDB.drFndrInfo3 != 0 || MDB.drFndrInfo5 != 0)
            {
                sb.AppendLine("Volume is bootable.");
            }
            else
            {
                sb.AppendLine("Volume is not bootable.");
            }

            information = sb.ToString();

            XmlFsType = new FileSystemType();
            if (MDB.drVolBkUp > 0)
            {
                XmlFsType.BackupDate          = DateHandlers.MacToDateTime(MDB.drVolBkUp);
                XmlFsType.BackupDateSpecified = true;
            }
            XmlFsType.Bootable = BB.signature == HFSBB_MAGIC || MDB.drFndrInfo0 != 0 || MDB.drFndrInfo3 != 0 ||
                                 MDB.drFndrInfo5 != 0;
            XmlFsType.Clusters    = MDB.drNmAlBlks;
            XmlFsType.ClusterSize = (int)MDB.drAlBlkSiz;
            if (MDB.drCrDate > 0)
            {
                XmlFsType.CreationDate          = DateHandlers.MacToDateTime(MDB.drCrDate);
                XmlFsType.CreationDateSpecified = true;
            }
            XmlFsType.Dirty                 = (MDB.drAtrb & 0x100) != 0x100;
            XmlFsType.Files                 = MDB.drFilCnt;
            XmlFsType.FilesSpecified        = true;
            XmlFsType.FreeClusters          = MDB.drFreeBks;
            XmlFsType.FreeClustersSpecified = true;
            if (MDB.drLsMod > 0)
            {
                XmlFsType.ModificationDate          = DateHandlers.MacToDateTime(MDB.drLsMod);
                XmlFsType.ModificationDateSpecified = true;
            }
            XmlFsType.Type       = "HFS";
            XmlFsType.VolumeName = StringHandlers.PascalToString(MDB.drVN, Encoding);
            if (MDB.drFndrInfo6 != 0 && MDB.drFndrInfo7 != 0)
            {
                XmlFsType.VolumeSerial = $"{MDB.drFndrInfo6:X8}{MDB.drFndrInfo7:X8}";
            }
        }
Exemplo n.º 15
0
Arquivo: Info.cs Projeto: paulyc/Aaru
        internal static string GetBootBlockInformation(byte[] bbSector, Encoding encoding)
        {
            if (bbSector is null ||
                bbSector.Length < 0x100)
            {
                return(null);
            }

            BootBlock bb = Marshal.ByteArrayToStructureBigEndian <BootBlock>(bbSector);

            if (bb.bbID != BB_MAGIC)
            {
                return(null);
            }

            var sb = new StringBuilder();

            sb.AppendLine("Boot Block:");

            if ((bb.bbVersion & 0x8000) > 0)
            {
                sb.AppendLine("Boot block is in new format.");

                if ((bb.bbVersion & 0x4000) > 0)
                {
                    sb.AppendLine("Boot block should be executed.");

                    if ((bb.bbVersion & 0x2000) > 0)
                    {
                        sb.
                        AppendFormat("System heap will be extended by {0} bytes and a {1} fraction of the available RAM",
                                     bb.bbSysHeapExtra, bb.bbSysHeapFract).AppendLine();
                    }
                }
            }
            else if ((bb.bbVersion & 0xFF) == 0x0D)
            {
                sb.AppendLine("Boot block should be executed.");
            }

            if (bb.bbPageFlags > 0)
            {
                sb.AppendLine("Allocate secondary sound buffer at boot.");
            }
            else if (bb.bbPageFlags < 0)
            {
                sb.AppendLine("Allocate secondary sound and video buffers at boot.");
            }

            sb.AppendFormat("System filename: {0}", StringHandlers.PascalToString(bb.bbSysName, encoding)).AppendLine();

            sb.AppendFormat("Finder filename: {0}", StringHandlers.PascalToString(bb.bbShellName, encoding)).
            AppendLine();

            sb.AppendFormat("Debugger filename: {0}", StringHandlers.PascalToString(bb.bbDbg1Name, encoding)).
            AppendLine();

            sb.AppendFormat("Disassembler filename: {0}", StringHandlers.PascalToString(bb.bbDbg2Name, encoding)).
            AppendLine();

            sb.AppendFormat("Startup screen filename: {0}", StringHandlers.PascalToString(bb.bbScreenName, encoding)).
            AppendLine();

            sb.AppendFormat("First program to execute at boot: {0}",
                            StringHandlers.PascalToString(bb.bbHelloName, encoding)).AppendLine();

            sb.AppendFormat("Clipboard filename: {0}", StringHandlers.PascalToString(bb.bbScrapName, encoding)).
            AppendLine();

            sb.AppendFormat("Maximum opened files: {0}", bb.bbCntFCBs * 4).AppendLine();
            sb.AppendFormat("Event queue size: {0}", bb.bbCntEvts).AppendLine();
            sb.AppendFormat("Heap size with 128KiB of RAM: {0} bytes", bb.bb128KSHeap).AppendLine();
            sb.AppendFormat("Heap size with 256KiB of RAM: {0} bytes", bb.bb256KSHeap).AppendLine();
            sb.AppendFormat("Heap size with 512KiB of RAM or more: {0} bytes", bb.bbSysHeapSize).AppendLine();

            return(sb.ToString());
        }
Exemplo n.º 16
0
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding    = encoding ?? Encoding.GetEncoding("macintosh");
            information = "";

            var sb = new StringBuilder();

            byte[] bbSector  = null;
            byte[] mdbSector = null;
            ushort drSigWord;

            bool apmFromHddOnCd = false;

            if (imagePlugin.Info.SectorSize == 2352 ||
                imagePlugin.Info.SectorSize == 2448 ||
                imagePlugin.Info.SectorSize == 2048)
            {
                byte[] tmpSector = imagePlugin.ReadSectors(partition.Start, 2);

                foreach (int offset in new[]
                {
                    0, 0x200, 0x400, 0x600, 0x800, 0xA00
                })
                {
                    drSigWord = BigEndianBitConverter.ToUInt16(tmpSector, offset);

                    if (drSigWord != AppleCommon.HFS_MAGIC)
                    {
                        continue;
                    }

                    bbSector  = new byte[1024];
                    mdbSector = new byte[512];

                    if (offset >= 0x400)
                    {
                        Array.Copy(tmpSector, offset - 0x400, bbSector, 0, 1024);
                    }

                    Array.Copy(tmpSector, offset, mdbSector, 0, 512);
                    apmFromHddOnCd = true;

                    break;
                }

                if (!apmFromHddOnCd)
                {
                    return;
                }
            }
            else
            {
                mdbSector = imagePlugin.ReadSector(2 + partition.Start);
                drSigWord = BigEndianBitConverter.ToUInt16(mdbSector, 0);

                if (drSigWord == AppleCommon.HFS_MAGIC)
                {
                    bbSector = imagePlugin.ReadSector(partition.Start);
                }
                else
                {
                    return;
                }
            }

            MasterDirectoryBlock mdb = Marshal.ByteArrayToStructureBigEndian <MasterDirectoryBlock>(mdbSector);

            sb.AppendLine("Apple Hierarchical File System");
            sb.AppendLine();

            if (apmFromHddOnCd)
            {
                sb.AppendLine("HFS uses 512 bytes/sector while device uses 2048 bytes/sector.").AppendLine();
            }

            sb.AppendLine("Master Directory Block:");
            sb.AppendFormat("Creation date: {0}", DateHandlers.MacToDateTime(mdb.drCrDate)).AppendLine();
            sb.AppendFormat("Last modification date: {0}", DateHandlers.MacToDateTime(mdb.drLsMod)).AppendLine();

            if (mdb.drVolBkUp > 0)
            {
                sb.AppendFormat("Last backup date: {0}", DateHandlers.MacToDateTime(mdb.drVolBkUp)).AppendLine();
                sb.AppendFormat("Backup sequence number: {0}", mdb.drVSeqNum).AppendLine();
            }
            else
            {
                sb.AppendLine("Volume has never been backed up");
            }

            if (mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.HardwareLock))
            {
                sb.AppendLine("Volume is locked by hardware.");
            }

            sb.AppendLine(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.Unmounted) ? "Volume was unmonted."
                              : "Volume is mounted.");

            if (mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.SparedBadBlocks))
            {
                sb.AppendLine("Volume has spared bad blocks.");
            }

            if (mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.DoesNotNeedCache))
            {
                sb.AppendLine("Volume does not need cache.");
            }

            if (mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.BootInconsistent))
            {
                sb.AppendLine("Boot volume is inconsistent.");
            }

            if (mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.ReusedIds))
            {
                sb.AppendLine("There are reused CNIDs.");
            }

            if (mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.Journaled))
            {
                sb.AppendLine("Volume is journaled.");
            }

            if (mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.Inconsistent))
            {
                sb.AppendLine("Volume is seriously inconsistent.");
            }

            if (mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.SoftwareLock))
            {
                sb.AppendLine("Volume is locked by software.");
            }

            sb.AppendFormat("{0} files on root directory", mdb.drNmFls).AppendLine();
            sb.AppendFormat("{0} directories on root directory", mdb.drNmRtDirs).AppendLine();
            sb.AppendFormat("{0} files on volume", mdb.drFilCnt).AppendLine();
            sb.AppendFormat("{0} directories on volume", mdb.drDirCnt).AppendLine();
            sb.AppendFormat("Volume write count: {0}", mdb.drWrCnt).AppendLine();

            sb.AppendFormat("Volume bitmap starting sector (in 512-bytes): {0}", mdb.drVBMSt).AppendLine();
            sb.AppendFormat("Next allocation block: {0}.", mdb.drAllocPtr).AppendLine();
            sb.AppendFormat("{0} volume allocation blocks.", mdb.drNmAlBlks).AppendLine();
            sb.AppendFormat("{0} bytes per allocation block.", mdb.drAlBlkSiz).AppendLine();
            sb.AppendFormat("{0} bytes to allocate when extending a file.", mdb.drClpSiz).AppendLine();
            sb.AppendFormat("{0} bytes to allocate when extending a Extents B-Tree.", mdb.drXTClpSiz).AppendLine();
            sb.AppendFormat("{0} bytes to allocate when extending a Catalog B-Tree.", mdb.drCTClpSiz).AppendLine();
            sb.AppendFormat("Sector of first allocation block: {0}", mdb.drAlBlSt).AppendLine();
            sb.AppendFormat("Next unused CNID: {0}", mdb.drNxtCNID).AppendLine();
            sb.AppendFormat("{0} unused allocation blocks.", mdb.drFreeBks).AppendLine();

            sb.AppendFormat("{0} bytes in the Extents B-Tree", mdb.drXTFlSize).AppendLine();
            sb.AppendFormat("{0} bytes in the Catalog B-Tree", mdb.drCTFlSize).AppendLine();

            sb.AppendFormat("Volume name: {0}", StringHandlers.PascalToString(mdb.drVN, Encoding)).AppendLine();

            sb.AppendLine("Finder info:");
            sb.AppendFormat("CNID of bootable system's directory: {0}", mdb.drFndrInfo0).AppendLine();
            sb.AppendFormat("CNID of first-run application's directory: {0}", mdb.drFndrInfo1).AppendLine();
            sb.AppendFormat("CNID of previously opened directory: {0}", mdb.drFndrInfo2).AppendLine();
            sb.AppendFormat("CNID of bootable Mac OS 8 or 9 directory: {0}", mdb.drFndrInfo3).AppendLine();
            sb.AppendFormat("CNID of bootable Mac OS X directory: {0}", mdb.drFndrInfo5).AppendLine();

            if (mdb.drFndrInfo6 != 0 &&
                mdb.drFndrInfo7 != 0)
            {
                sb.AppendFormat("Mac OS X Volume ID: {0:X8}{1:X8}", mdb.drFndrInfo6, mdb.drFndrInfo7).AppendLine();
            }

            if (mdb.drEmbedSigWord == AppleCommon.HFSP_MAGIC)
            {
                sb.AppendLine("Volume wraps a HFS+ volume.");
                sb.AppendFormat("Starting block of the HFS+ volume: {0}", mdb.xdrStABNt).AppendLine();
                sb.AppendFormat("Allocations blocks of the HFS+ volume: {0}", mdb.xdrNumABlks).AppendLine();
            }
            else
            {
                sb.AppendFormat("{0} blocks in volume cache", mdb.drVCSize).AppendLine();
                sb.AppendFormat("{0} blocks in volume bitmap cache", mdb.drVBMCSize).AppendLine();
                sb.AppendFormat("{0} blocks in volume common cache", mdb.drCtlCSize).AppendLine();
            }

            string bootBlockInfo = AppleCommon.GetBootBlockInformation(bbSector, Encoding);

            if (bootBlockInfo != null)
            {
                sb.AppendLine("Volume is bootable.");
                sb.AppendLine();
                sb.AppendLine(bootBlockInfo);
            }
            else if (mdb.drFndrInfo0 != 0 ||
                     mdb.drFndrInfo3 != 0 ||
                     mdb.drFndrInfo5 != 0)
            {
                sb.AppendLine("Volume is bootable.");
            }
            else
            {
                sb.AppendLine("Volume is not bootable.");
            }

            information = sb.ToString();

            XmlFsType = new FileSystemType();

            if (mdb.drVolBkUp > 0)
            {
                XmlFsType.BackupDate          = DateHandlers.MacToDateTime(mdb.drVolBkUp);
                XmlFsType.BackupDateSpecified = true;
            }

            XmlFsType.Bootable = bootBlockInfo != null || mdb.drFndrInfo0 != 0 || mdb.drFndrInfo3 != 0 ||
                                 mdb.drFndrInfo5 != 0;

            XmlFsType.Clusters    = mdb.drNmAlBlks;
            XmlFsType.ClusterSize = mdb.drAlBlkSiz;

            if (mdb.drCrDate > 0)
            {
                XmlFsType.CreationDate          = DateHandlers.MacToDateTime(mdb.drCrDate);
                XmlFsType.CreationDateSpecified = true;
            }

            XmlFsType.Dirty                 = !mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.Unmounted);
            XmlFsType.Files                 = mdb.drFilCnt;
            XmlFsType.FilesSpecified        = true;
            XmlFsType.FreeClusters          = mdb.drFreeBks;
            XmlFsType.FreeClustersSpecified = true;

            if (mdb.drLsMod > 0)
            {
                XmlFsType.ModificationDate          = DateHandlers.MacToDateTime(mdb.drLsMod);
                XmlFsType.ModificationDateSpecified = true;
            }

            XmlFsType.Type       = "HFS";
            XmlFsType.VolumeName = StringHandlers.PascalToString(mdb.drVN, Encoding);

            if (mdb.drFndrInfo6 != 0 &&
                mdb.drFndrInfo7 != 0)
            {
                XmlFsType.VolumeSerial = $"{mdb.drFndrInfo6:X8}{mdb.drFndrInfo7:X8}";
            }
        }
Exemplo n.º 17
0
        public bool Open(IFilter imageFilter)
        {
            Stream stream = imageFilter.GetDataForkStream();

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

            DartHeader header = new DartHeader();

            stream.Seek(0, SeekOrigin.Begin);
            byte[] headerB = new byte[Marshal.SizeOf(header)];

            stream.Read(headerB, 0, Marshal.SizeOf(header));
            header = BigEndianMarshal.ByteArrayToStructureBigEndian <DartHeader>(headerB);

            if (header.srcCmp > COMPRESS_NONE)
            {
                return(false);
            }

            int expectedMaxSize = 84 + header.srcSize * 2 * 524;

            switch (header.srcType)
            {
            case DISK_MAC:
                if (header.srcSize != SIZE_MAC_SS && header.srcSize != SIZE_MAC)
                {
                    return(false);
                }

                break;

            case DISK_LISA:
                if (header.srcSize != SIZE_LISA)
                {
                    return(false);
                }

                break;

            case DISK_APPLE2:
                if (header.srcSize != DISK_APPLE2)
                {
                    return(false);
                }

                break;

            case DISK_MAC_HD:
                if (header.srcSize != SIZE_MAC_HD)
                {
                    return(false);
                }

                expectedMaxSize += 64;
                break;

            case DISK_DOS:
                if (header.srcSize != SIZE_DOS)
                {
                    return(false);
                }

                break;

            case DISK_DOS_HD:
                if (header.srcSize != SIZE_DOS_HD)
                {
                    return(false);
                }

                expectedMaxSize += 64;
                break;

            default: return(false);
            }

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

            short[] bLength;

            if (header.srcType == DISK_MAC_HD || header.srcType == DISK_DOS_HD)
            {
                bLength = new short[BLOCK_ARRAY_LEN_HIGH];
            }
            else
            {
                bLength = new short[BLOCK_ARRAY_LEN_LOW];
            }

            BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;

            for (int i = 0; i < bLength.Length; i++)
            {
                byte[] tmpShort = new byte[2];
                stream.Read(tmpShort, 0, 2);
                bLength[i] = BigEndianBitConverter.ToInt16(tmpShort, 0);
            }

            MemoryStream dataMs = new MemoryStream();
            MemoryStream tagMs  = new MemoryStream();

            foreach (short l in bLength)
            {
                if (l != 0)
                {
                    byte[] buffer = new byte[BUFFER_SIZE];
                    if (l == -1)
                    {
                        stream.Read(buffer, 0, BUFFER_SIZE);
                        dataMs.Write(buffer, 0, DATA_SIZE);
                        tagMs.Write(buffer, DATA_SIZE, TAG_SIZE);
                    }
                    else
                    {
                        byte[] temp;
                        if (header.srcCmp == COMPRESS_RLE)
                        {
                            temp = new byte[l * 2];
                            stream.Read(temp, 0, temp.Length);
                            AppleRle rle = new AppleRle(new MemoryStream(temp));
                            buffer = new byte[BUFFER_SIZE];
                            for (int i = 0; i < BUFFER_SIZE; i++)
                            {
                                buffer[i] = (byte)rle.ProduceByte();
                            }
                            dataMs.Write(buffer, 0, DATA_SIZE);
                            tagMs.Write(buffer, DATA_SIZE, TAG_SIZE);
                        }
                        else
                        {
                            temp = new byte[l];
                            stream.Read(temp, 0, temp.Length);
                            throw new ImageNotSupportedException("LZH Compressed images not yet supported");
                        }
                    }
                }
            }

            dataCache = dataMs.ToArray();
            if (header.srcType == DISK_LISA || header.srcType == DISK_MAC || header.srcType == DISK_APPLE2)
            {
                imageInfo.ReadableSectorTags.Add(SectorTagType.AppleSectorTag);
                tagCache = tagMs.ToArray();
            }

            try
            {
                if (imageFilter.HasResourceFork())
                {
                    ResourceFork rsrcFork = new ResourceFork(imageFilter.GetResourceForkStream());
                    // "vers"
                    if (rsrcFork.ContainsKey(0x76657273))
                    {
                        Resource versRsrc = rsrcFork.GetResource(0x76657273);

                        byte[] vers = versRsrc?.GetResource(versRsrc.GetIds()[0]);

                        if (vers != null)
                        {
                            Version version = new Version(vers);

                            string release = null;
                            string dev     = null;
                            string pre     = null;

                            string major = $"{version.MajorVersion}";
                            string minor = $".{version.MinorVersion / 10}";
                            if (version.MinorVersion % 10 > 0)
                            {
                                release = $".{version.MinorVersion % 10}";
                            }
                            switch (version.DevStage)
                            {
                            case Version.DevelopmentStage.Alpha:
                                dev = "a";
                                break;

                            case Version.DevelopmentStage.Beta:
                                dev = "b";
                                break;

                            case Version.DevelopmentStage.PreAlpha:
                                dev = "d";
                                break;
                            }

                            if (dev == null && version.PreReleaseVersion > 0)
                            {
                                dev = "f";
                            }

                            if (dev != null)
                            {
                                pre = $"{version.PreReleaseVersion}";
                            }

                            imageInfo.ApplicationVersion = $"{major}{minor}{release}{dev}{pre}";
                            imageInfo.Application        = version.VersionString;
                            imageInfo.Comments           = version.VersionMessage;
                        }
                    }

                    // "dart"
                    if (rsrcFork.ContainsKey(0x44415254))
                    {
                        Resource dartRsrc = rsrcFork.GetResource(0x44415254);
                        if (dartRsrc != null)
                        {
                            string dArt = StringHandlers.PascalToString(dartRsrc.GetResource(dartRsrc.GetIds()[0]),
                                                                        Encoding.GetEncoding("macintosh"));
                            const string DART_REGEX =
                                @"(?<version>\S+), tag checksum=\$(?<tagchk>[0123456789ABCDEF]{8}), data checksum=\$(?<datachk>[0123456789ABCDEF]{8})$";
                            Regex dArtEx    = new Regex(DART_REGEX);
                            Match dArtMatch = dArtEx.Match(dArt);

                            if (dArtMatch.Success)
                            {
                                imageInfo.Application        = "DART";
                                imageInfo.ApplicationVersion = dArtMatch.Groups["version"].Value;
                                dataChecksum = Convert.ToUInt32(dArtMatch.Groups["datachk"].Value, 16);
                                tagChecksum  = Convert.ToUInt32(dArtMatch.Groups["tagchk"].Value, 16);
                            }
                        }
                    }

                    // "cksm"
                    if (rsrcFork.ContainsKey(0x434B534D))
                    {
                        Resource cksmRsrc = rsrcFork.GetResource(0x434B534D);
                        if (cksmRsrc?.ContainsId(1) == true)
                        {
                            byte[] tagChk = cksmRsrc.GetResource(1);
                            tagChecksum = BigEndianBitConverter.ToUInt32(tagChk, 0);
                        }

                        if (cksmRsrc?.ContainsId(2) == true)
                        {
                            byte[] dataChk = cksmRsrc.GetResource(1);
                            dataChecksum = BigEndianBitConverter.ToUInt32(dataChk, 0);
                        }
                    }
                }
            }
            catch (InvalidCastException) { }

            DicConsole.DebugWriteLine("DART plugin", "Image application = {0} version {1}", imageInfo.Application,
                                      imageInfo.ApplicationVersion);

            imageInfo.Sectors              = (ulong)(header.srcSize * 2);
            imageInfo.CreationTime         = imageFilter.GetCreationTime();
            imageInfo.LastModificationTime = imageFilter.GetLastWriteTime();
            imageInfo.MediaTitle           = Path.GetFileNameWithoutExtension(imageFilter.GetFilename());
            imageInfo.SectorSize           = SECTOR_SIZE;
            imageInfo.XmlMediaType         = XmlMediaType.BlockMedia;
            imageInfo.ImageSize            = imageInfo.Sectors * SECTOR_SIZE;
            imageInfo.Version              = header.srcCmp == COMPRESS_NONE ? "1.4" : "1.5";

            switch (header.srcSize)
            {
            case SIZE_MAC_SS:
                imageInfo.Cylinders       = 80;
                imageInfo.Heads           = 1;
                imageInfo.SectorsPerTrack = 10;
                imageInfo.MediaType       = MediaType.AppleSonySS;
                break;

            case SIZE_MAC:
                imageInfo.Cylinders       = 80;
                imageInfo.Heads           = 2;
                imageInfo.SectorsPerTrack = 10;
                imageInfo.MediaType       = MediaType.AppleSonyDS;
                break;

            case SIZE_DOS:
                imageInfo.Cylinders       = 80;
                imageInfo.Heads           = 2;
                imageInfo.SectorsPerTrack = 9;
                imageInfo.MediaType       = MediaType.DOS_35_DS_DD_9;
                break;

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

            return(true);
        }
Exemplo n.º 18
0
        public bool Identify(IFilter imageFilter)
        {
            Stream stream = imageFilter.GetDataForkStream();

            stream.Seek(0, SeekOrigin.Begin);
            byte[] buffer  = new byte[0x58];
            byte[] pString = new byte[64];
            stream.Read(buffer, 0, 0x58);

            // Incorrect pascal string length, not DC42
            if (buffer[0] > 63)
            {
                return(false);
            }

            Dc42Header tmpHeader = new Dc42Header();

            Array.Copy(buffer, 0, pString, 0, 64);

            BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;

            tmpHeader.DiskName     = StringHandlers.PascalToString(pString, Encoding.GetEncoding("macintosh"));
            tmpHeader.DataSize     = BigEndianBitConverter.ToUInt32(buffer, 0x40);
            tmpHeader.TagSize      = BigEndianBitConverter.ToUInt32(buffer, 0x44);
            tmpHeader.DataChecksum = BigEndianBitConverter.ToUInt32(buffer, 0x48);
            tmpHeader.TagChecksum  = BigEndianBitConverter.ToUInt32(buffer, 0x4C);
            tmpHeader.Format       = buffer[0x50];
            tmpHeader.FmtByte      = buffer[0x51];
            tmpHeader.Valid        = buffer[0x52];
            tmpHeader.Reserved     = buffer[0x53];

            DicConsole.DebugWriteLine("DC42 plugin", "tmp_header.diskName = \"{0}\"", tmpHeader.DiskName);
            DicConsole.DebugWriteLine("DC42 plugin", "tmp_header.dataSize = {0} bytes", tmpHeader.DataSize);
            DicConsole.DebugWriteLine("DC42 plugin", "tmp_header.tagSize = {0} bytes", tmpHeader.TagSize);
            DicConsole.DebugWriteLine("DC42 plugin", "tmp_header.dataChecksum = 0x{0:X8}", tmpHeader.DataChecksum);
            DicConsole.DebugWriteLine("DC42 plugin", "tmp_header.tagChecksum = 0x{0:X8}", tmpHeader.TagChecksum);
            DicConsole.DebugWriteLine("DC42 plugin", "tmp_header.format = 0x{0:X2}", tmpHeader.Format);
            DicConsole.DebugWriteLine("DC42 plugin", "tmp_header.fmtByte = 0x{0:X2}", tmpHeader.FmtByte);
            DicConsole.DebugWriteLine("DC42 plugin", "tmp_header.valid = {0}", tmpHeader.Valid);
            DicConsole.DebugWriteLine("DC42 plugin", "tmp_header.reserved = {0}", tmpHeader.Reserved);

            if (tmpHeader.Valid != 1 || tmpHeader.Reserved != 0)
            {
                return(false);
            }

            // Some versions seem to incorrectly create little endian fields
            if (tmpHeader.DataSize + tmpHeader.TagSize + 0x54 != imageFilter.GetDataForkLength() &&
                tmpHeader.Format != kSigmaFormatTwiggy)
            {
                tmpHeader.DataSize     = BitConverter.ToUInt32(buffer, 0x40);
                tmpHeader.TagSize      = BitConverter.ToUInt32(buffer, 0x44);
                tmpHeader.DataChecksum = BitConverter.ToUInt32(buffer, 0x48);
                tmpHeader.TagChecksum  = BitConverter.ToUInt32(buffer, 0x4C);

                if (tmpHeader.DataSize + tmpHeader.TagSize + 0x54 != imageFilter.GetDataForkLength() &&
                    tmpHeader.Format != kSigmaFormatTwiggy)
                {
                    return(false);
                }
            }

            if (tmpHeader.Format != kSonyFormat400K && tmpHeader.Format != kSonyFormat800K &&
                tmpHeader.Format != kSonyFormat720K && tmpHeader.Format != kSonyFormat1440K &&
                tmpHeader.Format != kSonyFormat1680K && tmpHeader.Format != kSigmaFormatTwiggy &&
                tmpHeader.Format != kNotStandardFormat)
            {
                DicConsole.DebugWriteLine("DC42 plugin", "Unknown tmp_header.format = 0x{0:X2} value",
                                          tmpHeader.Format);

                return(false);
            }

            if (tmpHeader.FmtByte != kSonyFmtByte400K && tmpHeader.FmtByte != kSonyFmtByte800K &&
                tmpHeader.FmtByte != kSonyFmtByte800KIncorrect && tmpHeader.FmtByte != kSonyFmtByteProDos &&
                tmpHeader.FmtByte != kInvalidFmtByte && tmpHeader.FmtByte != kSigmaFmtByteTwiggy &&
                tmpHeader.FmtByte != kFmtNotStandard && tmpHeader.FmtByte != kMacOSXFmtByte)
            {
                DicConsole.DebugWriteLine("DC42 plugin", "Unknown tmp_header.fmtByte = 0x{0:X2} value",
                                          tmpHeader.FmtByte);

                return(false);
            }

            if (tmpHeader.FmtByte != kInvalidFmtByte)
            {
                return(true);
            }

            DicConsole.DebugWriteLine("DC42 plugin", "Image says it's unformatted");

            return(false);
        }
Exemplo n.º 19
0
        public Errno Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding,
                           Dictionary <string, string> options, string @namespace)
        {
            device   = imagePlugin;
            Encoding = encoding ?? new Apple2();

            if (options == null)
            {
                options = GetDefaultOptions();
            }

            if (options.TryGetValue("debug", out string debugString))
            {
                bool.TryParse(debugString, out debug);
            }

            if (device.Info.Sectors < 3)
            {
                return(Errno.InvalidArgument);
            }

            multiplier = (uint)(imagePlugin.Info.SectorSize == 256 ? 2 : 1);

            // Blocks 0 and 1 are boot code
            catalogBlocks = device.ReadSectors(multiplier * 2, multiplier);

            // On Apple //, it's little endian
            // TODO: Fix
            //BigEndianBitConverter.IsLittleEndian =
            //    multiplier == 2 ? !BitConverter.IsLittleEndian : BitConverter.IsLittleEndian;

            mountedVolEntry.FirstBlock = BigEndianBitConverter.ToInt16(catalogBlocks, 0x00);
            mountedVolEntry.LastBlock  = BigEndianBitConverter.ToInt16(catalogBlocks, 0x02);
            mountedVolEntry.EntryType  = (PascalFileKind)BigEndianBitConverter.ToInt16(catalogBlocks, 0x04);
            mountedVolEntry.VolumeName = new byte[8];
            Array.Copy(catalogBlocks, 0x06, mountedVolEntry.VolumeName, 0, 8);
            mountedVolEntry.Blocks   = BigEndianBitConverter.ToInt16(catalogBlocks, 0x0E);
            mountedVolEntry.Files    = BigEndianBitConverter.ToInt16(catalogBlocks, 0x10);
            mountedVolEntry.Dummy    = BigEndianBitConverter.ToInt16(catalogBlocks, 0x12);
            mountedVolEntry.LastBoot = BigEndianBitConverter.ToInt16(catalogBlocks, 0x14);
            mountedVolEntry.Tail     = BigEndianBitConverter.ToInt32(catalogBlocks, 0x16);

            if (mountedVolEntry.FirstBlock != 0 ||
                mountedVolEntry.LastBlock <= mountedVolEntry.FirstBlock ||
                (ulong)mountedVolEntry.LastBlock > (device.Info.Sectors / multiplier) - 2 ||
                (mountedVolEntry.EntryType != PascalFileKind.Volume &&
                 mountedVolEntry.EntryType != PascalFileKind.Secure) ||
                mountedVolEntry.VolumeName[0] > 7 ||
                mountedVolEntry.Blocks < 0 ||
                (ulong)mountedVolEntry.Blocks != device.Info.Sectors / multiplier ||
                mountedVolEntry.Files < 0)
            {
                return(Errno.InvalidArgument);
            }

            catalogBlocks = device.ReadSectors(multiplier * 2,
                                               (uint)(mountedVolEntry.LastBlock - mountedVolEntry.FirstBlock - 2) *
                                               multiplier);

            int offset = 26;

            fileEntries = new List <PascalFileEntry>();

            while (offset + 26 < catalogBlocks.Length)
            {
                var entry = new PascalFileEntry
                {
                    Filename   = new byte[16],
                    FirstBlock = BigEndianBitConverter.ToInt16(catalogBlocks, offset + 0x00),
                    LastBlock  =
                        BigEndianBitConverter.ToInt16(catalogBlocks, offset + 0x02),
                    EntryType        = (PascalFileKind)BigEndianBitConverter.ToInt16(catalogBlocks, offset + 0x04),
                    LastBytes        = BigEndianBitConverter.ToInt16(catalogBlocks, offset + 0x16),
                    ModificationTime = BigEndianBitConverter.ToInt16(catalogBlocks, offset + 0x18)
                };

                Array.Copy(catalogBlocks, offset + 0x06, entry.Filename, 0, 16);

                if (entry.Filename[0] <= 15 &&
                    entry.Filename[0] > 0)
                {
                    fileEntries.Add(entry);
                }

                offset += 26;
            }

            bootBlocks = device.ReadSectors(0, 2 * multiplier);

            XmlFsType = new FileSystemType
            {
                Bootable       = !ArrayHelpers.ArrayIsNullOrEmpty(bootBlocks), Clusters = (ulong)mountedVolEntry.Blocks,
                ClusterSize    = device.Info.SectorSize, Files = (ulong)mountedVolEntry.Files,
                FilesSpecified = true,
                Type           = "UCSD Pascal",
                VolumeName     =
                    StringHandlers.PascalToString(mountedVolEntry.VolumeName, Encoding)
            };

            mounted = true;

            return(Errno.NoError);
        }
Exemplo n.º 20
0
        public bool Open(IFilter imageFilter)
        {
            if (!imageFilter.HasResourceFork() || imageFilter.GetResourceForkLength() == 0)
            {
                return(false);
            }

            ResourceFork rsrcFork;
            Resource     rsrc;

            short[] bcems;

            try
            {
                rsrcFork = new ResourceFork(imageFilter.GetResourceForkStream());
                if (!rsrcFork.ContainsKey(NDIF_RESOURCE))
                {
                    return(false);
                }

                rsrc = rsrcFork.GetResource(NDIF_RESOURCE);

                bcems = rsrc.GetIds();

                if (bcems == null || bcems.Length == 0)
                {
                    return(false);
                }
            }
            catch (InvalidCastException) { return(false); }

            imageInfo.Sectors = 0;
            foreach (byte[] bcem in bcems.Select(id => rsrc.GetResource(NDIF_RESOURCEID)))
            {
                if (bcem.Length < 128)
                {
                    return(false);
                }

                header = Marshal.ByteArrayToStructureBigEndian <ChunkHeader>(bcem);

                DicConsole.DebugWriteLine("NDIF plugin", "footer.type = {0}", header.version);
                DicConsole.DebugWriteLine("NDIF plugin", "footer.driver = {0}", header.driver);
                DicConsole.DebugWriteLine("NDIF plugin", "footer.name = {0}",
                                          StringHandlers.PascalToString(header.name,
                                                                        Encoding.GetEncoding("macintosh")));
                DicConsole.DebugWriteLine("NDIF plugin", "footer.sectors = {0}", header.sectors);
                DicConsole.DebugWriteLine("NDIF plugin", "footer.maxSectorsPerChunk = {0}", header.maxSectorsPerChunk);
                DicConsole.DebugWriteLine("NDIF plugin", "footer.dataOffset = {0}", header.dataOffset);
                DicConsole.DebugWriteLine("NDIF plugin", "footer.crc = 0x{0:X7}", header.crc);
                DicConsole.DebugWriteLine("NDIF plugin", "footer.segmented = {0}", header.segmented);
                DicConsole.DebugWriteLine("NDIF plugin", "footer.p1 = 0x{0:X8}", header.p1);
                DicConsole.DebugWriteLine("NDIF plugin", "footer.p2 = 0x{0:X8}", header.p2);
                DicConsole.DebugWriteLine("NDIF plugin", "footer.unknown[0] = 0x{0:X8}", header.unknown[0]);
                DicConsole.DebugWriteLine("NDIF plugin", "footer.unknown[1] = 0x{0:X8}", header.unknown[1]);
                DicConsole.DebugWriteLine("NDIF plugin", "footer.unknown[2] = 0x{0:X8}", header.unknown[2]);
                DicConsole.DebugWriteLine("NDIF plugin", "footer.unknown[3] = 0x{0:X8}", header.unknown[3]);
                DicConsole.DebugWriteLine("NDIF plugin", "footer.unknown[4] = 0x{0:X8}", header.unknown[4]);
                DicConsole.DebugWriteLine("NDIF plugin", "footer.encrypted = {0}", header.encrypted);
                DicConsole.DebugWriteLine("NDIF plugin", "footer.hash = 0x{0:X8}", header.hash);
                DicConsole.DebugWriteLine("NDIF plugin", "footer.chunks = {0}", header.chunks);

                // Block chunks and headers
                chunks = new Dictionary <ulong, BlockChunk>();

                BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;

                for (int i = 0; i < header.chunks; i++)
                {
                    // Obsolete read-only NDIF only prepended the header and then put the image without any kind of block references.
                    // So let's falsify a block chunk
                    BlockChunk bChnk  = new BlockChunk();
                    byte[]     sector = new byte[4];
                    Array.Copy(bcem, 128 + 0 + i * 12, sector, 1, 3);
                    bChnk.sector = BigEndianBitConverter.ToUInt32(sector, 0);
                    bChnk.type   = bcem[128 + 3 + i * 12];
                    bChnk.offset = BigEndianBitConverter.ToUInt32(bcem, 128 + 4 + i * 12);
                    bChnk.length = BigEndianBitConverter.ToUInt32(bcem, 128 + 8 + i * 12);

                    DicConsole.DebugWriteLine("NDIF plugin", "bHdr.chunk[{0}].type = 0x{1:X2}", i, bChnk.type);
                    DicConsole.DebugWriteLine("NDIF plugin", "bHdr.chunk[{0}].sector = {1}", i, bChnk.sector);
                    DicConsole.DebugWriteLine("NDIF plugin", "bHdr.chunk[{0}].offset = {1}", i, bChnk.offset);
                    DicConsole.DebugWriteLine("NDIF plugin", "bHdr.chunk[{0}].length = {1}", i, bChnk.length);

                    if (bChnk.type == CHUNK_TYPE_END)
                    {
                        break;
                    }

                    bChnk.offset += header.dataOffset;
                    bChnk.sector += (uint)imageInfo.Sectors;

                    // TODO: Handle compressed chunks
                    switch (bChnk.type)
                    {
                    case CHUNK_TYPE_KENCODE:
                        throw new
                              ImageNotSupportedException("Chunks compressed with KenCode are not yet supported.");

                    case CHUNK_TYPE_LZH:
                        throw new ImageNotSupportedException("Chunks compressed with LZH are not yet supported.");

                    case CHUNK_TYPE_STUFFIT:
                        throw new
                              ImageNotSupportedException("Chunks compressed with StuffIt! are not yet supported.");
                    }

                    // TODO: Handle compressed chunks
                    if (bChnk.type > CHUNK_TYPE_COPY && bChnk.type < CHUNK_TYPE_KENCODE ||
                        bChnk.type > CHUNK_TYPE_ADC && bChnk.type < CHUNK_TYPE_STUFFIT ||
                        bChnk.type > CHUNK_TYPE_STUFFIT && bChnk.type < CHUNK_TYPE_END || bChnk.type == 1)
                    {
                        throw new ImageNotSupportedException($"Unsupported chunk type 0x{bChnk.type:X8} found");
                    }

                    chunks.Add(bChnk.sector, bChnk);
                }

                imageInfo.Sectors += header.sectors;
            }

            if (header.segmented > 0)
            {
                throw new ImageNotSupportedException("Segmented images are not yet supported.");
            }

            if (header.encrypted > 0)
            {
                throw new ImageNotSupportedException("Encrypted images are not yet supported.");
            }

            switch (imageInfo.Sectors)
            {
            case 1440:
                imageInfo.MediaType = MediaType.DOS_35_DS_DD_9;
                break;

            case 1600:
                imageInfo.MediaType = MediaType.AppleSonyDS;
                break;

            case 2880:
                imageInfo.MediaType = MediaType.DOS_35_HD;
                break;

            case 3360:
                imageInfo.MediaType = MediaType.DMF;
                break;

            default:
                imageInfo.MediaType = MediaType.GENERIC_HDD;
                break;
            }

            if (rsrcFork.ContainsKey(0x76657273))
            {
                Resource versRsrc = rsrcFork.GetResource(0x76657273);
                if (versRsrc != null)
                {
                    byte[] vers = versRsrc.GetResource(versRsrc.GetIds()[0]);

                    Version version = new Version(vers);

                    string release = null;
                    string dev     = null;
                    string pre     = null;

                    string major = $"{version.MajorVersion}";
                    string minor = $".{version.MinorVersion / 10}";
                    if (version.MinorVersion % 10 > 0)
                    {
                        release = $".{version.MinorVersion % 10}";
                    }
                    switch (version.DevStage)
                    {
                    case Version.DevelopmentStage.Alpha:
                        dev = "a";
                        break;

                    case Version.DevelopmentStage.Beta:
                        dev = "b";
                        break;

                    case Version.DevelopmentStage.PreAlpha:
                        dev = "d";
                        break;
                    }

                    if (dev == null && version.PreReleaseVersion > 0)
                    {
                        dev = "f";
                    }

                    if (dev != null)
                    {
                        pre = $"{version.PreReleaseVersion}";
                    }

                    imageInfo.ApplicationVersion = $"{major}{minor}{release}{dev}{pre}";
                    imageInfo.Application        = version.VersionString;
                    imageInfo.Comments           = version.VersionMessage;

                    if (version.MajorVersion == 3)
                    {
                        imageInfo.Application = "ShrinkWrap™";
                    }
                    else if (version.MajorVersion == 6)
                    {
                        imageInfo.Application = "DiskCopy";
                    }
                }
            }

            DicConsole.DebugWriteLine("NDIF plugin", "Image application = {0} version {1}", imageInfo.Application,
                                      imageInfo.ApplicationVersion);

            sectorCache           = new Dictionary <ulong, byte[]>();
            chunkCache            = new Dictionary <ulong, byte[]>();
            currentChunkCacheSize = 0;
            imageStream           = imageFilter.GetDataForkStream();
            buffersize            = header.maxSectorsPerChunk * SECTOR_SIZE;

            imageInfo.CreationTime         = imageFilter.GetCreationTime();
            imageInfo.LastModificationTime = imageFilter.GetLastWriteTime();
            imageInfo.MediaTitle           =
                StringHandlers.PascalToString(header.name, Encoding.GetEncoding("macintosh"));
            imageInfo.SectorSize         = SECTOR_SIZE;
            imageInfo.XmlMediaType       = XmlMediaType.BlockMedia;
            imageInfo.ImageSize          = imageInfo.Sectors * SECTOR_SIZE;
            imageInfo.ApplicationVersion = "6";
            imageInfo.Application        = "Apple DiskCopy";

            switch (imageInfo.MediaType)
            {
            case MediaType.AppleSonyDS:
                imageInfo.Cylinders       = 80;
                imageInfo.Heads           = 2;
                imageInfo.SectorsPerTrack = 10;
                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.DMF:
                imageInfo.Cylinders       = 80;
                imageInfo.Heads           = 2;
                imageInfo.SectorsPerTrack = 21;
                break;

            default:
                imageInfo.MediaType       = MediaType.GENERIC_HDD;
                imageInfo.Cylinders       = (uint)(imageInfo.Sectors / 16 / 63);
                imageInfo.Heads           = 16;
                imageInfo.SectorsPerTrack = 63;
                break;
            }

            return(true);
        }
Exemplo n.º 21
0
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding = encoding ?? Encoding.GetEncoding("iso-8859-1");
            StringBuilder sbInformation = new StringBuilder();

            XmlFsType   = new FileSystemType();
            information = null;
            BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;

            byte[] bootBlockSectors = imagePlugin.ReadSectors(0 + partition.Start, 2);

            BootBlock bootBlk = Marshal.ByteArrayToStructureBigEndian <BootBlock>(bootBlockSectors);

            bootBlk.bootCode = new byte[bootBlockSectors.Length - 12];
            Array.Copy(bootBlockSectors, 12, bootBlk.bootCode, 0, bootBlk.bootCode.Length);
            bootBlockSectors[4] = bootBlockSectors[5] = bootBlockSectors[6] = bootBlockSectors[7] = 0;
            uint bsum = AmigaBootChecksum(bootBlockSectors);

            ulong bRootPtr = 0;

            // If bootblock is correct, let's take its rootblock pointer
            if (bsum == bootBlk.checksum)
            {
                bRootPtr = bootBlk.root_ptr + partition.Start;
                DicConsole.DebugWriteLine("AmigaDOS plugin", "Bootblock points to {0} as Rootblock", bRootPtr);
            }

            ulong[] rootPtrs =
            {
                bRootPtr + partition.Start,                                      (partition.End - partition.Start + 1) / 2 + partition.Start - 2,
                (partition.End - partition.Start + 1) / 2 + partition.Start - 1,
                (partition.End - partition.Start + 1) / 2 +
                partition.Start,
                (partition.End - partition.Start + 1) / 2 + partition.Start + 4
            };

            RootBlock rootBlk = new RootBlock();

            byte[] rootBlockSector = null;

            bool rootFound = false;
            uint blockSize = 0;

            // So to handle even number of sectors
            foreach (ulong rootPtr in rootPtrs.Where(rootPtr => rootPtr < partition.End && rootPtr >= partition.Start))
            {
                DicConsole.DebugWriteLine("AmigaDOS plugin", "Searching for Rootblock in sector {0}", rootPtr);

                rootBlockSector = imagePlugin.ReadSector(rootPtr);

                rootBlk.type = BigEndianBitConverter.ToUInt32(rootBlockSector, 0x00);
                DicConsole.DebugWriteLine("AmigaDOS plugin", "rootBlk.type = {0}", rootBlk.type);
                if (rootBlk.type != TYPE_HEADER)
                {
                    continue;
                }

                rootBlk.hashTableSize = BigEndianBitConverter.ToUInt32(rootBlockSector, 0x0C);

                DicConsole.DebugWriteLine("AmigaDOS plugin", "rootBlk.hashTableSize = {0}", rootBlk.hashTableSize);

                blockSize = (rootBlk.hashTableSize + 56) * 4;
                uint sectorsPerBlock = (uint)(blockSize / rootBlockSector.Length);

                DicConsole.DebugWriteLine("AmigaDOS plugin", "blockSize = {0}", blockSize);
                DicConsole.DebugWriteLine("AmigaDOS plugin", "sectorsPerBlock = {0}", sectorsPerBlock);

                if (blockSize % rootBlockSector.Length > 0)
                {
                    sectorsPerBlock++;
                }

                if (rootPtr + sectorsPerBlock >= partition.End)
                {
                    continue;
                }

                rootBlockSector = imagePlugin.ReadSectors(rootPtr, sectorsPerBlock);

                // Clear checksum on sector
                rootBlk.checksum    = BigEndianBitConverter.ToUInt32(rootBlockSector, 20);
                rootBlockSector[20] = rootBlockSector[21] = rootBlockSector[22] = rootBlockSector[23] = 0;
                uint rsum = AmigaChecksum(rootBlockSector);

                DicConsole.DebugWriteLine("AmigaDOS plugin", "rootBlk.checksum = 0x{0:X8}", rootBlk.checksum);
                DicConsole.DebugWriteLine("AmigaDOS plugin", "rsum = 0x{0:X8}", rsum);

                rootBlk.sec_type = BigEndianBitConverter.ToUInt32(rootBlockSector, rootBlockSector.Length - 4);
                DicConsole.DebugWriteLine("AmigaDOS plugin", "rootBlk.sec_type = {0}", rootBlk.sec_type);

                if (rootBlk.sec_type != SUBTYPE_ROOT || rootBlk.checksum != rsum)
                {
                    continue;
                }

                rootBlockSector = imagePlugin.ReadSectors(rootPtr, sectorsPerBlock);
                rootFound       = true;
                break;
            }

            if (!rootFound)
            {
                return;
            }

            rootBlk = MarshalRootBlock(rootBlockSector);

            string diskName = StringHandlers.PascalToString(rootBlk.diskName, Encoding);

            switch (bootBlk.diskType & 0xFF)
            {
            case 0:
                sbInformation.Append("Amiga Original File System");
                XmlFsType.Type = "Amiga OFS";
                break;

            case 1:
                sbInformation.Append("Amiga Fast File System");
                XmlFsType.Type = "Amiga FFS";
                break;

            case 2:
                sbInformation.Append("Amiga Original File System with international characters");
                XmlFsType.Type = "Amiga OFS";
                break;

            case 3:
                sbInformation.Append("Amiga Fast File System with international characters");
                XmlFsType.Type = "Amiga FFS";
                break;

            case 4:
                sbInformation.Append("Amiga Original File System with directory cache");
                XmlFsType.Type = "Amiga OFS";
                break;

            case 5:
                sbInformation.Append("Amiga Fast File System with directory cache");
                XmlFsType.Type = "Amiga FFS";
                break;

            case 6:
                sbInformation.Append("Amiga Original File System with long filenames");
                XmlFsType.Type = "Amiga OFS2";
                break;

            case 7:
                sbInformation.Append("Amiga Fast File System with long filenames");
                XmlFsType.Type = "Amiga FFS2";
                break;
            }

            if ((bootBlk.diskType & 0x6D754600) == 0x6D754600)
            {
                sbInformation.Append(", with multi-user patches");
            }

            sbInformation.AppendLine();

            sbInformation.AppendFormat("Volume name: {0}", diskName).AppendLine();

            if (bootBlk.checksum == bsum)
            {
                Sha1Context sha1Ctx = new Sha1Context();
                sha1Ctx.Update(bootBlk.bootCode);
                sbInformation.AppendLine("Volume is bootable");
                sbInformation.AppendFormat("Boot code SHA1 is {0}", sha1Ctx.End()).AppendLine();
            }

            if (rootBlk.bitmapFlag == 0xFFFFFFFF)
            {
                sbInformation.AppendLine("Volume bitmap is valid");
            }

            if (rootBlk.bitmapExtensionBlock != 0x00000000 && rootBlk.bitmapExtensionBlock != 0xFFFFFFFF)
            {
                sbInformation.AppendFormat("Bitmap extension at block {0}", rootBlk.bitmapExtensionBlock).AppendLine();
            }

            if ((bootBlk.diskType & 0xFF) == 4 || (bootBlk.diskType & 0xFF) == 5)
            {
                sbInformation.AppendFormat("Directory cache starts at block {0}", rootBlk.extension).AppendLine();
            }

            ulong blocks = (partition.End - partition.Start + 1) * imagePlugin.Info.SectorSize / blockSize;

            sbInformation.AppendFormat("Volume block size is {0} bytes", blockSize).AppendLine();
            sbInformation.AppendFormat("Volume has {0} blocks", blocks).AppendLine();
            sbInformation.AppendFormat("Volume created on {0}",
                                       DateHandlers.AmigaToDateTime(rootBlk.cDays, rootBlk.cMins, rootBlk.cTicks))
            .AppendLine();
            sbInformation.AppendFormat("Volume last modified on {0}",
                                       DateHandlers.AmigaToDateTime(rootBlk.vDays, rootBlk.vMins, rootBlk.vTicks))
            .AppendLine();
            sbInformation.AppendFormat("Volume root directory last modified on on {0}",
                                       DateHandlers.AmigaToDateTime(rootBlk.rDays, rootBlk.rMins, rootBlk.rTicks))
            .AppendLine();
            sbInformation.AppendFormat("Root block checksum is 0x{0:X8}", rootBlk.checksum).AppendLine();
            information = sbInformation.ToString();

            XmlFsType.CreationDate =
                DateHandlers.AmigaToDateTime(rootBlk.cDays, rootBlk.cMins, rootBlk.cTicks);
            XmlFsType.CreationDateSpecified = true;
            XmlFsType.ModificationDate      =
                DateHandlers.AmigaToDateTime(rootBlk.vDays, rootBlk.vMins, rootBlk.vTicks);
            XmlFsType.ModificationDateSpecified = true;
            XmlFsType.Dirty       = rootBlk.bitmapFlag != 0xFFFFFFFF;
            XmlFsType.Clusters    = blocks;
            XmlFsType.ClusterSize = blockSize;
            XmlFsType.VolumeName  = diskName;
            XmlFsType.Bootable    = bsum == bootBlk.checksum;
            // Useful as a serial
            XmlFsType.VolumeSerial = $"{rootBlk.checksum:X8}";
        }
Exemplo n.º 22
0
        public bool Open(IFilter imageFilter)
        {
            Stream stream = imageFilter.GetDataForkStream();

            stream.Seek(0, SeekOrigin.Begin);
            byte[] buffer  = new byte[0x58];
            byte[] pString = new byte[64];
            stream.Read(buffer, 0, 0x58);
            IsWriting = false;

            // Incorrect pascal string length, not DC42
            if (buffer[0] > 63)
            {
                return(false);
            }

            header = new Dc42Header();

            Array.Copy(buffer, 0, pString, 0, 64);
            header.DiskName     = StringHandlers.PascalToString(pString, Encoding.GetEncoding("macintosh"));
            header.DataSize     = BigEndianBitConverter.ToUInt32(buffer, 0x40);
            header.TagSize      = BigEndianBitConverter.ToUInt32(buffer, 0x44);
            header.DataChecksum = BigEndianBitConverter.ToUInt32(buffer, 0x48);
            header.TagChecksum  = BigEndianBitConverter.ToUInt32(buffer, 0x4C);
            header.Format       = buffer[0x50];
            header.FmtByte      = buffer[0x51];
            header.Valid        = buffer[0x52];
            header.Reserved     = buffer[0x53];

            AaruConsole.DebugWriteLine("DC42 plugin", "header.diskName = \"{0}\"", header.DiskName);
            AaruConsole.DebugWriteLine("DC42 plugin", "header.dataSize = {0} bytes", header.DataSize);
            AaruConsole.DebugWriteLine("DC42 plugin", "header.tagSize = {0} bytes", header.TagSize);
            AaruConsole.DebugWriteLine("DC42 plugin", "header.dataChecksum = 0x{0:X8}", header.DataChecksum);
            AaruConsole.DebugWriteLine("DC42 plugin", "header.tagChecksum = 0x{0:X8}", header.TagChecksum);
            AaruConsole.DebugWriteLine("DC42 plugin", "header.format = 0x{0:X2}", header.Format);
            AaruConsole.DebugWriteLine("DC42 plugin", "header.fmtByte = 0x{0:X2}", header.FmtByte);
            AaruConsole.DebugWriteLine("DC42 plugin", "header.valid = {0}", header.Valid);
            AaruConsole.DebugWriteLine("DC42 plugin", "header.reserved = {0}", header.Reserved);

            if (header.Valid != 1 ||
                header.Reserved != 0)
            {
                return(false);
            }

            // Some versions seem to incorrectly create little endian fields
            if (header.DataSize + header.TagSize + 0x54 != imageFilter.GetDataForkLength() &&
                header.Format != kSigmaFormatTwiggy)
            {
                header.DataSize     = BitConverter.ToUInt32(buffer, 0x40);
                header.TagSize      = BitConverter.ToUInt32(buffer, 0x44);
                header.DataChecksum = BitConverter.ToUInt32(buffer, 0x48);
                header.TagChecksum  = BitConverter.ToUInt32(buffer, 0x4C);

                if (header.DataSize + header.TagSize + 0x54 != imageFilter.GetDataForkLength() &&
                    header.Format != kSigmaFormatTwiggy)
                {
                    return(false);
                }
            }

            if (header.Format != kSonyFormat400K &&
                header.Format != kSonyFormat800K &&
                header.Format != kSonyFormat720K &&
                header.Format != kSonyFormat1440K &&
                header.Format != kSonyFormat1680K &&
                header.Format != kSigmaFormatTwiggy &&
                header.Format != kNotStandardFormat)
            {
                AaruConsole.DebugWriteLine("DC42 plugin", "Unknown header.format = 0x{0:X2} value", header.Format);

                return(false);
            }

            if (header.FmtByte != kSonyFmtByte400K &&
                header.FmtByte != kSonyFmtByte800K &&
                header.FmtByte != kSonyFmtByte800KIncorrect &&
                header.FmtByte != kSonyFmtByteProDos &&
                header.FmtByte != kInvalidFmtByte &&
                header.FmtByte != kSigmaFmtByteTwiggy &&
                header.FmtByte != kFmtNotStandard &&
                header.FmtByte != kMacOSXFmtByte)
            {
                AaruConsole.DebugWriteLine("DC42 plugin", "Unknown tmp_header.fmtByte = 0x{0:X2} value",
                                           header.FmtByte);

                return(false);
            }

            if (header.FmtByte == kInvalidFmtByte)
            {
                AaruConsole.DebugWriteLine("DC42 plugin", "Image says it's unformatted");

                return(false);
            }

            dataOffset           = 0x54;
            tagOffset            = header.TagSize != 0 ? 0x54 + header.DataSize : 0;
            imageInfo.SectorSize = 512;
            bptag           = (uint)(header.TagSize != 0 ? 12 : 0);
            dc42ImageFilter = imageFilter;

            imageInfo.Sectors = header.DataSize / 512;

            if (header.TagSize != 0)
            {
                bptag = (uint)(header.TagSize / imageInfo.Sectors);
                AaruConsole.DebugWriteLine("DC42 plugin", "bptag = {0} bytes", bptag);

                if (bptag != 12 &&
                    bptag != 20 &&
                    bptag != 24)
                {
                    AaruConsole.DebugWriteLine("DC42 plugin", "Unknown tag size");

                    return(false);
                }

                imageInfo.ReadableSectorTags.Add(SectorTagType.AppleSectorTag);
            }

            imageInfo.ImageSize            = (imageInfo.Sectors * imageInfo.SectorSize) + (imageInfo.Sectors * bptag);
            imageInfo.CreationTime         = imageFilter.GetCreationTime();
            imageInfo.LastModificationTime = imageFilter.GetLastWriteTime();
            imageInfo.MediaTitle           = header.DiskName;

            switch (header.Format)
            {
            case kSonyFormat400K:
                imageInfo.MediaType = imageInfo.Sectors == 1600 ? MediaType.AppleSonyDS : MediaType.AppleSonySS;

                break;

            case kSonyFormat800K:
                imageInfo.MediaType = MediaType.AppleSonyDS;

                break;

            case kSonyFormat720K:
                imageInfo.MediaType = MediaType.DOS_35_DS_DD_9;

                break;

            case kSonyFormat1440K:
                imageInfo.MediaType = MediaType.DOS_35_HD;

                break;

            case kSonyFormat1680K:
                imageInfo.MediaType = MediaType.DMF;

                break;

            case kSigmaFormatTwiggy:
                imageInfo.MediaType = MediaType.AppleFileWare;

                break;

            case kNotStandardFormat:
                switch (imageInfo.Sectors)
                {
                case 9728:
                    imageInfo.MediaType = MediaType.AppleProfile;

                    break;

                case 19456:
                    imageInfo.MediaType = MediaType.AppleProfile;

                    break;

                case 38912:
                    imageInfo.MediaType = MediaType.AppleWidget;

                    break;

                case 39040:
                    imageInfo.MediaType = MediaType.AppleHD20;

                    break;

                default:
                    imageInfo.MediaType = MediaType.Unknown;

                    break;
                }

                break;

            default:
                imageInfo.MediaType = MediaType.Unknown;

                break;
            }

            if (imageInfo.MediaType == MediaType.AppleFileWare)
            {
                byte[] data = new byte[header.DataSize];
                byte[] tags = new byte[header.TagSize];

                twiggyCache     = new byte[header.DataSize];
                twiggyCacheTags = new byte[header.TagSize];
                twiggy          = true;

                Stream datastream = imageFilter.GetDataForkStream();
                datastream.Seek(dataOffset, SeekOrigin.Begin);
                datastream.Read(data, 0, (int)header.DataSize);

                Stream tagstream = imageFilter.GetDataForkStream();
                tagstream.Seek(tagOffset, SeekOrigin.Begin);
                tagstream.Read(tags, 0, (int)header.TagSize);

                ushort mfsMagic     = BigEndianBitConverter.ToUInt16(data, (data.Length / 2) + 0x400);
                ushort mfsAllBlocks = BigEndianBitConverter.ToUInt16(data, (data.Length / 2) + 0x412);

                // Detect a Macintosh Twiggy
                if (mfsMagic == 0xD2D7 &&
                    mfsAllBlocks == 422)
                {
                    AaruConsole.DebugWriteLine("DC42 plugin", "Macintosh Twiggy detected, reversing disk sides");
                    Array.Copy(data, header.DataSize / 2, twiggyCache, 0, header.DataSize / 2);
                    Array.Copy(tags, header.TagSize / 2, twiggyCacheTags, 0, header.TagSize / 2);
                    Array.Copy(data, 0, twiggyCache, header.DataSize / 2, header.DataSize / 2);
                    Array.Copy(tags, 0, twiggyCacheTags, header.TagSize / 2, header.TagSize / 2);
                }
                else
                {
                    AaruConsole.DebugWriteLine("DC42 plugin", "Lisa Twiggy detected, reversing second half of disk");
                    Array.Copy(data, 0, twiggyCache, 0, header.DataSize / 2);
                    Array.Copy(tags, 0, twiggyCacheTags, 0, header.TagSize / 2);

                    int copiedSectors = 0;
                    int sectorsToCopy = 0;

                    for (int i = 0; i < 46; i++)
                    {
                        if (i >= 0 &&
                            i <= 3)
                        {
                            sectorsToCopy = 22;
                        }

                        if (i >= 4 &&
                            i <= 10)
                        {
                            sectorsToCopy = 21;
                        }

                        if (i >= 11 &&
                            i <= 16)
                        {
                            sectorsToCopy = 20;
                        }

                        if (i >= 17 &&
                            i <= 22)
                        {
                            sectorsToCopy = 19;
                        }

                        if (i >= 23 &&
                            i <= 28)
                        {
                            sectorsToCopy = 18;
                        }

                        if (i >= 29 &&
                            i <= 34)
                        {
                            sectorsToCopy = 17;
                        }

                        if (i >= 35 &&
                            i <= 41)
                        {
                            sectorsToCopy = 16;
                        }

                        if (i >= 42 &&
                            i <= 45)
                        {
                            sectorsToCopy = 15;
                        }

                        Array.Copy(data, (header.DataSize / 2) + (copiedSectors * 512), twiggyCache,
                                   twiggyCache.Length - (copiedSectors * 512) - (sectorsToCopy * 512),
                                   sectorsToCopy * 512);

                        Array.Copy(tags, (header.TagSize / 2) + (copiedSectors * bptag), twiggyCacheTags,
                                   twiggyCacheTags.Length - (copiedSectors * bptag) - (sectorsToCopy * bptag),
                                   sectorsToCopy * bptag);

                        copiedSectors += sectorsToCopy;
                    }
                }
            }

            try
            {
                if (imageFilter.HasResourceFork())
                {
                    var rsrcFork = new ResourceFork(imageFilter.GetResourceForkStream());

                    if (rsrcFork.ContainsKey(0x76657273))
                    {
                        Resource versRsrc = rsrcFork.GetResource(0x76657273);

                        byte[] vers = versRsrc?.GetResource(versRsrc.GetIds()[0]);

                        if (vers != null)
                        {
                            var version = new Version(vers);

                            string release = null;
                            string dev     = null;
                            string pre     = null;

                            string major = $"{version.MajorVersion}";
                            string minor = $".{version.MinorVersion / 10}";

                            if (version.MinorVersion % 10 > 0)
                            {
                                release = $".{version.MinorVersion % 10}";
                            }

                            switch (version.DevStage)
                            {
                            case Version.DevelopmentStage.Alpha:
                                dev = "a";

                                break;

                            case Version.DevelopmentStage.Beta:
                                dev = "b";

                                break;

                            case Version.DevelopmentStage.PreAlpha:
                                dev = "d";

                                break;
                            }

                            if (dev == null &&
                                version.PreReleaseVersion > 0)
                            {
                                dev = "f";
                            }

                            if (dev != null)
                            {
                                pre = $"{version.PreReleaseVersion}";
                            }

                            imageInfo.ApplicationVersion = $"{major}{minor}{release}{dev}{pre}";
                            imageInfo.Application        = version.VersionString;
                            imageInfo.Comments           = version.VersionMessage;
                        }
                    }

                    if (rsrcFork.ContainsKey(0x64437079))
                    {
                        Resource dCpyRsrc = rsrcFork.GetResource(0x64437079);

                        if (dCpyRsrc != null)
                        {
                            string dCpy = StringHandlers.PascalToString(dCpyRsrc.GetResource(dCpyRsrc.GetIds()[0]),
                                                                        Encoding.GetEncoding("macintosh"));

                            var   dCpyEx    = new Regex(REGEX_DCPY);
                            Match dCpyMatch = dCpyEx.Match(dCpy);

                            if (dCpyMatch.Success)
                            {
                                imageInfo.Application        = dCpyMatch.Groups["application"].Value;
                                imageInfo.ApplicationVersion = dCpyMatch.Groups["version"].Value;
                            }
                        }
                    }
                }
            }
            catch (InvalidCastException) {}

            AaruConsole.DebugWriteLine("DC42 plugin", "Image application = {0} version {1}", imageInfo.Application,
                                       imageInfo.ApplicationVersion);

            imageInfo.XmlMediaType = XmlMediaType.BlockMedia;
            AaruConsole.VerboseWriteLine("DiskCopy 4.2 image contains a disk of type {0}", imageInfo.MediaType);

            switch (imageInfo.MediaType)
            {
            case MediaType.AppleSonySS:
                imageInfo.Cylinders       = 80;
                imageInfo.Heads           = 1;
                imageInfo.SectorsPerTrack = 10;

                break;

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

                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.DMF:
                imageInfo.Cylinders       = 80;
                imageInfo.Heads           = 2;
                imageInfo.SectorsPerTrack = 21;

                break;

            case MediaType.AppleProfile:
                switch (imageInfo.Sectors)
                {
                case 9728:
                    imageInfo.Cylinders = 152;

                    break;

                case 19456:
                    imageInfo.Cylinders = 304;

                    break;
                }

                imageInfo.Heads           = 4;
                imageInfo.SectorsPerTrack = 16;

                break;

            case MediaType.AppleWidget:
                imageInfo.Cylinders       = 608;
                imageInfo.Heads           = 2;
                imageInfo.SectorsPerTrack = 16;

                break;

            case MediaType.AppleHD20:
                imageInfo.Cylinders       = 610;
                imageInfo.Heads           = 2;
                imageInfo.SectorsPerTrack = 16;

                break;

            default:
                imageInfo.Cylinders       = (uint)(imageInfo.Sectors / 16 / 63);
                imageInfo.Heads           = 16;
                imageInfo.SectorsPerTrack = 63;

                break;
            }

            return(true);
        }