Пример #1
0
        public bool Close()
        {
            if (!IsWriting)
            {
                ErrorMessage = "Image is not opened for writing";

                return(false);
            }

            byte sessions = byte.MinValue;

            foreach (CommonTypes.Structs.Track t in _writingTracks.Where(t => t.TrackSession > byte.MinValue))
            {
                sessions = (byte)t.TrackSession;
            }

            var header = new Header
            {
                signature = _alcoholSignature,
                version   = new byte[]
                {
                    1, 5
                },
                type             = MediaTypeToMediumType(_imageInfo.MediaType),
                sessions         = sessions,
                structuresOffset = (uint)(_pfi == null ? 0 : 96),
                sessionOffset    = (uint)(_pfi == null ? 96 : 4196),
                unknown1         = new ushort[2],
                unknown2         = new uint[2],
                unknown3         = new uint[6],
                unknown4         = new uint[3]
            };

            // Alcohol sets this always, Daemon Tool expects this
            header.unknown1[0] = 2;

            _alcSessions    = new Dictionary <int, Session>();
            _alcTracks      = new Dictionary <int, Track>();
            _alcToc         = new Dictionary <int, Dictionary <int, Track> >();
            _writingTracks  = _writingTracks.OrderBy(t => t.TrackSession).ThenBy(t => t.TrackSequence).ToList();
            _alcTrackExtras = new Dictionary <int, TrackExtra>();
            long currentTrackOffset = header.sessionOffset + (Marshal.SizeOf <Session>() * sessions);

            byte[] tmpToc = null;

            if (_fullToc != null)
            {
                byte[] fullTocSize = BigEndianBitConverter.GetBytes((short)_fullToc.Length);
                tmpToc = new byte[_fullToc.Length + 2];
                Array.Copy(_fullToc, 0, tmpToc, 2, _fullToc.Length);
                tmpToc[0] = fullTocSize[0];
                tmpToc[1] = fullTocSize[1];
            }

            FullTOC.CDFullTOC?decodedToc = FullTOC.Decode(tmpToc);

            long currentExtraOffset = currentTrackOffset;
            int  extraCount         = 0;

            for (int i = 1; i <= sessions; i++)
            {
                if (decodedToc.HasValue)
                {
                    extraCount += decodedToc.Value.TrackDescriptors.Count(t => t.SessionNumber == i);

                    currentExtraOffset += Marshal.SizeOf <Track>() *
                                          decodedToc.Value.TrackDescriptors.Count(t => t.SessionNumber == i);
                }
                else
                {
                    currentExtraOffset += Marshal.SizeOf <Track>() * 3;
                    extraCount         += 3;

                    currentExtraOffset += Marshal.SizeOf <Track>() * _writingTracks.Count(t => t.TrackSession == i);

                    extraCount += _writingTracks.Count(t => t.TrackSession == i);

                    if (i < sessions)
                    {
                        currentExtraOffset += Marshal.SizeOf <Track>() * 2;
                        extraCount         += 2;
                    }
                }
            }

            long footerOffset = currentExtraOffset + (Marshal.SizeOf <TrackExtra>() * extraCount);

            if (_bca != null)
            {
                header.bcaOffset = (uint)footerOffset;
                footerOffset    += _bca.Length;
            }

            if (_isDvd)
            {
                _alcSessions.Add(1, new Session
                {
                    sessionEnd      = (int)((_writingTracks[0].TrackEndSector - _writingTracks[0].TrackStartSector) + 1),
                    sessionSequence = 1,
                    allBlocks       = 1,
                    nonTrackBlocks  = 3,
                    firstTrack      = 1,
                    lastTrack       = 1,
                    trackOffset     = 4220
                });

                footerOffset = 4300;

                if (_bca != null)
                {
                    footerOffset += _bca.Length;
                }

                _alcTracks.Add(1, new Track
                {
                    mode         = TrackMode.DVD,
                    adrCtl       = 20,
                    point        = 1,
                    extraOffset  = (uint)((_writingTracks[0].TrackEndSector - _writingTracks[0].TrackStartSector) + 1),
                    sectorSize   = 2048,
                    files        = 1,
                    footerOffset = (uint)footerOffset,
                    unknown      = new byte[18],
                    unknown2     = new byte[24]
                });

                _alcToc.Add(1, _alcTracks);
            }
            else
            {
                for (int i = 1; i <= sessions; i++)
                {
                    CommonTypes.Structs.Track firstTrack = _writingTracks.First(t => t.TrackSession == i);
                    CommonTypes.Structs.Track lastTrack  = _writingTracks.Last(t => t.TrackSession == i);

                    _alcSessions.Add(i, new Session
                    {
                        sessionStart    = (int)firstTrack.TrackStartSector - 150,
                        sessionEnd      = (int)lastTrack.TrackEndSector + 1,
                        sessionSequence = (ushort)i,
                        allBlocks       = (byte)(decodedToc?.TrackDescriptors.Count(t => t.SessionNumber == i) ??
                                                 _writingTracks.Count(t => t.TrackSession == i) + 3),
                        nonTrackBlocks =
                            (byte)(decodedToc?.TrackDescriptors.Count(t => t.SessionNumber == i && t.POINT >= 0xA0 &&
                                                                      t.POINT <= 0xAF) ?? 3),
                        firstTrack  = (ushort)firstTrack.TrackSequence,
                        lastTrack   = (ushort)lastTrack.TrackSequence,
                        trackOffset = (uint)currentTrackOffset
                    });

                    Dictionary <int, Track> thisSessionTracks = new Dictionary <int, Track>();
                    _trackFlags.TryGetValue((byte)firstTrack.TrackSequence, out byte firstTrackControl);
                    _trackFlags.TryGetValue((byte)lastTrack.TrackSequence, out byte lastTrackControl);

                    if (firstTrackControl == 0 &&
                        firstTrack.TrackType != TrackType.Audio)
                    {
                        firstTrackControl = (byte)CdFlags.DataTrack;
                    }

                    if (lastTrackControl == 0 &&
                        lastTrack.TrackType != TrackType.Audio)
                    {
                        lastTrackControl = (byte)CdFlags.DataTrack;
                    }

                    (byte minute, byte second, byte frame)leadinPmsf = LbaToMsf(lastTrack.TrackEndSector + 1);

                    if (decodedToc?.TrackDescriptors.Any(t => t.SessionNumber == i && t.POINT >= 0xA0 &&
                                                         t.POINT <= 0xAF) == true)
                    {
                        foreach (FullTOC.TrackDataDescriptor tocTrk in
                                 decodedToc.Value.TrackDescriptors.Where(t => t.SessionNumber == i && t.POINT >= 0xA0 &&
                                                                         t.POINT <= 0xAF))
                        {
                            thisSessionTracks.Add(tocTrk.POINT, new Track
                            {
                                adrCtl      = (byte)((tocTrk.ADR << 4) + tocTrk.CONTROL),
                                tno         = tocTrk.TNO,
                                point       = tocTrk.POINT,
                                min         = tocTrk.Min,
                                sec         = tocTrk.Sec,
                                frame       = tocTrk.Frame,
                                zero        = tocTrk.Zero,
                                pmin        = tocTrk.PMIN,
                                psec        = tocTrk.PSEC,
                                pframe      = tocTrk.PFRAME,
                                mode        = TrackMode.NoData,
                                unknown     = new byte[18],
                                unknown2    = new byte[24],
                                extraOffset = (uint)currentExtraOffset
                            });

                            currentTrackOffset += Marshal.SizeOf <Track>();
                            currentExtraOffset += Marshal.SizeOf <TrackExtra>();
                        }
                    }
                    else
                    {
                        thisSessionTracks.Add(0xA0, new Track
                        {
                            adrCtl   = (byte)((1 << 4) + firstTrackControl),
                            pmin     = (byte)firstTrack.TrackSequence,
                            mode     = TrackMode.NoData,
                            point    = 0xA0,
                            unknown  = new byte[18],
                            unknown2 = new byte[24],
                            psec     = (byte)(_imageInfo.MediaType == MediaType.CDI
                                              ? 0x10
                                              : _writingTracks.Any(t => t.TrackType == TrackType.CdMode2Form1 ||
                                                                   t.TrackType == TrackType.CdMode2Form2 ||
                                                                   t.TrackType == TrackType.CdMode2Formless)
                                                  ? 0x20
                                                  : 0),
                            extraOffset = (uint)currentExtraOffset
                        });

                        thisSessionTracks.Add(0xA1, new Track
                        {
                            adrCtl      = (byte)((1 << 4) + lastTrackControl),
                            pmin        = (byte)lastTrack.TrackSequence,
                            mode        = TrackMode.NoData,
                            point       = 0xA1,
                            unknown     = new byte[18],
                            unknown2    = new byte[24],
                            extraOffset = (uint)currentExtraOffset
                        });

                        thisSessionTracks.Add(0xA2, new Track
                        {
                            adrCtl      = (byte)((1 << 4) + firstTrackControl),
                            zero        = 0,
                            pmin        = leadinPmsf.minute,
                            psec        = leadinPmsf.second,
                            pframe      = leadinPmsf.frame,
                            mode        = TrackMode.NoData,
                            point       = 0xA2,
                            unknown     = new byte[18],
                            unknown2    = new byte[24],
                            extraOffset = (uint)currentExtraOffset
                        });

                        currentExtraOffset += Marshal.SizeOf <TrackExtra>() * 3;
                        currentTrackOffset += Marshal.SizeOf <Track>() * 3;
                    }

                    foreach (CommonTypes.Structs.Track track in _writingTracks.Where(t => t.TrackSession == i).
                             OrderBy(t => t.TrackSequence))
                    {
                        var alcTrk = new Track();

                        if (decodedToc?.TrackDescriptors.Any(t => t.SessionNumber == i &&
                                                             t.POINT == track.TrackSequence) == true)
                        {
                            FullTOC.TrackDataDescriptor tocTrk =
                                decodedToc.Value.TrackDescriptors.First(t => t.SessionNumber == i &&
                                                                        t.POINT == track.TrackSequence);

                            alcTrk.adrCtl = (byte)((tocTrk.ADR << 4) + tocTrk.CONTROL);
                            alcTrk.tno    = tocTrk.TNO;
                            alcTrk.point  = tocTrk.POINT;
                            alcTrk.min    = tocTrk.Min;
                            alcTrk.sec    = tocTrk.Sec;
                            alcTrk.frame  = tocTrk.Frame;
                            alcTrk.zero   = tocTrk.Zero;
                            alcTrk.pmin   = tocTrk.PMIN;
                            alcTrk.psec   = tocTrk.PSEC;
                            alcTrk.pframe = tocTrk.PFRAME;
                        }
                        else
                        {
                            (byte minute, byte second, byte frame)msf = LbaToMsf(track.TrackStartSector);
                            _trackFlags.TryGetValue((byte)track.TrackSequence, out byte trackControl);

                            if (trackControl == 0 &&
                                track.TrackType != TrackType.Audio)
                            {
                                trackControl = (byte)CdFlags.DataTrack;
                            }

                            alcTrk.adrCtl = (byte)((1 << 4) + trackControl);
                            alcTrk.point  = (byte)track.TrackSequence;
                            alcTrk.zero   = 0;
                            alcTrk.pmin   = msf.minute;
                            alcTrk.psec   = msf.second;
                            alcTrk.pframe = msf.frame;
                        }

                        alcTrk.mode = TrackTypeToTrackMode(track.TrackType);

                        alcTrk.subMode = track.TrackSubchannelType != TrackSubchannelType.None
                                             ? SubchannelMode.Interleaved : SubchannelMode.None;

                        alcTrk.sectorSize = (ushort)(track.TrackRawBytesPerSector +
                                                     (track.TrackSubchannelType != TrackSubchannelType.None ? 96 : 0));

                        alcTrk.startLba     = (uint)(track.TrackStartSector + track.TrackPregap);
                        alcTrk.startOffset  = track.TrackFileOffset + (alcTrk.sectorSize * track.TrackPregap);
                        alcTrk.files        = 1;
                        alcTrk.extraOffset  = (uint)currentExtraOffset;
                        alcTrk.footerOffset = (uint)footerOffset;

                        if (track.TrackSequence == firstTrack.TrackSequence &&
                            track.TrackSequence > 1)
                        {
                            alcTrk.startLba    -= 150;
                            alcTrk.startOffset -= (ulong)(alcTrk.sectorSize * 150);
                        }

                        // Alcohol seems to set that for all CD tracks
                        // Daemon Tools expect it to be like this
                        alcTrk.unknown = new byte[]
                        {
                            0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                            0x00, 0x00, 0x00
                        };

                        alcTrk.unknown2 = new byte[24];

                        thisSessionTracks.Add((int)track.TrackSequence, alcTrk);

                        currentTrackOffset += Marshal.SizeOf <Track>();
                        currentExtraOffset += Marshal.SizeOf <TrackExtra>();

                        var trkExtra = new TrackExtra
                        {
                            sectors = (uint)((track.TrackEndSector - track.TrackStartSector) + 1)
                        };

                        if (track.TrackSequence == firstTrack.TrackSequence)
                        {
                            trkExtra.pregap = 150;
                        }

                        // When track mode changes there's a mandatory gap, Alcohol needs it
                        else if (thisSessionTracks.TryGetValue((int)(track.TrackSequence - 1),
                                                               out Track previousTrack) &&
                                 _alcTrackExtras.TryGetValue((int)(track.TrackSequence - 1),
                                                             out TrackExtra previousExtra) &&
                                 previousTrack.mode != alcTrk.mode)
                        {
                            previousExtra.sectors -= 150;
                            trkExtra.pregap        = 150;
                            _alcTrackExtras.Remove((int)(track.TrackSequence - 1));
                            _alcTrackExtras.Add((int)(track.TrackSequence - 1), previousExtra);
                        }
                        else
                        {
                            trkExtra.pregap = 0;
                        }

                        _alcTrackExtras.Add((int)track.TrackSequence, trkExtra);
                    }

                    if (decodedToc?.TrackDescriptors.Any(t => t.SessionNumber == i && t.POINT >= 0xB0) == true)
                    {
                        foreach (FullTOC.TrackDataDescriptor tocTrk in
                                 decodedToc.Value.TrackDescriptors.Where(t => t.SessionNumber == i && t.POINT >= 0xB0))
                        {
                            thisSessionTracks.Add(tocTrk.POINT, new Track
                            {
                                adrCtl      = (byte)((tocTrk.ADR << 4) + tocTrk.CONTROL),
                                tno         = tocTrk.TNO,
                                point       = tocTrk.POINT,
                                min         = tocTrk.Min,
                                sec         = tocTrk.Sec,
                                frame       = tocTrk.Frame,
                                zero        = tocTrk.Zero,
                                pmin        = tocTrk.PMIN,
                                psec        = tocTrk.PSEC,
                                pframe      = tocTrk.PFRAME,
                                mode        = TrackMode.NoData,
                                unknown     = new byte[18],
                                unknown2    = new byte[24],
                                extraOffset = (uint)currentExtraOffset
                            });

                            currentExtraOffset += Marshal.SizeOf <TrackExtra>();
                            currentTrackOffset += Marshal.SizeOf <Track>();
                        }
                    }
                    else if (i < sessions)
                    {
                        (byte minute, byte second, byte frame)leadoutAmsf =
                            LbaToMsf(_writingTracks.First(t => t.TrackSession == i + 1).TrackStartSector - 150);

                        (byte minute, byte second, byte frame)leadoutPmsf =
                            LbaToMsf(_writingTracks.OrderBy(t => t.TrackSession).ThenBy(t => t.TrackSequence).Last().
                                     TrackStartSector);

                        thisSessionTracks.Add(0xB0, new Track
                        {
                            point    = 0xB0,
                            adrCtl   = 0x50,
                            zero     = 0,
                            min      = leadoutAmsf.minute,
                            sec      = leadoutAmsf.second,
                            frame    = leadoutAmsf.frame,
                            pmin     = leadoutPmsf.minute,
                            psec     = leadoutPmsf.second,
                            pframe   = leadoutPmsf.frame,
                            unknown  = new byte[18],
                            unknown2 = new byte[24]
                        });

                        thisSessionTracks.Add(0xC0, new Track
                        {
                            point    = 0xC0,
                            adrCtl   = 0x50,
                            min      = 128,
                            pmin     = 97,
                            psec     = 25,
                            unknown  = new byte[18],
                            unknown2 = new byte[24]
                        });

                        currentTrackOffset += Marshal.SizeOf <Track>() * 2;
                    }

                    _alcToc.Add(i, thisSessionTracks);
                }
            }

            _alcFooter = new Footer
            {
                filenameOffset = (uint)(footerOffset + Marshal.SizeOf <Footer>()),
                widechar       = 1
            };

            byte[] filename = Encoding.Unicode.GetBytes("*.mdf"); // Yup, Alcohol stores no filename but a wildcard.

            // Write header
            _descriptorStream.Seek(0, SeekOrigin.Begin);
            byte[] block    = new byte[Marshal.SizeOf <Header>()];
            IntPtr blockPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(Marshal.SizeOf <Header>());

            System.Runtime.InteropServices.Marshal.StructureToPtr(header, blockPtr, true);
            System.Runtime.InteropServices.Marshal.Copy(blockPtr, block, 0, block.Length);
            System.Runtime.InteropServices.Marshal.FreeHGlobal(blockPtr);
            _descriptorStream.Write(block, 0, block.Length);

            // Write DVD structures if present
            if (header.structuresOffset != 0)
            {
                if (_dmi != null)
                {
                    _descriptorStream.Seek(header.structuresOffset, SeekOrigin.Begin);

                    switch (_dmi.Length)
                    {
                    case 2052:
                        _descriptorStream.Write(_dmi, 0, 2052);

                        break;

                    case 2048:
                        _descriptorStream.Write(new byte[]
                        {
                            0x08, 0x02, 0x00, 0x00
                        }, 0, 4);

                        _descriptorStream.Write(_dmi, 0, 2048);

                        break;
                    }
                }

                // TODO: Create fake PFI if none present
                if (_pfi != null)
                {
                    _descriptorStream.Seek(header.structuresOffset + 2052, SeekOrigin.Begin);
                    _descriptorStream.Write(_pfi, _pfi.Length - 2048, 2048);
                }
            }

            // Write sessions
            _descriptorStream.Seek(header.sessionOffset, SeekOrigin.Begin);

            foreach (Session session in _alcSessions.Values)
            {
                block    = new byte[Marshal.SizeOf <Session>()];
                blockPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(Marshal.SizeOf <Session>());
                System.Runtime.InteropServices.Marshal.StructureToPtr(session, blockPtr, true);
                System.Runtime.InteropServices.Marshal.Copy(blockPtr, block, 0, block.Length);
                System.Runtime.InteropServices.Marshal.FreeHGlobal(blockPtr);
                _descriptorStream.Write(block, 0, block.Length);
            }

            // Write tracks
            foreach (KeyValuePair <int, Dictionary <int, Track> > kvp in _alcToc)
            {
                _descriptorStream.Seek(_alcSessions.First(t => t.Key == kvp.Key).Value.trackOffset, SeekOrigin.Begin);

                foreach (Track track in kvp.Value.Values)
                {
                    Track alcoholTrack = track;

                    // Write extra
                    if (!_isDvd)
                    {
                        long position = _descriptorStream.Position;
                        _descriptorStream.Seek(alcoholTrack.extraOffset, SeekOrigin.Begin);

                        block = new byte[Marshal.SizeOf <TrackExtra>()];

                        if (_alcTrackExtras.TryGetValue(alcoholTrack.point, out TrackExtra extra))
                        {
                            blockPtr = System.Runtime.InteropServices.Marshal.
                                       AllocHGlobal(Marshal.SizeOf <TrackExtra>());

                            System.Runtime.InteropServices.Marshal.StructureToPtr(extra, blockPtr, true);
                            System.Runtime.InteropServices.Marshal.Copy(blockPtr, block, 0, block.Length);
                            System.Runtime.InteropServices.Marshal.FreeHGlobal(blockPtr);
                        }
                        else
                        {
                            alcoholTrack.extraOffset = 0;
                        }

                        _descriptorStream.Write(block, 0, block.Length);

                        _descriptorStream.Seek(position, SeekOrigin.Begin);
                    }

                    block    = new byte[Marshal.SizeOf <Track>()];
                    blockPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(Marshal.SizeOf <Track>());
                    System.Runtime.InteropServices.Marshal.StructureToPtr(alcoholTrack, blockPtr, true);
                    System.Runtime.InteropServices.Marshal.Copy(blockPtr, block, 0, block.Length);
                    System.Runtime.InteropServices.Marshal.FreeHGlobal(blockPtr);
                    _descriptorStream.Write(block, 0, block.Length);
                }
            }

            // Write BCA
            if (_bca != null)
            {
                _descriptorStream.Seek(header.bcaOffset, SeekOrigin.Begin);
                _descriptorStream.Write(_bca, 0, _bca.Length);
            }

            // Write footer
            _descriptorStream.Seek(footerOffset, SeekOrigin.Begin);
            block    = new byte[Marshal.SizeOf <Footer>()];
            blockPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(Marshal.SizeOf <Footer>());
            System.Runtime.InteropServices.Marshal.StructureToPtr(_alcFooter, blockPtr, true);
            System.Runtime.InteropServices.Marshal.Copy(blockPtr, block, 0, block.Length);
            System.Runtime.InteropServices.Marshal.FreeHGlobal(blockPtr);
            _descriptorStream.Write(block, 0, block.Length);

            // Write filename
            _descriptorStream.Write(filename, 0, filename.Length);

            // Write filename null termination
            _descriptorStream.Write(new byte[]
            {
                0, 0
            }, 0, 2);

            _descriptorStream.Flush();
            _descriptorStream.Close();
            _imageStream.Flush();
            _imageStream.Close();

            IsWriting    = false;
            ErrorMessage = "";

            return(true);
        }
Пример #2
0
        static void ReadLeadOutUsingTrapDisc(string devPath, Device dev)
        {
            string strDev;
            int    item;
            bool   tocIsNotBcd = false;
            bool   sense;

            byte[] buffer;
            byte[] senseBuffer;
            int    retries;

start:
            System.Console.Clear();

            AaruConsole.WriteLine("Ejecting disc...");

            dev.AllowMediumRemoval(out _, dev.Timeout, out _);
            dev.EjectTray(out _, dev.Timeout, out _);

            AaruConsole.WriteLine("Please insert a data only disc inside...");
            AaruConsole.WriteLine("Press any key to continue...");
            System.Console.ReadLine();

            AaruConsole.WriteLine("Sending READ FULL TOC to the device...");

            retries = 0;

            do
            {
                retries++;
                sense = dev.ScsiTestUnitReady(out senseBuffer, dev.Timeout, out _);

                if (!sense)
                {
                    break;
                }

                DecodedSense?decodedSense = Sense.Decode(senseBuffer);

                if (decodedSense.Value.ASC != 0x04)
                {
                    break;
                }

                if (decodedSense.Value.ASCQ != 0x01)
                {
                    break;
                }

                Thread.Sleep(2000);
            } while(retries < 25);

            sense = dev.ReadRawToc(out buffer, out senseBuffer, 1, dev.Timeout, out _);

            if (sense)
            {
                AaruConsole.WriteLine("READ FULL TOC failed...");
                AaruConsole.WriteLine("{0}", Sense.PrettifySense(senseBuffer));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            FullTOC.CDFullTOC?decodedToc = FullTOC.Decode(buffer);

            if (decodedToc is null)
            {
                AaruConsole.WriteLine("Could not decode TOC...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            FullTOC.CDFullTOC toc = decodedToc.Value;

            FullTOC.TrackDataDescriptor leadOutTrack = toc.TrackDescriptors.FirstOrDefault(t => t.POINT == 0xA2);

            if (leadOutTrack.POINT != 0xA2)
            {
                AaruConsole.WriteLine("Cannot find lead-out...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            int min   = ((leadOutTrack.PMIN >> 4) * 10) + (leadOutTrack.PMIN & 0x0F);
            int sec   = ((leadOutTrack.PSEC >> 4) * 10) + (leadOutTrack.PSEC & 0x0F);
            int frame = ((leadOutTrack.PFRAME >> 4) * 10) + (leadOutTrack.PFRAME & 0x0F);

            int sectors = (min * 60 * 75) + (sec * 75) + frame - 150;

            AaruConsole.WriteLine("Data disc shows {0} sectors...", sectors);

            AaruConsole.WriteLine("Ejecting disc...");

            dev.AllowMediumRemoval(out _, dev.Timeout, out _);
            dev.EjectTray(out _, dev.Timeout, out _);

            AaruConsole.WriteLine("Please insert the trap disc inside...");
            AaruConsole.WriteLine("Press any key to continue...");
            System.Console.ReadLine();

            AaruConsole.WriteLine("Sending READ FULL TOC to the device...");

            retries = 0;

            do
            {
                retries++;
                sense = dev.ScsiTestUnitReady(out senseBuffer, dev.Timeout, out _);

                if (!sense)
                {
                    break;
                }

                DecodedSense?decodedSense = Sense.Decode(senseBuffer);

                if (decodedSense.Value.ASC != 0x04)
                {
                    break;
                }

                if (decodedSense.Value.ASCQ != 0x01)
                {
                    break;
                }

                Thread.Sleep(2000);
            } while(retries < 25);

            sense = dev.ReadRawToc(out buffer, out senseBuffer, 1, dev.Timeout, out _);

            if (sense)
            {
                AaruConsole.WriteLine("READ FULL TOC failed...");
                AaruConsole.WriteLine("{0}", Sense.PrettifySense(senseBuffer));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            decodedToc = FullTOC.Decode(buffer);

            if (decodedToc is null)
            {
                AaruConsole.WriteLine("Could not decode TOC...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            toc = decodedToc.Value;

            leadOutTrack = toc.TrackDescriptors.FirstOrDefault(t => t.POINT == 0xA2);

            if (leadOutTrack.POINT != 0xA2)
            {
                AaruConsole.WriteLine("Cannot find lead-out...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            min = 0;

            if (leadOutTrack.PMIN == 122)
            {
                tocIsNotBcd = true;
            }

            if (leadOutTrack.PMIN >= 0xA0 &&
                !tocIsNotBcd)
            {
                min += 90;
                leadOutTrack.PMIN -= 0x90;
            }

            if (tocIsNotBcd)
            {
                min   = leadOutTrack.PMIN;
                sec   = leadOutTrack.PSEC;
                frame = leadOutTrack.PFRAME;
            }
            else
            {
                min  += ((leadOutTrack.PMIN >> 4) * 10) + (leadOutTrack.PMIN & 0x0F);
                sec   = ((leadOutTrack.PSEC >> 4) * 10) + (leadOutTrack.PSEC & 0x0F);
                frame = ((leadOutTrack.PFRAME >> 4) * 10) + (leadOutTrack.PFRAME & 0x0F);
            }

            int trapSectors = (min * 60 * 75) + (sec * 75) + frame - 150;

            AaruConsole.WriteLine("Trap disc shows {0} sectors...", trapSectors);

            if (trapSectors < sectors + 100)
            {
                AaruConsole.WriteLine("Trap disc doesn't have enough sectors...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            AaruConsole.WriteLine("Stopping motor...");

            dev.StopUnit(out _, dev.Timeout, out _);

            AaruConsole.WriteLine("Please MANUALLY get the trap disc out and put the data disc back inside...");
            AaruConsole.WriteLine("Press any key to continue...");
            System.Console.ReadLine();

            AaruConsole.WriteLine("Waiting 5 seconds...");
            Thread.Sleep(5000);

            AaruConsole.WriteLine("Sending READ FULL TOC to the device...");

            retries = 0;

            do
            {
                retries++;
                sense = dev.ReadRawToc(out buffer, out senseBuffer, 1, dev.Timeout, out _);

                if (!sense)
                {
                    break;
                }

                DecodedSense?decodedSense = Sense.Decode(senseBuffer);

                if (decodedSense.Value.ASC != 0x04)
                {
                    break;
                }

                if (decodedSense.Value.ASCQ != 0x01)
                {
                    break;
                }
            } while(retries < 25);

            if (sense)
            {
                AaruConsole.WriteLine("READ FULL TOC failed...");
                AaruConsole.WriteLine("{0}", Sense.PrettifySense(senseBuffer));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            decodedToc = FullTOC.Decode(buffer);

            if (decodedToc is null)
            {
                AaruConsole.WriteLine("Could not decode TOC...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            toc = decodedToc.Value;

            FullTOC.TrackDataDescriptor newLeadOutTrack = toc.TrackDescriptors.FirstOrDefault(t => t.POINT == 0xA2);

            if (newLeadOutTrack.POINT != 0xA2)
            {
                AaruConsole.WriteLine("Cannot find lead-out...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            if (newLeadOutTrack.PMIN >= 0xA0 &&
                !tocIsNotBcd)
            {
                newLeadOutTrack.PMIN -= 0x90;
            }

            if (newLeadOutTrack.PMIN != leadOutTrack.PMIN ||
                newLeadOutTrack.PSEC != leadOutTrack.PSEC ||
                newLeadOutTrack.PFRAME != leadOutTrack.PFRAME)
            {
                AaruConsole.WriteLine("Lead-out has changed, this drive does not support hot swapping discs...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            AaruConsole.Write("Reading LBA {0}... ", sectors + 5);

            bool dataResult = dev.ReadCd(out byte[] dataBuffer, out byte[] dataSense, (uint)(sectors + 5), 2352, 1,
                                         MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true,
                                         true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _);

            AaruConsole.WriteLine(dataResult ? "FAIL!" : "Success!");

            AaruConsole.Write("Reading LBA {0} as audio (scrambled)... ", sectors + 5);

            bool scrambledResult = dev.ReadCd(out byte[] scrambledBuffer, out byte[] scrambledSense,
                                              (uint)(sectors + 5), 2352, 1, MmcSectorTypes.Cdda, false, false, false,
                                              MmcHeaderCodes.None, true, false, MmcErrorField.None, MmcSubchannel.None,
                                              dev.Timeout, out _);

            AaruConsole.WriteLine(scrambledResult ? "FAIL!" : "Success!");

            AaruConsole.Write("Reading LBA {0}'s PQ subchannel... ", sectors + 5);

            bool pqResult = dev.ReadCd(out byte[] pqBuffer, out byte[] pqSense, (uint)(sectors + 5), 16, 1,
                                       MmcSectorTypes.AllTypes, false, false, false, MmcHeaderCodes.None, false, false,
                                       MmcErrorField.None, MmcSubchannel.Q16, dev.Timeout, out _);

            if (pqResult)
            {
                pqResult = dev.ReadCd(out pqBuffer, out pqSense, (uint)(sectors + 5), 16, 1, MmcSectorTypes.AllTypes,
                                      false, false, false, MmcHeaderCodes.None, false, false, MmcErrorField.None,
                                      MmcSubchannel.Q16, dev.Timeout, out _);
            }

            AaruConsole.WriteLine(pqResult ? "FAIL!" : "Success!");

            AaruConsole.Write("Reading LBA {0}'s PQ subchannel... ", sectors + 5);

            bool rwResult = dev.ReadCd(out byte[] rwBuffer, out byte[] rwSense, (uint)(sectors + 5), 16, 1,
                                       MmcSectorTypes.AllTypes, false, false, false, MmcHeaderCodes.None, false, false,
                                       MmcErrorField.None, MmcSubchannel.Rw, dev.Timeout, out _);

            if (rwResult)
            {
                rwResult = dev.ReadCd(out rwBuffer, out rwSense, (uint)(sectors + 5), 16, 1, MmcSectorTypes.Cdda, false,
                                      false, false, MmcHeaderCodes.None, false, false, MmcErrorField.None,
                                      MmcSubchannel.Rw, dev.Timeout, out _);
            }

            AaruConsole.WriteLine(pqResult ? "FAIL!" : "Success!");

menu:
            System.Console.Clear();
            AaruConsole.WriteLine("Device: {0}", devPath);
            AaruConsole.WriteLine("Device {0} read Lead-Out.", dataResult && scrambledResult ? "cannot" : "can");

            AaruConsole.WriteLine("LBA {0} sense is {1}, buffer is {2}, sense buffer is {3}.", sectors + 5, dataResult,
                                  dataBuffer is null
                                      ? "null"
                                      : ArrayHelpers.ArrayIsNullOrEmpty(dataBuffer)
                                          ? "empty"
                                          : $"{dataBuffer.Length} bytes", dataSense is null
                                                                              ? "null"
                                                                              : ArrayHelpers.
                                  ArrayIsNullOrEmpty(dataSense)
                                                                                  ? "empty"
                                                                                  : $"{dataSense.Length}");

            AaruConsole.WriteLine("LBA {0} (scrambled) sense is {1}, buffer is {2}, sense buffer is {3}.", sectors + 5,
                                  scrambledResult, scrambledBuffer is null
                                                       ? "null"
                                                       : ArrayHelpers.ArrayIsNullOrEmpty(scrambledBuffer)
                                                           ? "empty"
                                                           : $"{scrambledBuffer.Length} bytes", scrambledSense is null
                                      ? "null"
                                      : ArrayHelpers.ArrayIsNullOrEmpty(scrambledSense)
                                          ? "empty"
                                          : $"{scrambledSense.Length}");

            AaruConsole.WriteLine("LBA {0}'s PQ sense is {1}, buffer is {2}, sense buffer is {3}.", sectors + 5,
                                  pqResult, pqBuffer is null
                                                ? "null"
                                                : ArrayHelpers.ArrayIsNullOrEmpty(pqBuffer)
                                                    ? "empty"
                                                    : $"{pqBuffer.Length} bytes", pqSense is null
                                      ? "null"
                                      : ArrayHelpers.ArrayIsNullOrEmpty(pqSense)
                                          ? "empty"
                                          : $"{pqSense.Length}");

            AaruConsole.WriteLine("LBA {0}'s RW sense is {1}, buffer is {2}, sense buffer is {3}.", sectors + 5,
                                  rwResult, rwBuffer is null
                                                ? "null"
                                                : ArrayHelpers.ArrayIsNullOrEmpty(rwBuffer)
                                                    ? "empty"
                                                    : $"{rwBuffer.Length} bytes", rwSense is null
                                      ? "null"
                                      : ArrayHelpers.ArrayIsNullOrEmpty(rwSense)
                                          ? "empty"
                                          : $"{rwSense.Length}");

            AaruConsole.WriteLine();
            AaruConsole.WriteLine("Choose what to do:");
            AaruConsole.WriteLine("1.- Print LBA {0} buffer.", sectors + 5);
            AaruConsole.WriteLine("2.- Print LBA {0} sense buffer.", sectors + 5);
            AaruConsole.WriteLine("3.- Decode LBA {0} sense buffer.", sectors + 5);
            AaruConsole.WriteLine("4.- Print LBA {0} (scrambled) buffer.", sectors + 5);
            AaruConsole.WriteLine("5.- Print LBA {0} (scrambled) sense buffer.", sectors + 5);
            AaruConsole.WriteLine("6.- Decode LBA {0} (scrambled) sense buffer.", sectors + 5);
            AaruConsole.WriteLine("7.- Print LBA {0}'s PQ buffer.", sectors + 5);
            AaruConsole.WriteLine("8.- Print LBA {0}'s PQ sense buffer.", sectors + 5);
            AaruConsole.WriteLine("9.- Decode LBA {0}'s PQ sense buffer.", sectors + 5);
            AaruConsole.WriteLine("10.- Print LBA {0}'s RW buffer.", sectors + 5);
            AaruConsole.WriteLine("11.- Print LBA {0}'s RW sense buffer.", sectors + 5);
            AaruConsole.WriteLine("12.- Decode LBA {0}'s RW sense buffer.", sectors + 5);
            AaruConsole.WriteLine("13.- Send command again.");
            AaruConsole.WriteLine("0.- Return to special SCSI MultiMedia Commands menu.");
            AaruConsole.Write("Choose: ");

            strDev = System.Console.ReadLine();

            if (!int.TryParse(strDev, out item))
            {
                AaruConsole.WriteLine("Not a number. Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();

                goto menu;
            }

            switch (item)
            {
            case 0:
                AaruConsole.WriteLine("Returning to special SCSI MultiMedia Commands menu...");

                return;

            case 1:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA {0} response:", sectors + 5);

                if (buffer != null)
                {
                    PrintHex.PrintHexArray(dataBuffer, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 2:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA {0} sense:", sectors + 5);

                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(dataSense, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 3:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA {0} decoded sense:", sectors + 5);
                AaruConsole.Write("{0}", Sense.PrettifySense(dataSense));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 4:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA {0} (scrambled) response:", sectors + 5);

                if (buffer != null)
                {
                    PrintHex.PrintHexArray(scrambledBuffer, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 5:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA {0} (scrambled) sense:", sectors + 5);

                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(scrambledSense, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 6:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA {0} (scrambled) decoded sense:", sectors + 5);
                AaruConsole.Write("{0}", Sense.PrettifySense(scrambledSense));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 7:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA's PQ {0} response:", sectors + 5);

                if (buffer != null)
                {
                    PrintHex.PrintHexArray(pqBuffer, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 8:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA's PQ {0} sense:", sectors + 5);

                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(pqSense, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 9:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA's PQ {0} decoded sense:", sectors + 5);
                AaruConsole.Write("{0}", Sense.PrettifySense(pqSense));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 10:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA's RW {0} response:", sectors + 5);

                if (buffer != null)
                {
                    PrintHex.PrintHexArray(rwBuffer, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 11:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA's RW {0} sense:", sectors + 5);

                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(rwSense, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 12:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA's RW {0} decoded sense:", sectors + 5);
                AaruConsole.Write("{0}", Sense.PrettifySense(rwSense));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 13: goto start;

            default:
                AaruConsole.WriteLine("Incorrect option. Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();

                goto menu;
            }
        }
Пример #3
0
        static void CheckGdromReadability(string devPath, Device dev)
        {
            string strDev;
            int    item;
            bool   tocIsNotBcd = false;
            bool   sense;

            byte[] buffer;
            byte[] senseBuffer;
            int    retries;

start:
            System.Console.Clear();

            AaruConsole.WriteLine("Ejecting disc...");

            dev.AllowMediumRemoval(out _, dev.Timeout, out _);
            dev.EjectTray(out _, dev.Timeout, out _);

            AaruConsole.WriteLine("Please insert trap disc inside...");
            AaruConsole.WriteLine("Press any key to continue...");
            System.Console.ReadLine();

            AaruConsole.WriteLine("Sending READ FULL TOC to the device...");

            retries = 0;

            do
            {
                retries++;
                sense = dev.ScsiTestUnitReady(out senseBuffer, dev.Timeout, out _);

                if (!sense)
                {
                    break;
                }

                var decodedSense = Sense.Decode(senseBuffer);

                if (decodedSense.Value.ASC != 0x04)
                {
                    break;
                }

                if (decodedSense.Value.ASCQ != 0x01)
                {
                    break;
                }

                Thread.Sleep(2000);
            } while(retries < 25);

            sense = dev.ReadRawToc(out buffer, out senseBuffer, 1, dev.Timeout, out _);

            if (sense)
            {
                AaruConsole.WriteLine("READ FULL TOC failed...");
                AaruConsole.WriteLine("{0}", Sense.PrettifySense(senseBuffer));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            FullTOC.CDFullTOC?decodedToc = FullTOC.Decode(buffer);

            if (decodedToc is null)
            {
                AaruConsole.WriteLine("Could not decode TOC...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            FullTOC.CDFullTOC toc = decodedToc.Value;

            FullTOC.TrackDataDescriptor leadOutTrack = toc.TrackDescriptors.FirstOrDefault(t => t.POINT == 0xA2);

            if (leadOutTrack.POINT != 0xA2)
            {
                AaruConsole.WriteLine("Cannot find lead-out...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            int min = 0, sec, frame;

            if (leadOutTrack.PMIN == 122)
            {
                tocIsNotBcd = true;
            }

            if (leadOutTrack.PMIN >= 0xA0 &&
                !tocIsNotBcd)
            {
                min += 90;
                leadOutTrack.PMIN -= 0x90;
            }

            if (tocIsNotBcd)
            {
                min   = leadOutTrack.PMIN;
                sec   = leadOutTrack.PSEC;
                frame = leadOutTrack.PFRAME;
            }
            else
            {
                min  += ((leadOutTrack.PMIN >> 4) * 10) + (leadOutTrack.PMIN & 0x0F);
                sec   = ((leadOutTrack.PSEC >> 4) * 10) + (leadOutTrack.PSEC & 0x0F);
                frame = ((leadOutTrack.PFRAME >> 4) * 10) + (leadOutTrack.PFRAME & 0x0F);
            }

            int sectors = ((min * 60 * 75) + (sec * 75) + frame) - 150;

            AaruConsole.WriteLine("Trap disc shows {0} sectors...", sectors);

            if (sectors < 450000)
            {
                AaruConsole.WriteLine("Trap disc doesn't have enough sectors...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            AaruConsole.WriteLine("Stopping motor...");

            dev.StopUnit(out _, dev.Timeout, out _);

            AaruConsole.WriteLine("Please MANUALLY get the trap disc out and put the GD-ROM disc inside...");
            AaruConsole.WriteLine("Press any key to continue...");
            System.Console.ReadLine();

            AaruConsole.WriteLine("Waiting 5 seconds...");
            Thread.Sleep(5000);

            AaruConsole.WriteLine("Sending READ FULL TOC to the device...");

            retries = 0;

            do
            {
                retries++;
                sense = dev.ReadRawToc(out buffer, out senseBuffer, 1, dev.Timeout, out _);

                if (!sense)
                {
                    break;
                }

                var decodedSense = Sense.Decode(senseBuffer);

                if (decodedSense.Value.ASC != 0x04)
                {
                    break;
                }

                if (decodedSense.Value.ASCQ != 0x01)
                {
                    break;
                }
            } while(retries < 25);

            if (sense)
            {
                AaruConsole.WriteLine("READ FULL TOC failed...");
                AaruConsole.WriteLine("{0}", Sense.PrettifySense(senseBuffer));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            decodedToc = FullTOC.Decode(buffer);

            if (decodedToc is null)
            {
                AaruConsole.WriteLine("Could not decode TOC...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            toc = decodedToc.Value;

            FullTOC.TrackDataDescriptor newLeadOutTrack = toc.TrackDescriptors.FirstOrDefault(t => t.POINT == 0xA2);

            if (newLeadOutTrack.POINT != 0xA2)
            {
                AaruConsole.WriteLine("Cannot find lead-out...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            if (newLeadOutTrack.PMIN >= 0xA0 &&
                !tocIsNotBcd)
            {
                newLeadOutTrack.PMIN -= 0x90;
            }

            if (newLeadOutTrack.PMIN != leadOutTrack.PMIN ||
                newLeadOutTrack.PSEC != leadOutTrack.PSEC ||
                newLeadOutTrack.PFRAME != leadOutTrack.PFRAME)
            {
                AaruConsole.WriteLine("Lead-out has changed, this drive does not support hot swapping discs...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            dev.SetCdSpeed(out _, RotationalControl.PureCav, 170, 0, dev.Timeout, out _);

            AaruConsole.Write("Reading LBA 0... ");

            bool lba0Result = dev.ReadCd(out byte[] lba0Buffer, out byte[] lba0Sense, 0, 2352, 1,
                                         MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true,
                                         true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _);

            AaruConsole.WriteLine(lba0Result ? "FAIL!" : "Success!");

            AaruConsole.Write("Reading LBA 0 as audio (scrambled)... ");

            bool lba0ScrambledResult = dev.ReadCd(out byte[] lba0ScrambledBuffer, out byte[] lba0ScrambledSense, 0,
                                                  2352, 1, MmcSectorTypes.Cdda, false, false, false,
                                                  MmcHeaderCodes.None, true, false, MmcErrorField.None,
                                                  MmcSubchannel.None, dev.Timeout, out _);

            AaruConsole.WriteLine(lba0ScrambledResult ? "FAIL!" : "Success!");

            AaruConsole.Write("Reading LBA 100000... ");

            bool lba100000Result = dev.ReadCd(out byte[] lba100000Buffer, out byte[] lba100000Sense, 100000, 2352, 1,
                                              MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders,
                                              true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _);

            AaruConsole.WriteLine(lba100000Result ? "FAIL!" : "Success!");

            AaruConsole.Write("Reading LBA 50000... ");

            bool lba50000Result = dev.ReadCd(out byte[] lba50000Buffer, out byte[] lba50000Sense, 50000, 2352, 1,
                                             MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders,
                                             true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _);

            AaruConsole.WriteLine(lba50000Result ? "FAIL!" : "Success!");

            AaruConsole.Write("Reading LBA 450000... ");

            bool lba450000Result = dev.ReadCd(out byte[] lba450000Buffer, out byte[] lba450000Sense, 450000, 2352, 1,
                                              MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders,
                                              true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _);

            AaruConsole.WriteLine(lba450000Result ? "FAIL!" : "Success!");

            AaruConsole.Write("Reading LBA 400000... ");

            bool lba400000Result = dev.ReadCd(out byte[] lba400000Buffer, out byte[] lba400000Sense, 400000, 2352, 1,
                                              MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders,
                                              true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _);

            AaruConsole.WriteLine(lba400000Result ? "FAIL!" : "Success!");

            AaruConsole.Write("Reading LBA 45000... ");

            bool lba45000Result = dev.ReadCd(out byte[] lba45000Buffer, out byte[] lba45000Sense, 45000, 2352, 1,
                                             MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders,
                                             true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _);

            AaruConsole.WriteLine(lba45000Result ? "FAIL!" : "Success!");

            AaruConsole.Write("Reading LBA 44990... ");

            bool lba44990Result = dev.ReadCd(out byte[] lba44990Buffer, out byte[] lba44990Sense, 44990, 2352, 1,
                                             MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders,
                                             true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _);

            AaruConsole.WriteLine(lba44990Result ? "FAIL!" : "Success!");

menu:
            System.Console.Clear();
            AaruConsole.WriteLine("Device: {0}", devPath);
            AaruConsole.WriteLine("Device {0} read HD area.", lba450000Result ? "cannot" : "can");

            AaruConsole.WriteLine("LBA 0 sense is {0}, buffer is {1}, sense buffer is {2}.", lba0Result,
                                  lba0Buffer is null
                                      ? "null"
                                      : ArrayHelpers.ArrayIsNullOrEmpty(lba0Buffer)
                                          ? "empty"
                                          : $"{lba0Buffer.Length} bytes", lba0Sense is null
                                                                              ? "null"
                                                                              : ArrayHelpers.
                                  ArrayIsNullOrEmpty(lba0Sense)
                                                                                  ? "empty"
                                                                                  : $"{lba0Sense.Length}");

            AaruConsole.WriteLine("LBA 0 (scrambled) sense is {0}, buffer is {1}, sense buffer is {2}.",
                                  lba0ScrambledResult, lba0ScrambledBuffer is null
                                                           ? "null"
                                                           : ArrayHelpers.ArrayIsNullOrEmpty(lba0ScrambledBuffer)
                                                               ? "empty"
                                                               : $"{lba0ScrambledBuffer.Length} bytes",
                                  lba0ScrambledSense is null
                                      ? "null"
                                      : ArrayHelpers.ArrayIsNullOrEmpty(lba0ScrambledSense)
                                          ? "empty"
                                          : $"{lba0ScrambledSense.Length}");

            AaruConsole.WriteLine("LBA 44990 sense is {0}, buffer is {1}, sense buffer is {2}.", lba44990Result,
                                  lba44990Buffer is null
                                      ? "null"
                                      : ArrayHelpers.ArrayIsNullOrEmpty(lba44990Buffer)
                                          ? "empty"
                                          : $"{lba44990Buffer.Length} bytes", lba44990Sense is null
                                                                                  ? "null"
                                                                                  : ArrayHelpers.
                                  ArrayIsNullOrEmpty(lba44990Sense)
                                                                                      ? "empty"
                                                                                      : $"{lba44990Sense.Length}");

            AaruConsole.WriteLine("LBA 45000 sense is {0}, buffer is {1}, sense buffer is {2}.", lba45000Result,
                                  lba45000Buffer is null
                                      ? "null"
                                      : ArrayHelpers.ArrayIsNullOrEmpty(lba45000Buffer)
                                          ? "empty"
                                          : $"{lba45000Buffer.Length} bytes", lba45000Sense is null
                                                                                  ? "null"
                                                                                  : ArrayHelpers.
                                  ArrayIsNullOrEmpty(lba45000Sense)
                                                                                      ? "empty"
                                                                                      : $"{lba45000Sense.Length}");

            AaruConsole.WriteLine("LBA 50000 sense is {0}, buffer is {1}, sense buffer is {2}.", lba50000Result,
                                  lba50000Buffer is null
                                      ? "null"
                                      : ArrayHelpers.ArrayIsNullOrEmpty(lba50000Buffer)
                                          ? "empty"
                                          : $"{lba50000Buffer.Length} bytes", lba50000Sense is null
                                                                                  ? "null"
                                                                                  : ArrayHelpers.
                                  ArrayIsNullOrEmpty(lba50000Sense)
                                                                                      ? "empty"
                                                                                      : $"{lba50000Sense.Length}");

            AaruConsole.WriteLine("LBA 100000 sense is {0}, buffer is {1}, sense buffer is {2}.", lba100000Result,
                                  lba100000Buffer is null
                                      ? "null"
                                      : ArrayHelpers.ArrayIsNullOrEmpty(lba100000Buffer)
                                          ? "empty"
                                          : $"{lba100000Buffer.Length} bytes", lba100000Sense is null
                                                                                   ? "null"
                                                                                   : ArrayHelpers.
                                  ArrayIsNullOrEmpty(lba100000Sense)
                                                                                       ? "empty"
                                                                                       : $"{lba100000Sense.Length}");

            AaruConsole.WriteLine("LBA 400000 sense is {0}, buffer is {1}, sense buffer is {2}.", lba400000Result,
                                  lba400000Buffer is null
                                      ? "null"
                                      : ArrayHelpers.ArrayIsNullOrEmpty(lba400000Buffer)
                                          ? "empty"
                                          : $"{lba400000Buffer.Length} bytes", lba400000Sense is null
                                                                                   ? "null"
                                                                                   : ArrayHelpers.
                                  ArrayIsNullOrEmpty(lba400000Sense)
                                                                                       ? "empty"
                                                                                       : $"{lba400000Sense.Length}");

            AaruConsole.WriteLine("LBA 450000 sense is {0}, buffer is {1}, sense buffer is {2}.", lba450000Result,
                                  lba450000Buffer is null
                                      ? "null"
                                      : ArrayHelpers.ArrayIsNullOrEmpty(lba450000Buffer)
                                          ? "empty"
                                          : $"{lba450000Buffer.Length} bytes", lba450000Sense is null
                                                                                   ? "null"
                                                                                   : ArrayHelpers.
                                  ArrayIsNullOrEmpty(lba450000Sense)
                                                                                       ? "empty"
                                                                                       : $"{lba450000Sense.Length}");

            AaruConsole.WriteLine();
            AaruConsole.WriteLine("Choose what to do:");
            AaruConsole.WriteLine("1.- Print LBA 0 buffer.");
            AaruConsole.WriteLine("2.- Print LBA 0 sense buffer.");
            AaruConsole.WriteLine("3.- Decode LBA 0 sense buffer.");
            AaruConsole.WriteLine("4.- Print LBA 0 (scrambled) buffer.");
            AaruConsole.WriteLine("5.- Print LBA 0 (scrambled) sense buffer.");
            AaruConsole.WriteLine("6.- Decode LBA 0 (scrambled) sense buffer.");
            AaruConsole.WriteLine("7.- Print LBA 44990 buffer.");
            AaruConsole.WriteLine("8.- Print LBA 44990 sense buffer.");
            AaruConsole.WriteLine("9.- Decode LBA 44990 sense buffer.");
            AaruConsole.WriteLine("10.- Print LBA 45000 buffer.");
            AaruConsole.WriteLine("11.- Print LBA 45000 sense buffer.");
            AaruConsole.WriteLine("12.- Decode LBA 45000 sense buffer.");
            AaruConsole.WriteLine("13.- Print LBA 50000 buffer.");
            AaruConsole.WriteLine("14.- Print LBA 50000 sense buffer.");
            AaruConsole.WriteLine("15.- Decode LBA 50000 sense buffer.");
            AaruConsole.WriteLine("16.- Print LBA 100000 buffer.");
            AaruConsole.WriteLine("17.- Print LBA 100000 sense buffer.");
            AaruConsole.WriteLine("18.- Decode LBA 100000 sense buffer.");
            AaruConsole.WriteLine("19.- Print LBA 400000 buffer.");
            AaruConsole.WriteLine("20.- Print LBA 400000 sense buffer.");
            AaruConsole.WriteLine("21.- Decode LBA 400000 sense buffer.");
            AaruConsole.WriteLine("22.- Print LBA 450000 buffer.");
            AaruConsole.WriteLine("23.- Print LBA 450000 sense buffer.");
            AaruConsole.WriteLine("24.- Decode LBA 450000 sense buffer.");
            AaruConsole.WriteLine("25.- Send command again.");
            AaruConsole.WriteLine("0.- Return to special SCSI MultiMedia Commands menu.");
            AaruConsole.Write("Choose: ");

            strDev = System.Console.ReadLine();

            if (!int.TryParse(strDev, out item))
            {
                AaruConsole.WriteLine("Not a number. Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();

                goto menu;
            }

            switch (item)
            {
            case 0:
                AaruConsole.WriteLine("Returning to special SCSI MultiMedia Commands menu...");

                return;

            case 1:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 0 response:");

                if (buffer != null)
                {
                    PrintHex.PrintHexArray(lba0Buffer, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 2:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 0 sense:");

                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(lba0Sense, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 3:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 0 decoded sense:");
                AaruConsole.Write("{0}", Sense.PrettifySense(lba0Sense));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 4:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 0 (scrambled) response:");

                if (buffer != null)
                {
                    PrintHex.PrintHexArray(lba0ScrambledBuffer, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 5:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 0 (scrambled) sense:");

                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(lba0ScrambledSense, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 6:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 0 (scrambled) decoded sense:");
                AaruConsole.Write("{0}", Sense.PrettifySense(lba0ScrambledSense));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 7:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 44990 response:");

                if (buffer != null)
                {
                    PrintHex.PrintHexArray(lba44990Buffer, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 8:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 44990 sense:");

                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(lba44990Sense, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 9:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 44990 decoded sense:");
                AaruConsole.Write("{0}", Sense.PrettifySense(lba44990Sense));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 10:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 45000 response:");

                if (buffer != null)
                {
                    PrintHex.PrintHexArray(lba45000Buffer, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 11:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 45000 sense:");

                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(lba45000Sense, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 12:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 45000 decoded sense:");
                AaruConsole.Write("{0}", Sense.PrettifySense(lba45000Sense));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 13:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 50000 response:");

                if (buffer != null)
                {
                    PrintHex.PrintHexArray(lba50000Buffer, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 14:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 50000 sense:");

                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(lba50000Sense, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 15:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 50000 decoded sense:");
                AaruConsole.Write("{0}", Sense.PrettifySense(lba50000Sense));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 16:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 100000 response:");

                if (buffer != null)
                {
                    PrintHex.PrintHexArray(lba100000Buffer, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 17:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 100000 sense:");

                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(lba100000Sense, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 18:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 100000 decoded sense:");
                AaruConsole.Write("{0}", Sense.PrettifySense(lba100000Sense));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 19:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 400000 response:");

                if (buffer != null)
                {
                    PrintHex.PrintHexArray(lba400000Buffer, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 20:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 400000 sense:");

                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(lba400000Sense, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 21:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 400000 decoded sense:");
                AaruConsole.Write("{0}", Sense.PrettifySense(lba400000Sense));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 22:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 450000 response:");

                if (buffer != null)
                {
                    PrintHex.PrintHexArray(lba450000Buffer, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 23:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 450000 sense:");

                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(lba450000Sense, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 24:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 450000 decoded sense:");
                AaruConsole.Write("{0}", Sense.PrettifySense(lba450000Sense));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 25: goto start;

            default:
                AaruConsole.WriteLine("Incorrect option. Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();

                goto menu;
            }
        }
Пример #4
0
        public static void DetectDiscType(ref MediaType mediaType, int sessions, FullTOC.CDFullTOC?decodedToc,
                                          Device dev, out bool hiddenTrack, out bool hiddenData,
                                          int firstTrackLastSession)
        {
            uint startOfFirstDataTrack = uint.MaxValue;

            byte[] cmdBuf;
            bool   sense;
            byte   secondSessionFirstTrack = 0;

            byte[] sector0;
            byte[] sector1                      = null;
            byte[] ps2BootSectors               = null;
            byte[] playdia1                     = null;
            byte[] playdia2                     = null;
            byte[] firstDataSectorNotZero       = null;
            byte[] secondDataSectorNotZero      = null;
            byte[] firstTrackSecondSession      = null;
            byte[] firstTrackSecondSessionAudio = null;
            byte[] videoNowColorFrame;
            hiddenTrack = false;
            hiddenData  = false;

            if (decodedToc.HasValue)
            {
                if (decodedToc.Value.TrackDescriptors.Any(t => t.SessionNumber == 2))
                {
                    secondSessionFirstTrack =
                        decodedToc.Value.TrackDescriptors.Where(t => t.SessionNumber == 2).Min(t => t.POINT);
                }
            }

            if (mediaType == MediaType.CD ||
                mediaType == MediaType.CDROMXA)
            {
                bool hasDataTrack  = false;
                bool hasAudioTrack = false;
                bool allFirstSessionTracksAreAudio = true;
                bool hasVideoTrack = false;

                if (decodedToc.HasValue)
                {
                    foreach (FullTOC.TrackDataDescriptor track in decodedToc.Value.TrackDescriptors)
                    {
                        if (track.TNO == 1 &&
                            ((TocControl)(track.CONTROL & 0x0D) == TocControl.DataTrack ||
                             (TocControl)(track.CONTROL & 0x0D) == TocControl.DataTrackIncremental))
                        {
                            allFirstSessionTracksAreAudio &= firstTrackLastSession != 1;
                        }

                        if ((TocControl)(track.CONTROL & 0x0D) == TocControl.DataTrack ||
                            (TocControl)(track.CONTROL & 0x0D) == TocControl.DataTrackIncremental)
                        {
                            uint startAddress =
                                (uint)(((track.PHOUR * 3600 * 75) + (track.PMIN * 60 * 75) + (track.PSEC * 75) +
                                        track.PFRAME) - 150);

                            if (startAddress < startOfFirstDataTrack)
                            {
                                startOfFirstDataTrack = startAddress;
                            }

                            hasDataTrack = true;
                            allFirstSessionTracksAreAudio &= track.POINT >= firstTrackLastSession;
                        }
                        else
                        {
                            hasAudioTrack = true;
                        }

                        hasVideoTrack |= track.ADR == 4;
                    }
                }

                if (hasDataTrack &&
                    hasAudioTrack &&
                    allFirstSessionTracksAreAudio &&
                    sessions == 2)
                {
                    mediaType = MediaType.CDPLUS;
                }

                if (!hasDataTrack &&
                    hasAudioTrack &&
                    sessions == 1)
                {
                    mediaType = MediaType.CDDA;
                }

                if (hasDataTrack &&
                    !hasAudioTrack &&
                    sessions == 1)
                {
                    mediaType = MediaType.CDROM;
                }

                if (hasVideoTrack &&
                    !hasDataTrack &&
                    sessions == 1)
                {
                    mediaType = MediaType.CDV;
                }
            }

            if (secondSessionFirstTrack != 0 &&
                decodedToc.HasValue &&
                decodedToc.Value.TrackDescriptors.Any(t => t.POINT == secondSessionFirstTrack))
            {
                FullTOC.TrackDataDescriptor secondSessionFirstTrackTrack =
                    decodedToc.Value.TrackDescriptors.First(t => t.POINT == secondSessionFirstTrack);

                uint firstSectorSecondSessionFirstTrack =
                    (uint)(((secondSessionFirstTrackTrack.PHOUR * 3600 * 75) +
                            (secondSessionFirstTrackTrack.PMIN * 60 * 75) +
                            (secondSessionFirstTrackTrack.PSEC * 75) +
                            secondSessionFirstTrackTrack.PFRAME) - 150);

                sense = dev.ReadCd(out cmdBuf, out _, firstSectorSecondSessionFirstTrack, 2352, 1,
                                   MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true,
                                   MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _);

                if (!sense &&
                    !dev.Error)
                {
                    firstTrackSecondSession = cmdBuf;
                }
                else
                {
                    sense = dev.ReadCd(out cmdBuf, out _, firstSectorSecondSessionFirstTrack, 2352, 1,
                                       MmcSectorTypes.Cdda, false, false, true, MmcHeaderCodes.None, true, true,
                                       MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _);

                    if (!sense &&
                        !dev.Error)
                    {
                        firstTrackSecondSession = cmdBuf;
                    }
                }

                sense = dev.ReadCd(out cmdBuf, out _, firstSectorSecondSessionFirstTrack - 1, 2352, 3,
                                   MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true,
                                   MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _);

                if (!sense &&
                    !dev.Error)
                {
                    firstTrackSecondSessionAudio = cmdBuf;
                }
                else
                {
                    sense = dev.ReadCd(out cmdBuf, out _, firstSectorSecondSessionFirstTrack - 1, 2352, 3,
                                       MmcSectorTypes.Cdda, false, false, true, MmcHeaderCodes.None, true, true,
                                       MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _);

                    if (!sense &&
                        !dev.Error)
                    {
                        firstTrackSecondSessionAudio = cmdBuf;
                    }
                }
            }

            videoNowColorFrame = new byte[9 * 2352];

            for (int i = 0; i < 9; i++)
            {
                sense = dev.ReadCd(out cmdBuf, out _, (uint)i, 2352, 1, MmcSectorTypes.AllTypes, false, false, true,
                                   MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None,
                                   dev.Timeout, out _);

                if (sense || dev.Error)
                {
                    sense = dev.ReadCd(out cmdBuf, out _, (uint)i, 2352, 1, MmcSectorTypes.Cdda, false, false, true,
                                       MmcHeaderCodes.None, true, true, MmcErrorField.None, MmcSubchannel.None,
                                       dev.Timeout, out _);

                    if (sense || !dev.Error)
                    {
                        videoNowColorFrame = null;

                        break;
                    }
                }

                Array.Copy(cmdBuf, 0, videoNowColorFrame, i * 2352, 2352);
            }

            if (decodedToc.HasValue)
            {
                FullTOC.TrackDataDescriptor firstTrack =
                    decodedToc.Value.TrackDescriptors.FirstOrDefault(t => t.POINT == 1);

                if (firstTrack.POINT == 1)
                {
                    uint firstTrackSector = (uint)(((firstTrack.PHOUR * 3600 * 75) + (firstTrack.PMIN * 60 * 75) +
                                                    (firstTrack.PSEC * 75) + firstTrack.PFRAME) - 150);

                    // Check for hidden data before start of track 1
                    if (firstTrackSector > 0)
                    {
                        sense = dev.ReadCd(out sector0, out _, 0, 2352, 1, MmcSectorTypes.AllTypes, false, false, true,
                                           MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None,
                                           MmcSubchannel.None, dev.Timeout, out _);

                        if (!dev.Error &&
                            !sense)
                        {
                            hiddenTrack = true;

                            hiddenData = IsData(sector0);

                            if (hiddenData)
                            {
                                sense = dev.ReadCd(out byte[] sector16, out _, 16, 2352, 1, MmcSectorTypes.AllTypes,
                                                   false, false, true, MmcHeaderCodes.AllHeaders, true, true,
                                                   MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _);

                                if (IsCdi(sector0, sector16))
                                {
                                    mediaType = MediaType.CDIREADY;
                                }
                            }
                        }
                    }
                }
            }

            sector0 = null;

            switch (mediaType)
            {
            case MediaType.CD:
            case MediaType.CDDA:
            case MediaType.CDPLUS:
            case MediaType.CDROM:
            case MediaType.CDROMXA:
            {
                sense = dev.ReadCd(out cmdBuf, out _, 0, 2352, 1, MmcSectorTypes.AllTypes, false, false, true,
                                   MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None,
                                   dev.Timeout, out _);

                if (!sense &&
                    !dev.Error)
                {
                    sector0 = new byte[2048];
                    Array.Copy(cmdBuf, 16, sector0, 0, 2048);

                    sense = dev.ReadCd(out cmdBuf, out _, 1, 2352, 1, MmcSectorTypes.AllTypes, false, false, true,
                                       MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None,
                                       MmcSubchannel.None, dev.Timeout, out _);

                    if (!sense &&
                        !dev.Error)
                    {
                        sector1 = new byte[2048];
                        Array.Copy(cmdBuf, 16, sector1, 0, 2048);
                    }

                    sense = dev.ReadCd(out cmdBuf, out _, 4200, 2352, 1, MmcSectorTypes.AllTypes, false, false,
                                       true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None,
                                       MmcSubchannel.None, dev.Timeout, out _);

                    if (!sense &&
                        !dev.Error)
                    {
                        playdia1 = new byte[2048];
                        Array.Copy(cmdBuf, 24, playdia1, 0, 2048);
                    }

                    sense = dev.ReadCd(out cmdBuf, out _, 4201, 2352, 1, MmcSectorTypes.AllTypes, false, false,
                                       true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None,
                                       MmcSubchannel.None, dev.Timeout, out _);

                    if (!sense &&
                        !dev.Error)
                    {
                        playdia2 = new byte[2048];
                        Array.Copy(cmdBuf, 24, playdia2, 0, 2048);
                    }

                    if (startOfFirstDataTrack != uint.MaxValue)
                    {
                        sense = dev.ReadCd(out cmdBuf, out _, startOfFirstDataTrack, 2352, 1,
                                           MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders,
                                           true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _);

                        if (!sense &&
                            !dev.Error)
                        {
                            firstDataSectorNotZero = new byte[2048];
                            Array.Copy(cmdBuf, 16, firstDataSectorNotZero, 0, 2048);
                        }

                        sense = dev.ReadCd(out cmdBuf, out _, startOfFirstDataTrack + 1, 2352, 1,
                                           MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders,
                                           true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _);

                        if (!sense &&
                            !dev.Error)
                        {
                            secondDataSectorNotZero = new byte[2048];
                            Array.Copy(cmdBuf, 16, secondDataSectorNotZero, 0, 2048);
                        }
                    }

                    var ps2Ms = new MemoryStream();

                    for (uint p = 0; p < 12; p++)
                    {
                        sense = dev.ReadCd(out cmdBuf, out _, p, 2352, 1, MmcSectorTypes.AllTypes, false, false,
                                           true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None,
                                           MmcSubchannel.None, dev.Timeout, out _);

                        if (sense || dev.Error)
                        {
                            break;
                        }

                        ps2Ms.Write(cmdBuf, cmdBuf[0x0F] == 0x02 ? 24 : 16, 2048);
                    }

                    if (ps2Ms.Length == 0x6000)
                    {
                        ps2BootSectors = ps2Ms.ToArray();
                    }
                }
                else
                {
                    sense = dev.ReadCd(out cmdBuf, out _, 0, 2324, 1, MmcSectorTypes.Mode2, false, false, true,
                                       MmcHeaderCodes.None, true, true, MmcErrorField.None, MmcSubchannel.None,
                                       dev.Timeout, out _);

                    if (!sense &&
                        !dev.Error)
                    {
                        sector0 = new byte[2048];
                        Array.Copy(cmdBuf, 0, sector0, 0, 2048);

                        sense = dev.ReadCd(out cmdBuf, out _, 1, 2324, 1, MmcSectorTypes.Mode2, false, false, true,
                                           MmcHeaderCodes.None, true, true, MmcErrorField.None, MmcSubchannel.None,
                                           dev.Timeout, out _);

                        if (!sense &&
                            !dev.Error)
                        {
                            sector1 = new byte[2048];
                            Array.Copy(cmdBuf, 1, sector0, 0, 2048);
                        }

                        sense = dev.ReadCd(out cmdBuf, out _, 4200, 2324, 1, MmcSectorTypes.Mode2, false, false,
                                           true, MmcHeaderCodes.None, true, true, MmcErrorField.None,
                                           MmcSubchannel.None, dev.Timeout, out _);

                        if (!sense &&
                            !dev.Error)
                        {
                            playdia1 = new byte[2048];
                            Array.Copy(cmdBuf, 0, playdia1, 0, 2048);
                        }

                        sense = dev.ReadCd(out cmdBuf, out _, 4201, 2324, 1, MmcSectorTypes.Mode2, false, false,
                                           true, MmcHeaderCodes.None, true, true, MmcErrorField.None,
                                           MmcSubchannel.None, dev.Timeout, out _);

                        if (!sense &&
                            !dev.Error)
                        {
                            playdia2 = new byte[2048];
                            Array.Copy(cmdBuf, 0, playdia2, 0, 2048);
                        }

                        if (startOfFirstDataTrack != uint.MaxValue)
                        {
                            sense = dev.ReadCd(out cmdBuf, out _, startOfFirstDataTrack, 2324, 1,
                                               MmcSectorTypes.Mode2, false, false, true, MmcHeaderCodes.None, true,
                                               true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _);

                            if (!sense &&
                                !dev.Error)
                            {
                                firstDataSectorNotZero = new byte[2048];
                                Array.Copy(cmdBuf, 0, firstDataSectorNotZero, 0, 2048);
                            }

                            sense = dev.ReadCd(out cmdBuf, out _, startOfFirstDataTrack + 1, 2324, 1,
                                               MmcSectorTypes.Mode2, false, false, true, MmcHeaderCodes.None, true,
                                               true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _);

                            if (!sense &&
                                !dev.Error)
                            {
                                secondDataSectorNotZero = new byte[2048];
                                Array.Copy(cmdBuf, 0, secondDataSectorNotZero, 0, 2048);
                            }
                        }

                        var ps2Ms = new MemoryStream();

                        for (uint p = 0; p < 12; p++)
                        {
                            sense = dev.ReadCd(out cmdBuf, out _, p, 2324, 1, MmcSectorTypes.Mode2, false, false,
                                               true, MmcHeaderCodes.None, true, true, MmcErrorField.None,
                                               MmcSubchannel.None, dev.Timeout, out _);

                            if (sense || dev.Error)
                            {
                                break;
                            }

                            ps2Ms.Write(cmdBuf, 0, 2048);
                        }

                        if (ps2Ms.Length == 0x6000)
                        {
                            ps2BootSectors = ps2Ms.ToArray();
                        }
                    }
                    else
                    {
                        sense = dev.ReadCd(out cmdBuf, out _, 0, 2048, 1, MmcSectorTypes.Mode1, false, false, true,
                                           MmcHeaderCodes.None, true, true, MmcErrorField.None, MmcSubchannel.None,
                                           dev.Timeout, out _);

                        if (!sense &&
                            !dev.Error)
                        {
                            sector0 = cmdBuf;

                            sense = dev.ReadCd(out cmdBuf, out _, 0, 2048, 1, MmcSectorTypes.Mode1, false, false,
                                               true, MmcHeaderCodes.None, true, true, MmcErrorField.None,
                                               MmcSubchannel.None, dev.Timeout, out _);

                            if (!sense &&
                                !dev.Error)
                            {
                                sector1 = cmdBuf;
                            }

                            sense = dev.ReadCd(out cmdBuf, out _, 0, 2048, 12, MmcSectorTypes.Mode1, false, false,
                                               true, MmcHeaderCodes.None, true, true, MmcErrorField.None,
                                               MmcSubchannel.None, dev.Timeout, out _);

                            if (!sense &&
                                !dev.Error)
                            {
                                ps2BootSectors = cmdBuf;
                            }

                            if (startOfFirstDataTrack != uint.MaxValue)
                            {
                                sense = dev.ReadCd(out cmdBuf, out _, startOfFirstDataTrack, 2048, 1,
                                                   MmcSectorTypes.Mode1, false, false, true, MmcHeaderCodes.None,
                                                   true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout,
                                                   out _);

                                if (!sense &&
                                    !dev.Error)
                                {
                                    firstDataSectorNotZero = cmdBuf;
                                }

                                sense = dev.ReadCd(out cmdBuf, out _, startOfFirstDataTrack + 1, 2048, 1,
                                                   MmcSectorTypes.Mode1, false, false, true, MmcHeaderCodes.None,
                                                   true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout,
                                                   out _);

                                if (!sense &&
                                    !dev.Error)
                                {
                                    secondDataSectorNotZero = cmdBuf;
                                }
                            }
                        }
                        else
                        {
                            goto case MediaType.DVDROM;
                        }
                    }
                }

                break;
            }

            // TODO: Check for CD-i Ready
            case MediaType.CDI: break;

            case MediaType.DVDROM:
            case MediaType.HDDVDROM:
            case MediaType.BDROM:
            case MediaType.Unknown:
                sense = dev.Read16(out cmdBuf, out _, 0, false, true, false, 0, 2048, 0, 1, false, dev.Timeout,
                                   out _);

                if (!sense &&
                    !dev.Error)
                {
                    sector0 = cmdBuf;

                    sense = dev.Read16(out cmdBuf, out _, 0, false, true, false, 1, 2048, 0, 1, false, dev.Timeout,
                                       out _);

                    if (!sense &&
                        !dev.Error)
                    {
                        sector1 = cmdBuf;
                    }

                    sense = dev.Read16(out cmdBuf, out _, 0, false, true, false, 0, 2048, 0, 12, false, dev.Timeout,
                                       out _);

                    if (!sense &&
                        !dev.Error &&
                        cmdBuf.Length == 0x6000)
                    {
                        ps2BootSectors = cmdBuf;
                    }
                }
                else
                {
                    sense = dev.Read12(out cmdBuf, out _, 0, false, true, false, false, 0, 2048, 0, 1, false,
                                       dev.Timeout, out _);

                    if (!sense &&
                        !dev.Error)
                    {
                        sector0 = cmdBuf;

                        sense = dev.Read12(out cmdBuf, out _, 0, false, true, false, false, 1, 2048, 0, 1, false,
                                           dev.Timeout, out _);

                        if (!sense &&
                            !dev.Error)
                        {
                            sector1 = cmdBuf;
                        }

                        sense = dev.Read12(out cmdBuf, out _, 0, false, true, false, false, 0, 2048, 0, 12, false,
                                           dev.Timeout, out _);

                        if (!sense &&
                            !dev.Error &&
                            cmdBuf.Length == 0x6000)
                        {
                            ps2BootSectors = cmdBuf;
                        }
                    }
                    else
                    {
                        sense = dev.Read10(out cmdBuf, out _, 0, false, true, false, false, 0, 2048, 0, 1,
                                           dev.Timeout, out _);

                        if (!sense &&
                            !dev.Error)
                        {
                            sector0 = cmdBuf;

                            sense = dev.Read10(out cmdBuf, out _, 0, false, true, false, false, 1, 2048, 0, 1,
                                               dev.Timeout, out _);

                            if (!sense &&
                                !dev.Error)
                            {
                                sector1 = cmdBuf;
                            }

                            sense = dev.Read10(out cmdBuf, out _, 0, false, true, false, false, 0, 2048, 0, 12,
                                               dev.Timeout, out _);

                            if (!sense &&
                                !dev.Error &&
                                cmdBuf.Length == 0x6000)
                            {
                                ps2BootSectors = cmdBuf;
                            }
                        }
                        else
                        {
                            sense = dev.Read6(out cmdBuf, out _, 0, 2048, 1, dev.Timeout, out _);

                            if (!sense &&
                                !dev.Error)
                            {
                                sector0 = cmdBuf;

                                sense = dev.Read6(out cmdBuf, out _, 1, 2048, 1, dev.Timeout, out _);

                                if (!sense &&
                                    !dev.Error)
                                {
                                    sector1 = cmdBuf;
                                }

                                sense = dev.Read6(out cmdBuf, out _, 0, 2048, 12, dev.Timeout, out _);

                                if (!sense &&
                                    !dev.Error &&
                                    cmdBuf.Length == 0x6000)
                                {
                                    ps2BootSectors = cmdBuf;
                                }
                            }
                        }
                    }
                }

                break;

            // Recordables will not be checked
            case MediaType.CDR:
            case MediaType.CDRW:
            case MediaType.CDMRW:
            case MediaType.DDCDR:
            case MediaType.DDCDRW:
            case MediaType.DVDR:
            case MediaType.DVDRW:
            case MediaType.DVDPR:
            case MediaType.DVDPRW:
            case MediaType.DVDPRWDL:
            case MediaType.DVDRDL:
            case MediaType.DVDPRDL:
            case MediaType.DVDRAM:
            case MediaType.DVDRWDL:
            case MediaType.DVDDownload:
            case MediaType.HDDVDRAM:
            case MediaType.HDDVDR:
            case MediaType.HDDVDRW:
            case MediaType.HDDVDRDL:
            case MediaType.HDDVDRWDL:
            case MediaType.BDR:
            case MediaType.BDRE:
            case MediaType.BDRXL:
            case MediaType.BDREXL: return;
            }

            if (sector0 == null)
            {
                return;
            }

            switch (mediaType)
            {
            case MediaType.CD:
            case MediaType.CDDA:
            case MediaType.CDPLUS:
            case MediaType.CDROM:
            case MediaType.CDROMXA:
                // TODO: CDTV requires reading the filesystem, searching for a file called "/CDTV.TM"
                // TODO: CD32 requires reading the filesystem, searching for a file called "/CD32.TM"
                // TODO: Neo-Geo CD requires reading the filesystem and checking that the file "/IPL.TXT" is correct
                // TODO: Pippin requires interpreting Apple Partition Map, reading HFS and checking for Pippin signatures
            {
                if (CD.DecodeIPBin(sector0).HasValue)
                {
                    mediaType = MediaType.MEGACD;

                    return;
                }

                if (Saturn.DecodeIPBin(sector0).HasValue)
                {
                    mediaType = MediaType.SATURNCD;
                }

                // Are GDR detectable ???
                if (Dreamcast.DecodeIPBin(sector0).HasValue)
                {
                    mediaType = MediaType.GDROM;
                }

                if (ps2BootSectors != null &&
                    ps2BootSectors.Length == 0x6000)
                {
                    // The decryption key is applied as XOR. As first byte is originally always NULL, it gives us the key :)
                    byte decryptByte = ps2BootSectors[0];

                    for (int i = 0; i < 0x6000; i++)
                    {
                        ps2BootSectors[i] ^= decryptByte;
                    }

                    string ps2BootSectorsHash = Sha256Context.Data(ps2BootSectors, out _);

                    DicConsole.DebugWriteLine("Media-info Command", "PlayStation 2 boot sectors SHA256: {0}",
                                              ps2BootSectorsHash);

                    if (ps2BootSectorsHash == PS2_PAL_HASH ||
                        ps2BootSectorsHash == PS2_NTSC_HASH ||
                        ps2BootSectorsHash == PS2_JAPANESE_HASH)
                    {
                        mediaType = MediaType.PS2CD;
                    }
                }

                if (sector0 != null)
                {
                    byte[] syncBytes = new byte[7];
                    Array.Copy(sector0, 0, syncBytes, 0, 7);

                    if (_operaId.SequenceEqual(syncBytes))
                    {
                        mediaType = MediaType.ThreeDO;
                    }

                    if (_fmTownsBootId.SequenceEqual(syncBytes))
                    {
                        mediaType = MediaType.FMTOWNS;
                    }
                }

                if (playdia1 != null &&
                    playdia2 != null)
                {
                    byte[] pd1 = new byte[_playdiaCopyright.Length];
                    byte[] pd2 = new byte[_playdiaCopyright.Length];

                    Array.Copy(playdia1, 38, pd1, 0, pd1.Length);
                    Array.Copy(playdia2, 0, pd2, 0, pd1.Length);

                    if (_playdiaCopyright.SequenceEqual(pd1) &&
                        _playdiaCopyright.SequenceEqual(pd2))
                    {
                        mediaType = MediaType.Playdia;
                    }
                }

                if (secondDataSectorNotZero != null)
                {
                    byte[] pce = new byte[_pcEngineSignature.Length];
                    Array.Copy(secondDataSectorNotZero, 32, pce, 0, pce.Length);

                    if (_pcEngineSignature.SequenceEqual(pce))
                    {
                        mediaType = MediaType.SuperCDROM2;
                    }
                }

                if (firstDataSectorNotZero != null)
                {
                    byte[] pcfx = new byte[_pcFxSignature.Length];
                    Array.Copy(firstDataSectorNotZero, 0, pcfx, 0, pcfx.Length);

                    if (_pcFxSignature.SequenceEqual(pcfx))
                    {
                        mediaType = MediaType.PCFX;
                    }
                }

                if (firstTrackSecondSessionAudio != null)
                {
                    byte[] jaguar = new byte[_atariSignature.Length];

                    for (int i = 0; i + jaguar.Length <= firstTrackSecondSessionAudio.Length; i += 2)
                    {
                        Array.Copy(firstTrackSecondSessionAudio, i, jaguar, 0, jaguar.Length);

                        if (!_atariSignature.SequenceEqual(jaguar))
                        {
                            continue;
                        }

                        mediaType = MediaType.JaguarCD;

                        break;
                    }
                }

                if (firstTrackSecondSession != null)
                {
                    if (firstTrackSecondSession.Length >= 2336)
                    {
                        byte[] milcd = new byte[2048];
                        Array.Copy(firstTrackSecondSession, 24, milcd, 0, 2048);

                        if (Dreamcast.DecodeIPBin(milcd).HasValue)
                        {
                            mediaType = MediaType.MilCD;
                        }
                    }
                }

                // TODO: Detect black and white VideoNow
                // TODO: Detect VideoNow XP
                if (IsVideoNowColor(videoNowColorFrame))
                {
                    mediaType = MediaType.VideoNowColor;
                }

                break;
            }

            // TODO: Check for CD-i Ready
            case MediaType.CDI: break;

            case MediaType.DVDROM:
            case MediaType.HDDVDROM:
            case MediaType.BDROM:
            case MediaType.Unknown:
                // TODO: Nuon requires reading the filesystem, searching for a file called "/NUON/NUON.RUN"
                if (ps2BootSectors != null &&
                    ps2BootSectors.Length == 0x6000)
                {
                    // The decryption key is applied as XOR. As first byte is originally always NULL, it gives us the key :)
                    byte decryptByte = ps2BootSectors[0];

                    for (int i = 0; i < 0x6000; i++)
                    {
                        ps2BootSectors[i] ^= decryptByte;
                    }

                    string ps2BootSectorsHash = Sha256Context.Data(ps2BootSectors, out _);

                    DicConsole.DebugWriteLine("Media-info Command", "PlayStation 2 boot sectors SHA256: {0}",
                                              ps2BootSectorsHash);

                    if (ps2BootSectorsHash == PS2_PAL_HASH ||
                        ps2BootSectorsHash == PS2_NTSC_HASH ||
                        ps2BootSectorsHash == PS2_JAPANESE_HASH)
                    {
                        mediaType = MediaType.PS2DVD;
                    }
                }

                if (sector1 != null)
                {
                    byte[] tmp = new byte[_ps3Id.Length];
                    Array.Copy(sector1, 0, tmp, 0, tmp.Length);

                    if (tmp.SequenceEqual(_ps3Id))
                    {
                        switch (mediaType)
                        {
                        case MediaType.BDROM:
                            mediaType = MediaType.PS3BD;

                            break;

                        case MediaType.DVDROM:
                            mediaType = MediaType.PS3DVD;

                            break;
                        }
                    }

                    tmp = new byte[_ps4Id.Length];
                    Array.Copy(sector1, 512, tmp, 0, tmp.Length);

                    if (tmp.SequenceEqual(_ps4Id) &&
                        mediaType == MediaType.BDROM)
                    {
                        mediaType = MediaType.PS4BD;
                    }
                }

                // TODO: Identify discs that require reading tracks (PC-FX, PlayStation, Sega, etc)
                break;
            }
        }