コード例 #1
0
        /// <summary>
        /// Attempts to parse incoming disk data
        /// </summary>
        /// <returns>
        /// TRUE:   disk parsed
        /// FALSE:  unable to parse disk
        /// </returns>
        public override bool ParseDisk(byte[] data)
        {
            // look for standard magic string
            string ident = Encoding.ASCII.GetString(data, 0, 4);

            if (!ident.StartsWith("UDI!") && !ident.StartsWith("udi!"))
            {
                // incorrect format
                return(false);
            }

            if (data[0x08] != 0)
            {
                // wrong version
                return(false);
            }

            if (ident == "udi!")
            {
                // cant handle compression yet
                return(false);
            }

            DiskHeader.DiskIdent      = ident;
            DiskHeader.NumberOfTracks = (byte)(data[0x09] + 1);
            DiskHeader.NumberOfSides  = (byte)(data[0x0A] + 1);

            DiskTracks = new Track[DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides];

            int fileSize = MediaConverter.GetInt32(data, 4);             // not including the final 4-byte checksum

            // ignore extended header
            var extHdrSize = MediaConverter.GetInt32(data, 0x0C);
            int pos        = 0x10 + extHdrSize;

            // process track information
            for (int t = 0; t < DiskHeader.NumberOfTracks; t++)
            {
                DiskTracks[t] = new UDIv1Track
                {
                    TrackNumber = (byte)t,
                    SideNumber  = 0,
                    TrackType   = data[pos++],
                    TLEN        = MediaConverter.GetWordValue(data, pos)
                };
                pos += 2;
                DiskTracks[t].TrackData = new byte[DiskTracks[t].TLEN + DiskTracks[t].CLEN];
                Array.Copy(data, pos, DiskTracks[t].TrackData, 0, DiskTracks[t].TLEN + DiskTracks[t].CLEN);
                pos += DiskTracks[t].TLEN + DiskTracks[t].CLEN;
            }

            return(true);
        }
コード例 #2
0
        /// <summary>
        /// Attempts to parse incoming disk data
        /// </summary>
        /// <param name="diskData"></param>
        /// <returns>
        /// TRUE:   disk parsed
        /// FALSE:  unable to parse disk
        /// </returns>
        public override bool ParseDisk(byte[] data)
        {
            // look for standard magic string
            string ident = Encoding.ASCII.GetString(data, 0, 16);

            if (!ident.ToUpper().Contains("EXTENDED CPC DSK"))
            {
                // incorrect format
                return(false);
            }

            // read the disk information block
            DiskHeader.DiskIdent         = ident;
            DiskHeader.DiskCreatorString = Encoding.ASCII.GetString(data, 0x22, 14);
            DiskHeader.NumberOfTracks    = data[0x30];
            DiskHeader.NumberOfSides     = data[0x31];
            DiskHeader.TrackSizes        = new int[DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides];
            DiskTracks = new Track[DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides];
            DiskData   = data;
            int pos = 0x34;

            if (DiskHeader.NumberOfSides > 1)
            {
                StringBuilder sbm = new StringBuilder();
                sbm.AppendLine();
                sbm.AppendLine();
                sbm.AppendLine("The detected disk image contains multiple sides.");
                sbm.AppendLine("This is NOT currently supported in ZXHawk.");
                sbm.AppendLine("Please find an alternate image/dump where each side has been saved as a separate *.dsk image (and use the mutli-disk bundler tool to load into Bizhawk).");
                throw new System.NotImplementedException(sbm.ToString());
            }

            if (DiskHeader.NumberOfTracks > 42)
            {
                StringBuilder sbm = new StringBuilder();
                sbm.AppendLine();
                sbm.AppendLine();
                sbm.AppendLine("The detected disk is an " + DiskHeader.NumberOfTracks + " track disk image.");
                sbm.AppendLine("This is currently incompatible with the emulated +3 disk drive (42 tracks).");
                sbm.AppendLine("Likely the disk image is an 80 track betadisk or opus image, the drives and controllers for which are not currently emulated in ZXHawk");
                throw new System.NotImplementedException(sbm.ToString());
            }

            for (int i = 0; i < DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides; i++)
            {
                DiskHeader.TrackSizes[i] = data[pos++] * 256;
            }

            // move to first track information block
            pos = 0x100;

            // parse each track
            for (int i = 0; i < DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides; i++)
            {
                // check for unformatted track
                if (DiskHeader.TrackSizes[i] == 0)
                {
                    DiskTracks[i]         = new Track();
                    DiskTracks[i].Sectors = new Sector[0];
                    continue;
                }

                int p = pos;
                DiskTracks[i] = new Track();

                // track info block
                DiskTracks[i].TrackIdent = Encoding.ASCII.GetString(data, p, 12);
                p += 16;
                DiskTracks[i].TrackNumber     = data[p++];
                DiskTracks[i].SideNumber      = data[p++];
                DiskTracks[i].DataRate        = data[p++];
                DiskTracks[i].RecordingMode   = data[p++];
                DiskTracks[i].SectorSize      = data[p++];
                DiskTracks[i].NumberOfSectors = data[p++];
                DiskTracks[i].GAP3Length      = data[p++];
                DiskTracks[i].FillerByte      = data[p++];

                int dpos = pos + 0x100;

                // sector info list
                DiskTracks[i].Sectors = new Sector[DiskTracks[i].NumberOfSectors];
                for (int s = 0; s < DiskTracks[i].NumberOfSectors; s++)
                {
                    DiskTracks[i].Sectors[s] = new Sector();

                    DiskTracks[i].Sectors[s].TrackNumber          = data[p++];
                    DiskTracks[i].Sectors[s].SideNumber           = data[p++];
                    DiskTracks[i].Sectors[s].SectorID             = data[p++];
                    DiskTracks[i].Sectors[s].SectorSize           = data[p++];
                    DiskTracks[i].Sectors[s].Status1              = data[p++];
                    DiskTracks[i].Sectors[s].Status2              = data[p++];
                    DiskTracks[i].Sectors[s].ActualDataByteLength = MediaConverter.GetWordValue(data, p);
                    p += 2;

                    // sector data - begins at 0x100 offset from the start of the track info block (in this case dpos)
                    DiskTracks[i].Sectors[s].SectorData = new byte[DiskTracks[i].Sectors[s].ActualDataByteLength];

                    // copy the data
                    for (int b = 0; b < DiskTracks[i].Sectors[s].ActualDataByteLength; b++)
                    {
                        DiskTracks[i].Sectors[s].SectorData[b] = data[dpos + b];
                    }

                    // check for multiple weak/random sectors stored
                    if (DiskTracks[i].Sectors[s].SectorSize <= 7)
                    {
                        // sectorsize n=8 is equivilent to n=0 - FDC will use DTL for length
                        int specifiedSize = 0x80 << DiskTracks[i].Sectors[s].SectorSize;

                        if (specifiedSize < DiskTracks[i].Sectors[s].ActualDataByteLength)
                        {
                            // more data stored than sectorsize defines
                            // check for multiple weak/random copies
                            if (DiskTracks[i].Sectors[s].ActualDataByteLength % specifiedSize != 0)
                            {
                                DiskTracks[i].Sectors[s].ContainsMultipleWeakSectors = true;
                            }
                        }
                    }

                    // move dpos to the next sector data postion
                    dpos += DiskTracks[i].Sectors[s].ActualDataByteLength;
                }

                // move to the next track info block
                pos += DiskHeader.TrackSizes[i];
            }

            // run protection scheme detector
            ParseProtection();

            return(true);
        }
コード例 #3
0
ファイル: SZX.Methods.cs プロジェクト: Asnivor/BizHawk
        /// <summary>
        /// Exports state information to a byte array in ZX-State format
        /// </summary>
        /// <param name="machine"></param>
        /// <returns></returns>
        public static byte[] ExportSZX(SpectrumBase machine)
        {
            var s = new SZX(machine);

            byte[] result = null;

            using (MemoryStream ms = new MemoryStream())
            {
                using (BinaryWriter r = new BinaryWriter(ms))
                {
                    // temp buffer
                    byte[] buff;
                    // working block
                    ZXSTBLOCK block = new ZXSTBLOCK();

                    // header
                    ZXSTHEADER header = new ZXSTHEADER();
                    header.dwMagic        = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("ZXST"), 0);
                    header.chMajorVersion = 1;
                    header.chMinorVersion = 4;
                    header.chFlags        = 0;
                    switch (s._machine.Spectrum.MachineType)
                    {
                    case MachineType.ZXSpectrum16: header.chMachineId = (int)MachineIdentifier.ZXSTMID_16K; break;

                    case MachineType.ZXSpectrum48: header.chMachineId = (int)MachineIdentifier.ZXSTMID_48K; break;

                    case MachineType.ZXSpectrum128: header.chMachineId = (int)MachineIdentifier.ZXSTMID_128K; break;

                    case MachineType.ZXSpectrum128Plus2: header.chMachineId = (int)MachineIdentifier.ZXSTMID_PLUS2; break;

                    case MachineType.ZXSpectrum128Plus2a: header.chMachineId = (int)MachineIdentifier.ZXSTMID_PLUS2A; break;

                    case MachineType.ZXSpectrum128Plus3: header.chMachineId = (int)MachineIdentifier.ZXSTMID_PLUS3; break;
                    }
                    buff = MediaConverter.SerializeRaw(header);
                    r.Write(buff);

                    // ZXSTCREATOR
                    var bStruct = s.GetZXSTCREATOR();
                    block.dwId   = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("CRTR"), 0);
                    block.dwSize = (uint)Marshal.SizeOf(bStruct);
                    buff         = MediaConverter.SerializeRaw(block);
                    r.Write(buff);
                    buff = MediaConverter.SerializeRaw(bStruct);
                    r.Write(buff);

                    // ZXSTZ80REGS
                    var cStruct = s.GetZXSTZ80REGS();
                    block.dwId   = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("Z80R"), 0);
                    block.dwSize = (uint)Marshal.SizeOf(cStruct);
                    buff         = MediaConverter.SerializeRaw(block);
                    r.Write(buff);
                    buff = MediaConverter.SerializeRaw(cStruct);
                    r.Write(buff);

                    // ZXSTSPECREGS
                    var dStruct = s.GetZXSTSPECREGS();
                    block.dwId   = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("SPCR"), 0);
                    block.dwSize = (uint)Marshal.SizeOf(dStruct);
                    buff         = MediaConverter.SerializeRaw(block);
                    r.Write(buff);
                    buff = MediaConverter.SerializeRaw(dStruct);
                    r.Write(buff);

                    // ZXSTKEYBOARD
                    var eStruct = s.GetZXSTKEYBOARD();
                    block.dwId   = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("KEYB"), 0);
                    block.dwSize = (uint)Marshal.SizeOf(eStruct);
                    buff         = MediaConverter.SerializeRaw(block);
                    r.Write(buff);
                    buff = MediaConverter.SerializeRaw(eStruct);
                    r.Write(buff);

                    // ZXSTJOYSTICK
                    var fStruct = s.GetZXSTJOYSTICK();
                    block.dwId   = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("JOY\0"), 0);
                    block.dwSize = (uint)Marshal.SizeOf(fStruct);
                    buff         = MediaConverter.SerializeRaw(block);
                    r.Write(buff);
                    buff = MediaConverter.SerializeRaw(fStruct);
                    r.Write(buff);


                    // ZXSTAYBLOCK
                    if (s._machine.Spectrum.MachineType != MachineType.ZXSpectrum16 && s._machine.Spectrum.MachineType != MachineType.ZXSpectrum48)
                    {
                        var gStruct = s.GetZXSTAYBLOCK();
                        block.dwId   = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("AY\0\0"), 0);
                        block.dwSize = (uint)Marshal.SizeOf(gStruct);
                        buff         = MediaConverter.SerializeRaw(block);
                        r.Write(buff);
                        buff = MediaConverter.SerializeRaw(gStruct);
                        r.Write(buff);
                    }

                    // ZXSTRAMPAGE
                    switch (s._machine.Spectrum.MachineType)
                    {
                    // For 16k Spectrums, only page 5 (0x4000 - 0x7fff) is saved.
                    case MachineType.ZXSpectrum16:
                        block.dwId = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("RAMP"), 0);
                        var rp16 = s.GetZXSTRAMPAGE(5, s._machine.RAM0);
                        block.dwSize = (uint)Marshal.SizeOf(rp16);
                        buff         = MediaConverter.SerializeRaw(block);
                        r.Write(buff);
                        buff = MediaConverter.SerializeRaw(rp16);
                        r.Write(buff);
                        break;

                    // For 48k Spectrums and Timex TS/TC models, pages 5, 2 (0x8000 - 0xbfff) and 0 (0xc000 - 0xffff) are saved.
                    case MachineType.ZXSpectrum48:
                        block.dwId = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("RAMP"), 0);
                        var rp48_0 = s.GetZXSTRAMPAGE(5, s._machine.RAM0);
                        block.dwSize = (uint)Marshal.SizeOf(rp48_0);
                        buff         = MediaConverter.SerializeRaw(block);
                        r.Write(buff);
                        buff = MediaConverter.SerializeRaw(rp48_0);
                        r.Write(buff);

                        block.dwId = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("RAMP"), 0);
                        var rp48_1 = s.GetZXSTRAMPAGE(5, s._machine.RAM1);
                        block.dwSize = (uint)Marshal.SizeOf(rp48_1);
                        buff         = MediaConverter.SerializeRaw(block);
                        r.Write(buff);
                        buff = MediaConverter.SerializeRaw(rp48_1);
                        r.Write(buff);

                        block.dwId = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("RAMP"), 0);
                        var rp48_2 = s.GetZXSTRAMPAGE(5, s._machine.RAM2);
                        block.dwSize = (uint)Marshal.SizeOf(rp48_2);
                        buff         = MediaConverter.SerializeRaw(block);
                        r.Write(buff);
                        buff = MediaConverter.SerializeRaw(rp48_2);
                        r.Write(buff);
                        break;

                    // For 128k Spectrums and the Pentagon 128, all pages (0-7) are saved.
                    case MachineType.ZXSpectrum128:
                    case MachineType.ZXSpectrum128Plus2:
                    case MachineType.ZXSpectrum128Plus2a:
                    case MachineType.ZXSpectrum128Plus3:
                        List <byte[]> rams = new List <byte[]>
                        {
                            s._machine.RAM0, s._machine.RAM1, s._machine.RAM2, s._machine.RAM3,
                            s._machine.RAM4, s._machine.RAM5, s._machine.RAM6, s._machine.RAM7
                        };
                        for (byte i = 0; i < 8; i++)
                        {
                            block.dwId = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("RAMP"), 0);
                            var rp = s.GetZXSTRAMPAGE(i, rams[i]);
                            block.dwSize = (uint)Marshal.SizeOf(rp);
                            buff         = MediaConverter.SerializeRaw(block);
                            r.Write(buff);
                            buff = MediaConverter.SerializeRaw(rp);
                            r.Write(buff);
                        }
                        break;
                    }

                    /*
                     * // ZXSTPLUS3
                     * if (s._machine.Spectrum.MachineType == MachineType.ZXSpectrum128Plus3)
                     * {
                     *  var iStruct = s.GetZXSTPLUS3();
                     *  block.dwId = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("+3\0\0"), 0);
                     *  block.dwSize = (uint)Marshal.SizeOf(iStruct);
                     *  buff = MediaConverter.SerializeRaw(block);
                     *  r.Write(buff);
                     *  buff = MediaConverter.SerializeRaw(iStruct);
                     *  r.Write(buff);
                     *
                     *  // ZXSTDSKFILE
                     *  if (s._machine.diskImages.Count() > 0)
                     *  {
                     *      var jStruct = s.GetZXSTDSKFILE();
                     *      block.dwId = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("DSK\0"), 0);
                     *      block.dwSize = (uint)Marshal.SizeOf(jStruct);
                     *      buff = MediaConverter.SerializeRaw(block);
                     *      r.Write(buff);
                     *      buff = MediaConverter.SerializeRaw(jStruct);
                     *      r.Write(buff);
                     *  }
                     * }
                     *
                     * // ZXSTTAPE
                     * if (s._machine.tapeImages.Count() > 0)
                     * {
                     *  var hStruct = s.GetZXSTTAPE();
                     *  var tapeData = s._machine.tapeImages[s._machine.TapeMediaIndex];
                     *  block.dwId = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("TAPE"), 0);
                     *  block.dwSize = (uint)Marshal.SizeOf(hStruct) + (uint)tapeData.Length;
                     *  buff = MediaConverter.SerializeRaw(block);
                     *  r.Write(buff);
                     *  buff = MediaConverter.SerializeRaw(hStruct);
                     *  r.Write(buff);
                     *  buff = MediaConverter.SerializeRaw(tapeData);
                     *  r.Write(buff);
                     *  char[] terminator = "\0".ToCharArray();
                     *  r.Write(terminator);
                     * }
                     */
                }

                result = ms.ToArray();
            }

            return(result);
        }
コード例 #4
0
ファイル: IPFFloppyDisk.cs プロジェクト: KuSunda/BizHawk
            public static IPFBlock ParseNextBlock(ref int startPos, FloppyDisk disk, byte[] data, List <IPFBlock> blockCollection)
            {
                IPFBlock ipf = new IPFBlock();

                ipf.StartPos = startPos;

                if (startPos >= data.Length)
                {
                    // EOF
                    return(null);
                }

                // assume the startPos passed in is actually the start of a new block
                // look for record header ident
                string ident = Encoding.ASCII.GetString(data, startPos, 4);

                startPos += 4;
                try
                {
                    ipf.RecordType = (RecordHeaderType)Enum.Parse(typeof(RecordHeaderType), ident);
                }
                catch
                {
                    ipf.RecordType = RecordHeaderType.None;
                }

                // setup for actual block size
                ipf.BlockLength  = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                ipf.CRC          = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                ipf.RawBlockData = new byte[ipf.BlockLength];
                Array.Copy(data, ipf.StartPos, ipf.RawBlockData, 0, ipf.BlockLength);

                switch (ipf.RecordType)
                {
                // Nothing to process / unknown
                // just move ahead
                case RecordHeaderType.CAPS:
                case RecordHeaderType.TRCK:
                case RecordHeaderType.DUMP:
                case RecordHeaderType.CTEI:
                case RecordHeaderType.CTEX:
                default:
                    startPos = ipf.StartPos + ipf.BlockLength;
                    break;

                // INFO block
                case RecordHeaderType.INFO:
                    // INFO header is followed immediately by an INFO block
                    ipf.INFOmediaType    = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.INFOencoderType  = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.INFOencoderRev   = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.INFOfileKey      = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.INFOfileRev      = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.INFOorigin       = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.INFOminTrack     = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.INFOmaxTrack     = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.INFOminSide      = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.INFOmaxSide      = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.INFOcreationDate = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.INFOcreationTime = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.INFOplatform1    = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.INFOplatform2    = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.INFOplatform3    = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.INFOplatform4    = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.INFOdiskNumber   = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.INFOcreatorId    = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    startPos            += 12;                  // reserved
                    break;

                case RecordHeaderType.IMGE:
                    ipf.IMGEtrack          = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.IMGEside           = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.IMGEdensity        = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.IMGEsignalType     = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.IMGEtrackBytes     = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.IMGEstartBytePos   = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.IMGEstartBitPos    = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.IMGEdataBits       = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.IMGEgapBits        = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.IMGEtrackBits      = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.IMGEblockCount     = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.IMGEencoderProcess = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.IMGEtrackFlags     = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.IMGEdataKey        = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    startPos += 12;                             // reserved
                    break;

                case RecordHeaderType.DATA:
                    ipf.DATAlength = MediaConverter.GetBEInt32(data, startPos);
                    if (ipf.DATAlength == 0)
                    {
                        ipf.DATAextraDataRaw = new byte[0];
                        ipf.DATAlength       = 0;
                    }
                    else
                    {
                        ipf.DATAextraDataRaw = new byte[ipf.DATAlength];
                    }
                    startPos       += 4;
                    ipf.DATAbitSize = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.DATAcrc     = MediaConverter.GetBEInt32(data, startPos); startPos += 4;
                    ipf.DATAdataKey = MediaConverter.GetBEInt32(data, startPos); startPos += 4;

                    if (ipf.DATAlength != 0)
                    {
                        Array.Copy(data, startPos, ipf.DATAextraDataRaw, 0, ipf.DATAlength);
                    }

                    startPos += ipf.DATAlength;
                    break;
                }

                return(ipf);
            }
コード例 #5
0
ファイル: IPFFloppyDisk.cs プロジェクト: KuSunda/BizHawk
        /// <summary>
        /// Attempts to parse incoming disk data
        /// </summary>
        /// <returns>
        /// TRUE:   disk parsed
        /// FALSE:  unable to parse disk
        /// </returns>
        public override bool ParseDisk(byte[] data)
        {
            // look for standard magic string
            string ident = Encoding.ASCII.GetString(data, 0, 16);

            if (!ident.ToUpper().Contains("CAPS"))
            {
                // incorrect format
                return(false);
            }

            int pos = 0;

            List <IPFBlock> blocks = new List <IPFBlock>();

            while (pos < data.Length)
            {
                try
                {
                    var block = IPFBlock.ParseNextBlock(ref pos, this, data, blocks);

                    if (block == null)
                    {
                        // EOF
                        break;
                    }

                    if (block.RecordType == RecordHeaderType.None)
                    {
                        // unknown block
                    }

                    blocks.Add(block);
                }
                catch (Exception ex)
                {
                    var e = ex.ToString();
                }
            }

            // now process the blocks
            var infoBlock  = blocks.FirstOrDefault(a => a.RecordType == RecordHeaderType.INFO);
            var IMGEblocks = blocks.Where(a => a.RecordType == RecordHeaderType.IMGE).ToList();
            var DATAblocks = blocks.Where(a => a.RecordType == RecordHeaderType.DATA);

            DiskHeader.NumberOfTracks = (byte)(IMGEblocks.Count());
            DiskHeader.NumberOfSides  = (byte)(infoBlock.INFOmaxSide + 1);
            DiskTracks = new Track[DiskHeader.NumberOfTracks];

            for (int t = 0; t < DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides; t++)
            {
                // each imge block represents one track
                var img = IMGEblocks[t];
                DiskTracks[t] = new Track();
                var trk = DiskTracks[t];

                var blockCount = img.IMGEblockCount;
                var dataBlock  = DATAblocks.FirstOrDefault(a => a.DATAdataKey == img.IMGEdataKey);

                trk.SideNumber  = (byte)img.IMGEside;
                trk.TrackNumber = (byte)img.IMGEtrack;

                trk.Sectors = new Sector[blockCount];

                // process data block descriptors
                int p = 0;
                for (int d = 0; d < blockCount; d++)
                {
                    var extraDataAreaStart = 32 * blockCount;
                    trk.Sectors[d] = new Sector();
                    var sector = trk.Sectors[d];

                    int dataBits = MediaConverter.GetBEInt32(dataBlock.DATAextraDataRaw, p); p += 4;
                    int gapBits  = MediaConverter.GetBEInt32(dataBlock.DATAextraDataRaw, p); p += 4;
                    int dataBytes;
                    int gapBytes;
                    int gapOffset;
                    int cellType;
                    if (infoBlock.INFOencoderType == 1)
                    {
                        dataBytes = MediaConverter.GetBEInt32(dataBlock.DATAextraDataRaw, p); p += 4;
                        gapBytes  = MediaConverter.GetBEInt32(dataBlock.DATAextraDataRaw, p); p += 4;
                    }
                    else if (infoBlock.INFOencoderType == 2)
                    {
                        gapOffset = MediaConverter.GetBEInt32(dataBlock.DATAextraDataRaw, p); p += 4;
                        cellType  = MediaConverter.GetBEInt32(dataBlock.DATAextraDataRaw, p); p += 4;
                    }
                    int encoderType = MediaConverter.GetBEInt32(dataBlock.DATAextraDataRaw, p); p += 4;
                    int?blockFlags  = null;
                    if (infoBlock.INFOencoderType == 2)
                    {
                        blockFlags = MediaConverter.GetBEInt32(dataBlock.DATAextraDataRaw, p);
                    }
                    p += 4;

                    int gapDefault = MediaConverter.GetBEInt32(dataBlock.DATAextraDataRaw, p); p += 4;
                    int dataOffset = MediaConverter.GetBEInt32(dataBlock.DATAextraDataRaw, p); p += 4;

                    // gap stream elements
                    if (infoBlock.INFOencoderType == 2 && gapBits != 0 && blockFlags != null)
                    {
                        if (!blockFlags.Value.Bit(1) && !blockFlags.Value.Bit(0))
                        {
                            // no gap stream
                        }
                        if (!blockFlags.Value.Bit(1) && blockFlags.Value.Bit(0))
                        {
                            // Forward gap stream list only
                        }
                        if (blockFlags.Value.Bit(1) && !blockFlags.Value.Bit(0))
                        {
                            //  Backward gap stream list only
                        }
                        if (blockFlags.Value.Bit(1) && blockFlags.Value.Bit(0))
                        {
                            // Forward and Backward stream lists
                        }
                    }

                    // data stream elements
                    if (dataBits != 0)
                    {
                        var dsLocation = dataOffset;

                        for (; ;)
                        {
                            byte dataHead = dataBlock.DATAextraDataRaw[dsLocation++];
                            if (dataHead == 0)
                            {
                                // end of data stream list
                                break;
                            }

                            var    sampleSize = ((dataHead & 0xE0) >> 5);
                            var    dataType   = dataHead & 0x1F;
                            byte[] dSize      = new byte[sampleSize];
                            Array.Copy(dataBlock.DATAextraDataRaw, dsLocation, dSize, 0, sampleSize);
                            var dataSize = MediaConverter.GetBEInt32FromByteArray(dSize);
                            dsLocation += dSize.Length;
                            int    dataLen;
                            byte[] dataStream = new byte[0];

                            if (blockFlags != null && blockFlags.Value.Bit(2))
                            {
                                // bits
                                if (dataType != 5)
                                {
                                    dataLen = dataSize / 8;
                                    if (dataSize % 8 != 0)
                                    {
                                        // bits left over
                                    }
                                    dataStream = new byte[dataLen];
                                    Array.Copy(dataBlock.DATAextraDataRaw, dsLocation, dataStream, 0, dataLen);
                                }
                            }
                            else
                            {
                                // bytes
                                if (dataType != 5)
                                {
                                    dataStream = new byte[dataSize];
                                    Array.Copy(dataBlock.DATAextraDataRaw, dsLocation, dataStream, 0, dataSize);
                                }
                            }

                            // dataStream[] now contains the data
                            switch (dataType)
                            {
                            // SYNC
                            case 1:
                                break;

                            // DATA
                            case 2:
                                if (dataStream.Length == 7)
                                {
                                    // ID
                                    // first byte IAM
                                    sector.TrackNumber = dataStream[1];
                                    sector.SideNumber  = dataStream[2];
                                    sector.SectorID    = dataStream[3];
                                    sector.SectorSize  = dataStream[4];
                                }
                                else if (dataStream.Length > 255)
                                {
                                    // DATA
                                    // first byte DAM
                                    if (dataStream[0] == 0xF8)
                                    {
                                        // deleted address mark
                                        //sector.Status1
                                    }
                                    sector.SectorData = new byte[dataStream.Length - 1 - 2];
                                    Array.Copy(dataStream, 1, sector.SectorData, 0, dataStream.Length - 1 - 2);
                                }
                                break;

                            // GAP
                            case 3:
                                break;

                            // RAW
                            case 4:
                                break;

                            // FUZZY
                            case 5:
                                break;

                            default:
                                break;
                            }


                            dsLocation += dataStream.Length;
                        }
                    }
                }
            }

            return(true);
        }
コード例 #6
0
        /// <summary>
        /// Attempts to parse incoming disk data
        /// </summary>
        /// <param name="diskData"></param>
        /// <returns>
        /// TRUE:   disk parsed
        /// FALSE:  unable to parse disk
        /// </returns>
        public override bool ParseDisk(byte[] data)
        {
            // look for standard magic string
            string ident = Encoding.ASCII.GetString(data, 0, 16);

            if (!ident.ToUpper().Contains("MV - CPC"))
            {
                // incorrect format
                return(false);
            }

            // read the disk information block
            DiskHeader.DiskIdent         = ident;
            DiskHeader.DiskCreatorString = Encoding.ASCII.GetString(data, 0x22, 14);
            DiskHeader.NumberOfTracks    = data[0x30];
            DiskHeader.NumberOfSides     = data[0x31];
            DiskHeader.TrackSizes        = new int[DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides];
            DiskTracks = new Track[DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides];
            DiskData   = data;
            int pos = 0x32;

            if (DiskHeader.NumberOfSides > 1)
            {
                StringBuilder sbm = new StringBuilder();
                sbm.AppendLine();
                sbm.AppendLine();
                sbm.AppendLine("The detected disk image contains multiple sides.");
                sbm.AppendLine("This is NOT currently supported in ZXHawk.");
                sbm.AppendLine("Please find an alternate image/dump where each side has been saved as a separate *.dsk image (and use the mutli-disk bundler tool to load into Bizhawk).");
                throw new System.NotImplementedException(sbm.ToString());
            }

            // standard CPC format all track sizes are the same in the image
            for (int i = 0; i < DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides; i++)
            {
                DiskHeader.TrackSizes[i] = MediaConverter.GetWordValue(data, pos);
            }

            // move to first track information block
            pos = 0x100;

            // parse each track
            for (int i = 0; i < DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides; i++)
            {
                // check for unformatted track
                if (DiskHeader.TrackSizes[i] == 0)
                {
                    DiskTracks[i]         = new Track();
                    DiskTracks[i].Sectors = new Sector[0];
                    continue;
                }

                int p = pos;
                DiskTracks[i] = new Track();

                // track info block
                DiskTracks[i].TrackIdent = Encoding.ASCII.GetString(data, p, 12);
                p += 16;
                DiskTracks[i].TrackNumber = data[p++];
                DiskTracks[i].SideNumber  = data[p++];
                p += 2;
                DiskTracks[i].SectorSize      = data[p++];
                DiskTracks[i].NumberOfSectors = data[p++];
                DiskTracks[i].GAP3Length      = data[p++];
                DiskTracks[i].FillerByte      = data[p++];

                int dpos = pos + 0x100;

                // sector info list
                DiskTracks[i].Sectors = new Sector[DiskTracks[i].NumberOfSectors];
                for (int s = 0; s < DiskTracks[i].NumberOfSectors; s++)
                {
                    DiskTracks[i].Sectors[s] = new Sector();

                    DiskTracks[i].Sectors[s].TrackNumber          = data[p++];
                    DiskTracks[i].Sectors[s].SideNumber           = data[p++];
                    DiskTracks[i].Sectors[s].SectorID             = data[p++];
                    DiskTracks[i].Sectors[s].SectorSize           = data[p++];
                    DiskTracks[i].Sectors[s].Status1              = data[p++];
                    DiskTracks[i].Sectors[s].Status2              = data[p++];
                    DiskTracks[i].Sectors[s].ActualDataByteLength = MediaConverter.GetWordValue(data, p);
                    p += 2;

                    // actualdatabytelength value is calculated now
                    if (DiskTracks[i].Sectors[s].SectorSize == 0)
                    {
                        // no sectorsize specified - DTL will be used at runtime
                        DiskTracks[i].Sectors[s].ActualDataByteLength = DiskHeader.TrackSizes[i];
                    }
                    else if (DiskTracks[i].Sectors[s].SectorSize > 6)
                    {
                        // invalid - wrap around to 0
                        DiskTracks[i].Sectors[s].ActualDataByteLength = DiskHeader.TrackSizes[i];
                    }
                    else if (DiskTracks[i].Sectors[s].SectorSize == 6)
                    {
                        // only 0x1800 bytes are stored
                        DiskTracks[i].Sectors[s].ActualDataByteLength = 0x1800;
                    }
                    else
                    {
                        // valid sector size for this format
                        DiskTracks[i].Sectors[s].ActualDataByteLength = 0x80 << DiskTracks[i].Sectors[s].SectorSize;
                    }

                    // sector data - begins at 0x100 offset from the start of the track info block (in this case dpos)
                    DiskTracks[i].Sectors[s].SectorData = new byte[DiskTracks[i].Sectors[s].ActualDataByteLength];

                    // copy the data
                    for (int b = 0; b < DiskTracks[i].Sectors[s].ActualDataByteLength; b++)
                    {
                        DiskTracks[i].Sectors[s].SectorData[b] = data[dpos + b];
                    }

                    // move dpos to the next sector data postion
                    dpos += DiskTracks[i].Sectors[s].ActualDataByteLength;
                }

                // move to the next track info block
                pos += DiskHeader.TrackSizes[i];
            }

            // run protection scheme detector
            ParseProtection();

            return(true);
        }
コード例 #7
0
        /// <summary>
        /// Takes a double-sided disk byte array and converts into 2 single-sided arrays
        /// </summary>
        /// <param name="data"></param>
        /// <param name="results"></param>
        /// <returns></returns>
        public static bool SplitDoubleSided(byte[] data, List <byte[]> results)
        {
            // look for standard magic string
            string ident = Encoding.ASCII.GetString(data, 0, 4);

            if (!ident.StartsWith("UDI!") && !ident.StartsWith("udi!"))
            {
                // incorrect format
                return(false);
            }

            if (data[0x08] != 0)
            {
                // wrong version
                return(false);
            }

            if (ident == "udi!")
            {
                // cant handle compression yet
                return(false);
            }

            byte[] S0 = new byte[data.Length];
            byte[] S1 = new byte[data.Length];

            // header
            var extHdr = MediaConverter.GetInt32(data, 0x0C);

            Array.Copy(data, 0, S0, 0, 0x10 + extHdr);
            Array.Copy(data, 0, S1, 0, 0x10 + extHdr);
            // change side number
            S0[0x0A] = 0;
            S1[0x0A] = 0;

            int pos      = 0x10 + extHdr;
            int fileSize = MediaConverter.GetInt32(data, 4); // not including the final 4-byte checksum

            int s0Pos = pos;
            int s1Pos = pos;

            // process track information
            for (int t = 0; t < (data[0x09] + 1) * 2; t++)
            {
                var TLEN      = MediaConverter.GetWordValue(data, pos + 1);
                var CLEN      = TLEN / 8 + (TLEN % 8 / 7) / 8;
                var blockSize = TLEN + CLEN + 3;

                // 2 sided image: side 0 tracks will all have t as an even number
                try
                {
                    if (t == 0 || t % 2 == 0)
                    {
                        Array.Copy(data, pos, S0, s0Pos, blockSize);
                        s0Pos += blockSize;
                    }
                    else
                    {
                        Array.Copy(data, pos, S1, s1Pos, blockSize);
                        s1Pos += blockSize;
                    }
                }
                catch (Exception ex)
                {
                }


                pos += blockSize;
            }

            // skip checkum bytes for now

            byte[] s0final = new byte[s0Pos];
            byte[] s1final = new byte[s1Pos];
            Array.Copy(S0, 0, s0final, 0, s0Pos);
            Array.Copy(S1, 0, s1final, 0, s1Pos);

            results.Add(s0final);
            results.Add(s1final);

            return(true);
        }
コード例 #8
0
ファイル: CPCFloppyDisk.cs プロジェクト: sornerol/BizHawk
        /// <summary>
        /// Takes a double-sided disk byte array and converts into 2 single-sided arrays
        /// </summary>
        public static bool SplitDoubleSided(byte[] data, List <byte[]> results)
        {
            // look for standard magic string
            string ident = Encoding.ASCII.GetString(data, 0, 16);

            if (!ident.ToUpper().Contains("MV - CPC"))
            {
                // incorrect format
                return(false);
            }

            byte[] S0 = new byte[data.Length];
            byte[] S1 = new byte[data.Length];

            // disk info block
            Array.Copy(data, 0, S0, 0, 0x100);
            Array.Copy(data, 0, S1, 0, 0x100);
            // change side number
            S0[0x31] = 1;
            S1[0x31] = 1;

            var trkSize = MediaConverter.GetWordValue(data, 0x32);

            // start at track info blocks
            int mPos  = 0x100;
            int s0Pos = 0x100;
            int s1Pos = 0x100;

            var numTrks  = data[0x30];
            var numSides = data[0x31];

            while (mPos < trkSize * data[0x30] * data[0x31])
            {
                // which side is this?
                var side = data[mPos + 0x11];
                if (side == 0)
                {
                    // side 1
                    Array.Copy(data, mPos, S0, s0Pos, trkSize);
                    s0Pos += trkSize;
                }
                else if (side == 1)
                {
                    // side 2
                    Array.Copy(data, mPos, S1, s1Pos, trkSize);
                    s1Pos += trkSize;
                }
                else
                {
                }

                mPos += trkSize;
            }

            byte[] s0final = new byte[s0Pos];
            byte[] s1final = new byte[s1Pos];
            Array.Copy(S0, 0, s0final, 0, s0Pos);
            Array.Copy(S1, 0, s1final, 0, s1Pos);

            results.Add(s0final);
            results.Add(s1final);

            return(true);
        }
コード例 #9
0
        /// <summary>
        /// Attempts to parse incoming disk data
        /// </summary>
        /// <param name="diskData"></param>
        /// <returns>
        /// TRUE:   disk parsed
        /// FALSE:  unable to parse disk
        /// </returns>
        public override bool ParseDisk(byte[] data)
        {
            // look for standard magic string
            string ident = Encoding.ASCII.GetString(data, 0, 16);

            if (!ident.ToUpper().Contains("EXTENDED CPC DSK"))
            {
                // incorrect format
                return(false);
            }

            // read the disk information block
            DiskHeader.DiskIdent         = ident;
            DiskHeader.DiskCreatorString = Encoding.ASCII.GetString(data, 0x22, 14);
            DiskHeader.NumberOfTracks    = data[0x30];
            DiskHeader.NumberOfSides     = data[0x31];
            DiskHeader.TrackSizes        = new int[DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides];
            DiskTracks = new Track[DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides];
            DiskData   = data;
            int pos = 0x34;

            for (int i = 0; i < DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides; i++)
            {
                DiskHeader.TrackSizes[i] = data[pos++] * 256;
            }

            // move to first track information block
            pos = 0x100;

            // parse each track
            for (int i = 0; i < DiskHeader.NumberOfTracks * DiskHeader.NumberOfSides; i++)
            {
                // check for unformatted track
                if (DiskHeader.TrackSizes[i] == 0)
                {
                    DiskTracks[i]         = new Track();
                    DiskTracks[i].Sectors = new Sector[0];
                    continue;
                }

                int p = pos;
                DiskTracks[i] = new Track();

                // track info block
                DiskTracks[i].TrackIdent = Encoding.ASCII.GetString(data, p, 12);
                p += 16;
                DiskTracks[i].TrackNumber     = data[p++];
                DiskTracks[i].SideNumber      = data[p++];
                DiskTracks[i].DataRate        = data[p++];
                DiskTracks[i].RecordingMode   = data[p++];
                DiskTracks[i].SectorSize      = data[p++];
                DiskTracks[i].NumberOfSectors = data[p++];
                DiskTracks[i].GAP3Length      = data[p++];
                DiskTracks[i].FillerByte      = data[p++];

                int dpos = pos + 0x100;

                // sector info list
                DiskTracks[i].Sectors = new Sector[DiskTracks[i].NumberOfSectors];
                for (int s = 0; s < DiskTracks[i].NumberOfSectors; s++)
                {
                    DiskTracks[i].Sectors[s] = new Sector();

                    DiskTracks[i].Sectors[s].TrackNumber          = data[p++];
                    DiskTracks[i].Sectors[s].SideNumber           = data[p++];
                    DiskTracks[i].Sectors[s].SectorID             = data[p++];
                    DiskTracks[i].Sectors[s].SectorSize           = data[p++];
                    DiskTracks[i].Sectors[s].Status1              = data[p++];
                    DiskTracks[i].Sectors[s].Status2              = data[p++];
                    DiskTracks[i].Sectors[s].ActualDataByteLength = MediaConverter.GetWordValue(data, p);
                    p += 2;

                    // sector data - begins at 0x100 offset from the start of the track info block (in this case dpos)
                    DiskTracks[i].Sectors[s].SectorData = new byte[DiskTracks[i].Sectors[s].ActualDataByteLength];

                    // copy the data
                    for (int b = 0; b < DiskTracks[i].Sectors[s].ActualDataByteLength; b++)
                    {
                        DiskTracks[i].Sectors[s].SectorData[b] = data[dpos + b];
                    }

                    // check for multiple weak/random sectors stored
                    if (DiskTracks[i].Sectors[s].SectorSize <= 7)
                    {
                        // sectorsize n=8 is equivilent to n=0 - FDC will use DTL for length
                        int specifiedSize = 0x80 << DiskTracks[i].Sectors[s].SectorSize;

                        if (specifiedSize < DiskTracks[i].Sectors[s].ActualDataByteLength)
                        {
                            // more data stored than sectorsize defines
                            // check for multiple weak/random copies
                            if (DiskTracks[i].Sectors[s].ActualDataByteLength % specifiedSize != 0)
                            {
                                DiskTracks[i].Sectors[s].ContainsMultipleWeakSectors = true;
                            }
                        }
                    }

                    // move dpos to the next sector data postion
                    dpos += DiskTracks[i].Sectors[s].ActualDataByteLength;
                }

                // move to the next track info block
                pos += DiskHeader.TrackSizes[i];
            }

            // run protection scheme detector
            ParseProtection();

            return(true);
        }