// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename       : ATA.cs
// Author(s)      : Natalia Portillo <claunia@claunia.com>
//
// Component      : Core algorithms.
//
// --[ Description ] ----------------------------------------------------------
//
//     Creates reports from ATA devices.
//
// --[ License ] --------------------------------------------------------------
//
//     This program is free software: you can redistribute it and/or modify
//     it under the terms of the GNU General Public License as
//     published by the Free Software Foundation, either version 3 of the
//     License, or (at your option) any later version.
//
//     This program is distributed in the hope that it will be useful,
//     but WITHOUT ANY WARRANTY; without even the implied warranty of
//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//     GNU General Public License for more details.
//
//     You should have received a copy of the GNU General Public License
//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2026 Natalia Portillo
// ****************************************************************************/

// ReSharper disable InlineOutVariableDeclaration

using System;
using System.Linq;
using System.Threading;
using Aaru.CommonTypes.Metadata;
using Aaru.Decoders.CD;
using Aaru.Decoders.SCSI;
using Aaru.Devices;
using Aaru.Logging;

namespace Aaru.Core.Devices.Report;

public sealed partial class DeviceReport
{
    /// <summary>Tries and checks reading a GD-ROM disc using the swap disc trick and adds the result to a device report</summary>
    /// <param name="report">Device report</param>
    public void ReportGdRomSwapTrick(ref CommonTypes.Metadata.DeviceReport report)
    {
        report.GdRomSwapDiscCapabilities = new GdRomSwapDiscCapabilities();

        var pressedKey = new ConsoleKeyInfo();

        while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N)
        {
            AaruLogging.Write(Localization.Core
                                          .Have_you_previously_tried_with_a_GD_ROM_disc_and_did_the_computer_hang_or_crash_Q);

            pressedKey = Console.ReadKey();
            AaruLogging.WriteLine();
        }

        if(pressedKey.Key == ConsoleKey.Y)
        {
            report.GdRomSwapDiscCapabilities.TestCrashed = true;

            return;
        }

        AaruLogging.WriteLine(Localization.Core.Ejecting_disc);

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

        AaruLogging.WriteLine(Localization.Core.Please_insert_trap_disc_inside);
        AaruLogging.WriteLine(Localization.Core.Press_any_key_to_continue);
        Console.ReadLine();

        AaruLogging.WriteLine(Localization.Core.Sending_READ_FULL_TOC_to_the_device);

        var                retries = 0;
        bool               sense;
        byte[]             buffer;
        ReadOnlySpan<byte> senseBuffer;

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

            if(!sense) break;

            DecodedSense? decodedSense = Sense.Decode(senseBuffer);

            if(decodedSense is not { ASC: 0x04, ASCQ: 0x01 }) break;

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

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

        if(sense)
        {
            AaruLogging.WriteLine(Localization.Core.READ_FULL_TOC_failed);
            AaruLogging.Debug(GDROM_MODULE_NAME, "{0}", Sense.PrettifySense(senseBuffer.ToArray()));

            report.GdRomSwapDiscCapabilities.RecognizedSwapDisc = false;
            report.GdRomSwapDiscCapabilities.TestCrashed        = false;

            return;
        }

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

        if(decodedToc is null)
        {
            AaruLogging.WriteLine(Localization.Core.Could_not_decode_TOC);

            report.GdRomSwapDiscCapabilities.RecognizedSwapDisc = false;
            report.GdRomSwapDiscCapabilities.TestCrashed        = false;

            return;
        }

        // Guaranteed to never fall into default
        FullTOC.CDFullTOC toc = decodedToc ?? default(FullTOC.CDFullTOC);

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

        if(leadOutTrack.POINT != 0xA2)
        {
            AaruLogging.WriteLine(Localization.Core.Cannot_find_lead_out);

            report.GdRomSwapDiscCapabilities.RecognizedSwapDisc = false;
            report.GdRomSwapDiscCapabilities.TestCrashed        = false;

            return;
        }

        int min         = 0, sec, frame;
        var tocIsNotBcd = false;

        report.GdRomSwapDiscCapabilities.SwapDiscLeadOutPMIN  = leadOutTrack.PMIN;
        report.GdRomSwapDiscCapabilities.SwapDiscLeadOutPSEC  = leadOutTrack.PSEC;
        report.GdRomSwapDiscCapabilities.SwapDiscLeadOutPFRAM = leadOutTrack.PFRAME;

        switch(leadOutTrack.PMIN)
        {
            case 122:
                tocIsNotBcd = true;

                break;
            case >= 0xA0:
                min               += 90;
                leadOutTrack.PMIN -= 0x90;

                break;
        }

        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;

        AaruLogging.WriteLine(Localization.Core.Trap_disc_shows_0_sectors, sectors);

        if(sectors < 450000)
        {
            AaruLogging.WriteLine(Localization.Core.Trap_disc_doesnt_have_enough_sectors);

            report.GdRomSwapDiscCapabilities.RecognizedSwapDisc = false;
            report.GdRomSwapDiscCapabilities.TestCrashed        = false;

            return;
        }

        report.GdRomSwapDiscCapabilities.RecognizedSwapDisc = true;

        AaruLogging.WriteLine(Localization.Core.Stopping_motor);

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

        AaruLogging.WriteLine(Localization.Core.Please_MANUALLY_get_the_trap_disc_out_and_put_the_GD_ROM_disc_inside);
        AaruLogging.WriteLine(Localization.Core.Press_any_key_to_continue);
        Console.ReadLine();

        AaruLogging.WriteLine(Localization.Core.Waiting_5_seconds);
        Thread.Sleep(5000);

        AaruLogging.WriteLine(Localization.Core.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 is not { ASC: 0x04, ASCQ: 0x01 }) break;
        } while(retries < 25);

        if(sense)
        {
            AaruLogging.WriteLine(Localization.Core.READ_FULL_TOC_failed);
            AaruLogging.Debug(GDROM_MODULE_NAME, "{0}", Sense.PrettifySense(senseBuffer.ToArray()));

            report.GdRomSwapDiscCapabilities.RecognizedSwapDisc = false;
            report.GdRomSwapDiscCapabilities.TestCrashed        = false;

            return;
        }

        decodedToc = FullTOC.Decode(buffer);

        if(decodedToc is null)
        {
            AaruLogging.WriteLine(Localization.Core.Could_not_decode_TOC);

            report.GdRomSwapDiscCapabilities.RecognizedSwapDisc = false;
            report.GdRomSwapDiscCapabilities.TestCrashed        = false;

            return;
        }

        // Guaranteed to never fall into default
        toc = decodedToc ?? default(FullTOC.CDFullTOC);

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

        if(newLeadOutTrack.POINT != 0xA2)
        {
            AaruLogging.WriteLine(Localization.Core.Cannot_find_lead_out);

            report.GdRomSwapDiscCapabilities.RecognizedSwapDisc = false;
            report.GdRomSwapDiscCapabilities.TestCrashed        = false;

            return;
        }

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

        if(newLeadOutTrack.PMIN   != leadOutTrack.PMIN ||
           newLeadOutTrack.PSEC   != leadOutTrack.PSEC ||
           newLeadOutTrack.PFRAME != leadOutTrack.PFRAME)
        {
            AaruLogging.WriteLine(Localization.Core
                                              .Lead_out_has_changed_this_drive_does_not_support_hot_swapping_discs);

            report.GdRomSwapDiscCapabilities.RecognizedSwapDisc = false;
            report.GdRomSwapDiscCapabilities.TestCrashed        = false;

            return;
        }

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

        AaruLogging.Write(Localization.Core.Reading_LBA_zero);

        report.GdRomSwapDiscCapabilities.Lba0Readable = !_dev.ReadCd(out byte[] lba0Buffer,
                                                                     out ReadOnlySpan<byte> lba0Sense,
                                                                     0,
                                                                     2352,
                                                                     1,
                                                                     MmcSectorTypes.AllTypes,
                                                                     false,
                                                                     false,
                                                                     true,
                                                                     MmcHeaderCodes.AllHeaders,
                                                                     true,
                                                                     true,
                                                                     MmcErrorField.None,
                                                                     MmcSubchannel.None,
                                                                     _dev.Timeout,
                                                                     out _);

        report.GdRomSwapDiscCapabilities.Lba0Data         = lba0Buffer;
        report.GdRomSwapDiscCapabilities.Lba0Sense        = lba0Sense.ToArray();
        report.GdRomSwapDiscCapabilities.Lba0DecodedSense = Sense.PrettifySense(lba0Sense);

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba0Readable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_zero_as_audio_scrambled);

        report.GdRomSwapDiscCapabilities.Lba0ScrambledReadable = !_dev.ReadCd(out byte[] lba0ScrambledBuffer,
                                                                              out ReadOnlySpan<byte> lba0ScrambledSense,
                                                                              0,
                                                                              2352,
                                                                              1,
                                                                              MmcSectorTypes.Cdda,
                                                                              false,
                                                                              false,
                                                                              false,
                                                                              MmcHeaderCodes.None,
                                                                              true,
                                                                              false,
                                                                              MmcErrorField.None,
                                                                              MmcSubchannel.None,
                                                                              _dev.Timeout,
                                                                              out _);

        report.GdRomSwapDiscCapabilities.Lba0ScrambledData         = lba0ScrambledBuffer;
        report.GdRomSwapDiscCapabilities.Lba0ScrambledSense        = lba0ScrambledSense.ToArray();
        report.GdRomSwapDiscCapabilities.Lba0ScrambledDecodedSense = Sense.PrettifySense(lba0ScrambledSense);

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba0ScrambledReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_100000_as_audio);
        uint cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba100000AudioReadable = !_dev.ReadCd(out byte[] lba100000AudioBuffer,
                                                                          out ReadOnlySpan<byte>
                                                                                  lba100000AudioSenseBuffer,
                                                                          100000,
                                                                          2352,
                                                                          cluster,
                                                                          MmcSectorTypes.Cdda,
                                                                          false,
                                                                          false,
                                                                          false,
                                                                          MmcHeaderCodes.None,
                                                                          true,
                                                                          false,
                                                                          MmcErrorField.None,
                                                                          MmcSubchannel.None,
                                                                          _dev.Timeout,
                                                                          out _);

            report.GdRomSwapDiscCapabilities.Lba100000AudioData  = lba100000AudioBuffer;
            report.GdRomSwapDiscCapabilities.Lba100000AudioSense = lba100000AudioSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba100000AudioDecodedSense =
                Sense.PrettifySense(lba100000AudioSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba100000AudioReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba100000AudioReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba100000AudioReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_50000_as_audio);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba50000AudioReadable = !_dev.ReadCd(out byte[] lba50000AudioBuffer,
                                                                         out ReadOnlySpan<byte>
                                                                                 lba50000AudioSenseBuffer,
                                                                         50000,
                                                                         2352,
                                                                         cluster,
                                                                         MmcSectorTypes.Cdda,
                                                                         false,
                                                                         false,
                                                                         false,
                                                                         MmcHeaderCodes.None,
                                                                         true,
                                                                         false,
                                                                         MmcErrorField.None,
                                                                         MmcSubchannel.None,
                                                                         _dev.Timeout,
                                                                         out _);

            report.GdRomSwapDiscCapabilities.Lba50000AudioData  = lba50000AudioBuffer;
            report.GdRomSwapDiscCapabilities.Lba50000AudioSense = lba50000AudioSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba50000AudioDecodedSense =
                Sense.PrettifySense(lba50000AudioSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba50000AudioReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba50000AudioReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba50000AudioReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_450000_as_audio);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba450000AudioReadable = !_dev.ReadCd(out byte[] lba450000AudioBuffer,
                                                                          out ReadOnlySpan<byte>
                                                                                  lba450000AudioSenseBuffer,
                                                                          450000,
                                                                          2352,
                                                                          cluster,
                                                                          MmcSectorTypes.Cdda,
                                                                          false,
                                                                          false,
                                                                          false,
                                                                          MmcHeaderCodes.None,
                                                                          true,
                                                                          false,
                                                                          MmcErrorField.None,
                                                                          MmcSubchannel.None,
                                                                          _dev.Timeout,
                                                                          out _);

            report.GdRomSwapDiscCapabilities.Lba450000AudioData  = lba450000AudioBuffer;
            report.GdRomSwapDiscCapabilities.Lba450000AudioSense = lba450000AudioSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba450000AudioDecodedSense =
                Sense.PrettifySense(lba450000AudioSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba450000AudioReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba450000AudioReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba450000AudioReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_400000_as_audio);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba400000AudioReadable = !_dev.ReadCd(out byte[] lba400000AudioBuffer,
                                                                          out ReadOnlySpan<byte>
                                                                                  lba400000AudioSenseBuffer,
                                                                          400000,
                                                                          2352,
                                                                          cluster,
                                                                          MmcSectorTypes.Cdda,
                                                                          false,
                                                                          false,
                                                                          false,
                                                                          MmcHeaderCodes.None,
                                                                          true,
                                                                          false,
                                                                          MmcErrorField.None,
                                                                          MmcSubchannel.None,
                                                                          _dev.Timeout,
                                                                          out _);

            report.GdRomSwapDiscCapabilities.Lba400000AudioData  = lba400000AudioBuffer;
            report.GdRomSwapDiscCapabilities.Lba400000AudioSense = lba400000AudioSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba400000AudioDecodedSense =
                Sense.PrettifySense(lba400000AudioSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba400000AudioReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba400000AudioReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba400000AudioReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_45000_as_audio);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba45000AudioReadable = !_dev.ReadCd(out byte[] lba45000AudioBuffer,
                                                                         out ReadOnlySpan<byte>
                                                                                 lba45000AudioSenseBuffer,
                                                                         45000,
                                                                         2352,
                                                                         cluster,
                                                                         MmcSectorTypes.Cdda,
                                                                         false,
                                                                         false,
                                                                         false,
                                                                         MmcHeaderCodes.None,
                                                                         true,
                                                                         false,
                                                                         MmcErrorField.None,
                                                                         MmcSubchannel.None,
                                                                         _dev.Timeout,
                                                                         out _);

            report.GdRomSwapDiscCapabilities.Lba45000AudioData  = lba45000AudioBuffer;
            report.GdRomSwapDiscCapabilities.Lba45000AudioSense = lba45000AudioSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba45000AudioDecodedSense =
                Sense.PrettifySense(lba45000AudioSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba45000AudioReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba45000AudioReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba45000AudioReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_44990_as_audio);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba44990AudioReadable = !_dev.ReadCd(out byte[] lba44990AudioBuffer,
                                                                         out ReadOnlySpan<byte>
                                                                                 lba44990AudioSenseBuffer,
                                                                         44990,
                                                                         2352,
                                                                         cluster,
                                                                         MmcSectorTypes.Cdda,
                                                                         false,
                                                                         false,
                                                                         false,
                                                                         MmcHeaderCodes.None,
                                                                         true,
                                                                         false,
                                                                         MmcErrorField.None,
                                                                         MmcSubchannel.None,
                                                                         _dev.Timeout,
                                                                         out _);

            report.GdRomSwapDiscCapabilities.Lba44990AudioData  = lba44990AudioBuffer;
            report.GdRomSwapDiscCapabilities.Lba44990AudioSense = lba44990AudioSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba44990AudioDecodedSense =
                Sense.PrettifySense(lba44990AudioSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba44990AudioReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba44990AudioReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba44990AudioReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_100000_as_audio_with_PQ_subchannel);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba100000AudioPqReadable = !_dev.ReadCd(out byte[] lba100000AudioPqBuffer,
                                                                            out ReadOnlySpan<byte>
                                                                                lba100000AudioPqSenseBuffer,
                                                                            100000,
                                                                            2368,
                                                                            cluster,
                                                                            MmcSectorTypes.Cdda,
                                                                            false,
                                                                            false,
                                                                            false,
                                                                            MmcHeaderCodes.None,
                                                                            true,
                                                                            false,
                                                                            MmcErrorField.None,
                                                                            MmcSubchannel.Q16,
                                                                            _dev.Timeout,
                                                                            out _);

            report.GdRomSwapDiscCapabilities.Lba100000AudioPqData  = lba100000AudioPqBuffer;
            report.GdRomSwapDiscCapabilities.Lba100000AudioPqSense = lba100000AudioPqSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba100000AudioPqDecodedSense =
                Sense.PrettifySense(lba100000AudioPqSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba100000AudioPqReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba100000AudioPqReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba100000AudioPqReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_50000_as_audio_with_PQ_subchannel);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba50000AudioPqReadable = !_dev.ReadCd(out byte[] lba50000AudioPqBuffer,
                                                                           out ReadOnlySpan<byte>
                                                                                   lba50000AudioPqSenseBuffer,
                                                                           50000,
                                                                           2368,
                                                                           cluster,
                                                                           MmcSectorTypes.Cdda,
                                                                           false,
                                                                           false,
                                                                           false,
                                                                           MmcHeaderCodes.None,
                                                                           true,
                                                                           false,
                                                                           MmcErrorField.None,
                                                                           MmcSubchannel.Q16,
                                                                           _dev.Timeout,
                                                                           out _);

            report.GdRomSwapDiscCapabilities.Lba50000AudioPqData  = lba50000AudioPqBuffer;
            report.GdRomSwapDiscCapabilities.Lba50000AudioPqSense = lba50000AudioPqSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba50000AudioPqDecodedSense =
                Sense.PrettifySense(lba50000AudioPqSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba50000AudioPqReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba50000AudioPqReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba50000AudioPqReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_450000_as_audio_with_PQ_subchannel);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba450000AudioPqReadable = !_dev.ReadCd(out byte[] lba450000AudioPqBuffer,
                                                                            out ReadOnlySpan<byte>
                                                                                lba450000AudioPqSenseBuffer,
                                                                            450000,
                                                                            2368,
                                                                            cluster,
                                                                            MmcSectorTypes.Cdda,
                                                                            false,
                                                                            false,
                                                                            false,
                                                                            MmcHeaderCodes.None,
                                                                            true,
                                                                            false,
                                                                            MmcErrorField.None,
                                                                            MmcSubchannel.Q16,
                                                                            _dev.Timeout,
                                                                            out _);

            report.GdRomSwapDiscCapabilities.Lba450000AudioPqData  = lba450000AudioPqBuffer;
            report.GdRomSwapDiscCapabilities.Lba450000AudioPqSense = lba450000AudioPqSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba450000AudioPqDecodedSense =
                Sense.PrettifySense(lba450000AudioPqSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba450000AudioPqReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba450000AudioPqReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba450000AudioPqReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_400000_as_audio_with_PQ_subchannel);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba400000AudioPqReadable = !_dev.ReadCd(out byte[] lba400000AudioPqBuffer,
                                                                            out ReadOnlySpan<byte>
                                                                                lba400000AudioPqSenseBuffer,
                                                                            400000,
                                                                            2368,
                                                                            cluster,
                                                                            MmcSectorTypes.Cdda,
                                                                            false,
                                                                            false,
                                                                            false,
                                                                            MmcHeaderCodes.None,
                                                                            true,
                                                                            false,
                                                                            MmcErrorField.None,
                                                                            MmcSubchannel.Q16,
                                                                            _dev.Timeout,
                                                                            out _);

            report.GdRomSwapDiscCapabilities.Lba400000AudioPqData  = lba400000AudioPqBuffer;
            report.GdRomSwapDiscCapabilities.Lba400000AudioPqSense = lba400000AudioPqSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba400000AudioPqDecodedSense =
                Sense.PrettifySense(lba400000AudioPqSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba400000AudioPqReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba400000AudioPqReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba400000AudioPqReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_45000_as_audio_with_PQ_subchannel);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba45000AudioPqReadable = !_dev.ReadCd(out byte[] lba45000AudioPqBuffer,
                                                                           out ReadOnlySpan<byte>
                                                                                   lba45000AudioPqSenseBuffer,
                                                                           45000,
                                                                           2368,
                                                                           cluster,
                                                                           MmcSectorTypes.Cdda,
                                                                           false,
                                                                           false,
                                                                           false,
                                                                           MmcHeaderCodes.None,
                                                                           true,
                                                                           false,
                                                                           MmcErrorField.None,
                                                                           MmcSubchannel.Q16,
                                                                           _dev.Timeout,
                                                                           out _);

            report.GdRomSwapDiscCapabilities.Lba45000AudioPqData  = lba45000AudioPqBuffer;
            report.GdRomSwapDiscCapabilities.Lba45000AudioPqSense = lba45000AudioPqSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba45000AudioPqDecodedSense =
                Sense.PrettifySense(lba45000AudioPqSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba45000AudioPqReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba45000AudioPqReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba45000AudioPqReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_44990_as_audio_with_PQ_subchannel);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba44990AudioPqReadable = !_dev.ReadCd(out byte[] lba44990AudioPqBuffer,
                                                                           out ReadOnlySpan<byte>
                                                                                   lba44990AudioPqSenseBuffer,
                                                                           44990,
                                                                           2368,
                                                                           cluster,
                                                                           MmcSectorTypes.Cdda,
                                                                           false,
                                                                           false,
                                                                           false,
                                                                           MmcHeaderCodes.None,
                                                                           true,
                                                                           false,
                                                                           MmcErrorField.None,
                                                                           MmcSubchannel.Q16,
                                                                           _dev.Timeout,
                                                                           out _);

            report.GdRomSwapDiscCapabilities.Lba44990AudioPqData  = lba44990AudioPqBuffer;
            report.GdRomSwapDiscCapabilities.Lba44990AudioPqSense = lba44990AudioPqSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba44990AudioPqDecodedSense =
                Sense.PrettifySense(lba44990AudioPqSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba44990AudioPqReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba44990AudioPqReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba44990AudioPqReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_100000_as_audio_with_RW_subchannel);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba100000AudioRwReadable = !_dev.ReadCd(out byte[] lba100000AudioRwBuffer,
                                                                            out ReadOnlySpan<byte>
                                                                                lba100000AudioRwSenseBuffer,
                                                                            100000,
                                                                            2448,
                                                                            cluster,
                                                                            MmcSectorTypes.Cdda,
                                                                            false,
                                                                            false,
                                                                            false,
                                                                            MmcHeaderCodes.None,
                                                                            true,
                                                                            false,
                                                                            MmcErrorField.None,
                                                                            MmcSubchannel.Raw,
                                                                            _dev.Timeout,
                                                                            out _);

            report.GdRomSwapDiscCapabilities.Lba100000AudioRwData  = lba100000AudioRwBuffer;
            report.GdRomSwapDiscCapabilities.Lba100000AudioRwSense = lba100000AudioRwSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba100000AudioRwDecodedSense =
                Sense.PrettifySense(lba100000AudioRwSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba100000AudioRwReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba100000AudioRwReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba100000AudioRwReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_50000_as_audio_with_RW_subchannel);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba50000AudioRwReadable = !_dev.ReadCd(out byte[] lba50000AudioRwBuffer,
                                                                           out ReadOnlySpan<byte>
                                                                                   lba50000AudioRwSenseBuffer,
                                                                           50000,
                                                                           2448,
                                                                           cluster,
                                                                           MmcSectorTypes.Cdda,
                                                                           false,
                                                                           false,
                                                                           false,
                                                                           MmcHeaderCodes.None,
                                                                           true,
                                                                           false,
                                                                           MmcErrorField.None,
                                                                           MmcSubchannel.Raw,
                                                                           _dev.Timeout,
                                                                           out _);

            report.GdRomSwapDiscCapabilities.Lba50000AudioRwData  = lba50000AudioRwBuffer;
            report.GdRomSwapDiscCapabilities.Lba50000AudioRwSense = lba50000AudioRwSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba50000AudioRwDecodedSense =
                Sense.PrettifySense(lba50000AudioRwSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba50000AudioRwReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba50000AudioRwReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba50000AudioRwReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_450000_as_audio_with_RW_subchannel);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba450000AudioRwReadable = !_dev.ReadCd(out byte[] lba450000AudioRwBuffer,
                                                                            out ReadOnlySpan<byte>
                                                                                lba450000AudioRwSenseBuffer,
                                                                            450000,
                                                                            2448,
                                                                            cluster,
                                                                            MmcSectorTypes.Cdda,
                                                                            false,
                                                                            false,
                                                                            false,
                                                                            MmcHeaderCodes.None,
                                                                            true,
                                                                            false,
                                                                            MmcErrorField.None,
                                                                            MmcSubchannel.Raw,
                                                                            _dev.Timeout,
                                                                            out _);

            report.GdRomSwapDiscCapabilities.Lba450000AudioRwData  = lba450000AudioRwBuffer;
            report.GdRomSwapDiscCapabilities.Lba450000AudioRwSense = lba450000AudioRwSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba450000AudioRwDecodedSense =
                Sense.PrettifySense(lba450000AudioRwSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba450000AudioRwReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba450000AudioRwReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba450000AudioRwReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_400000_as_audio_with_RW_subchannel);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba400000AudioRwReadable = !_dev.ReadCd(out byte[] lba400000AudioRwBuffer,
                                                                            out ReadOnlySpan<byte>
                                                                                lba400000AudioRwSenseBuffer,
                                                                            400000,
                                                                            2448,
                                                                            cluster,
                                                                            MmcSectorTypes.Cdda,
                                                                            false,
                                                                            false,
                                                                            false,
                                                                            MmcHeaderCodes.None,
                                                                            true,
                                                                            false,
                                                                            MmcErrorField.None,
                                                                            MmcSubchannel.Raw,
                                                                            _dev.Timeout,
                                                                            out _);

            report.GdRomSwapDiscCapabilities.Lba400000AudioRwData  = lba400000AudioRwBuffer;
            report.GdRomSwapDiscCapabilities.Lba400000AudioRwSense = lba400000AudioRwSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba400000AudioRwDecodedSense =
                Sense.PrettifySense(lba400000AudioRwSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba400000AudioRwReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba400000AudioRwReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba400000AudioRwReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_45000_as_audio_with_RW_subchannel);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba45000AudioRwReadable = !_dev.ReadCd(out byte[] lba45000AudioRwBuffer,
                                                                           out ReadOnlySpan<byte>
                                                                                   lba45000AudioRwSenseBuffer,
                                                                           45000,
                                                                           2448,
                                                                           cluster,
                                                                           MmcSectorTypes.Cdda,
                                                                           false,
                                                                           false,
                                                                           false,
                                                                           MmcHeaderCodes.None,
                                                                           true,
                                                                           false,
                                                                           MmcErrorField.None,
                                                                           MmcSubchannel.Raw,
                                                                           _dev.Timeout,
                                                                           out _);

            report.GdRomSwapDiscCapabilities.Lba45000AudioRwData  = lba45000AudioRwBuffer;
            report.GdRomSwapDiscCapabilities.Lba45000AudioRwSense = lba45000AudioRwSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba45000AudioRwDecodedSense =
                Sense.PrettifySense(lba45000AudioRwSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba45000AudioRwReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba45000AudioRwReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba45000AudioRwReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_44990_as_audio_with_RW_subchannel);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba44990AudioRwReadable = !_dev.ReadCd(out byte[] lba44990AudioRwBuffer,
                                                                           out ReadOnlySpan<byte>
                                                                                   lba44990AudioRwSenseBuffer,
                                                                           44990,
                                                                           2448,
                                                                           cluster,
                                                                           MmcSectorTypes.Cdda,
                                                                           false,
                                                                           false,
                                                                           false,
                                                                           MmcHeaderCodes.None,
                                                                           true,
                                                                           false,
                                                                           MmcErrorField.None,
                                                                           MmcSubchannel.Raw,
                                                                           _dev.Timeout,
                                                                           out _);

            report.GdRomSwapDiscCapabilities.Lba44990AudioRwData  = lba44990AudioRwBuffer;
            report.GdRomSwapDiscCapabilities.Lba44990AudioRwSense = lba44990AudioRwSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba44990AudioRwDecodedSense =
                Sense.PrettifySense(lba44990AudioRwSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba44990AudioRwReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba44990AudioRwReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba44990AudioRwReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_100000);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba100000Readable = !_dev.ReadCd(out byte[] lba100000Buffer,
                                                                              out ReadOnlySpan<byte>
                                                                                  lba100000SenseBuffer,
                                                                              100000,
                                                                              2352,
                                                                              cluster,
                                                                              MmcSectorTypes.AllTypes,
                                                                              false,
                                                                              false,
                                                                              true,
                                                                              MmcHeaderCodes.AllHeaders,
                                                                              true,
                                                                              true,
                                                                              MmcErrorField.None,
                                                                              MmcSubchannel.None,
                                                                              _dev.Timeout,
                                                                              out _);

            report.GdRomSwapDiscCapabilities.Lba100000Data  = lba100000Buffer;
            report.GdRomSwapDiscCapabilities.Lba100000Sense = lba100000SenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba100000DecodedSense =
                Sense.PrettifySense(lba100000SenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba100000ReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba100000Readable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba100000Readable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_50000);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba50000Readable = !_dev.ReadCd(out byte[] lba50000Buffer,
                                                                             out ReadOnlySpan<byte> lba50000SenseBuffer,
                                                                             50000,
                                                                             2352,
                                                                             cluster,
                                                                             MmcSectorTypes.AllTypes,
                                                                             false,
                                                                             false,
                                                                             true,
                                                                             MmcHeaderCodes.AllHeaders,
                                                                             true,
                                                                             true,
                                                                             MmcErrorField.None,
                                                                             MmcSubchannel.None,
                                                                             _dev.Timeout,
                                                                             out _);

            report.GdRomSwapDiscCapabilities.Lba50000Data = lba50000Buffer;
            report.GdRomSwapDiscCapabilities.Lba50000Sense = lba50000SenseBuffer.ToArray();
            report.GdRomSwapDiscCapabilities.Lba50000DecodedSense = Sense.PrettifySense(lba50000SenseBuffer.ToArray());
            report.GdRomSwapDiscCapabilities.Lba50000ReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba50000Readable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba50000Readable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_450000);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba450000Readable = !_dev.ReadCd(out byte[] lba450000Buffer,
                                                                              out ReadOnlySpan<byte>
                                                                                  lba450000SenseBuffer,
                                                                              450000,
                                                                              2352,
                                                                              cluster,
                                                                              MmcSectorTypes.AllTypes,
                                                                              false,
                                                                              false,
                                                                              true,
                                                                              MmcHeaderCodes.AllHeaders,
                                                                              true,
                                                                              true,
                                                                              MmcErrorField.None,
                                                                              MmcSubchannel.None,
                                                                              _dev.Timeout,
                                                                              out _);

            report.GdRomSwapDiscCapabilities.Lba450000Data  = lba450000Buffer;
            report.GdRomSwapDiscCapabilities.Lba450000Sense = lba450000SenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba450000DecodedSense =
                Sense.PrettifySense(lba450000SenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba450000ReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba450000Readable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba450000Readable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_400000);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba400000Readable = !_dev.ReadCd(out byte[] lba400000Buffer,
                                                                              out ReadOnlySpan<byte>
                                                                                  lba400000SenseBuffer,
                                                                              400000,
                                                                              2352,
                                                                              cluster,
                                                                              MmcSectorTypes.AllTypes,
                                                                              false,
                                                                              false,
                                                                              true,
                                                                              MmcHeaderCodes.AllHeaders,
                                                                              true,
                                                                              true,
                                                                              MmcErrorField.None,
                                                                              MmcSubchannel.None,
                                                                              _dev.Timeout,
                                                                              out _);

            report.GdRomSwapDiscCapabilities.Lba400000Data  = lba400000Buffer;
            report.GdRomSwapDiscCapabilities.Lba400000Sense = lba400000SenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba400000DecodedSense =
                Sense.PrettifySense(lba400000SenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba400000ReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba400000Readable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba400000Readable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_45000);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba45000Readable = !_dev.ReadCd(out byte[] lba45000Buffer,
                                                                             out ReadOnlySpan<byte> lba45000SenseBuffer,
                                                                             45000,
                                                                             2352,
                                                                             cluster,
                                                                             MmcSectorTypes.AllTypes,
                                                                             false,
                                                                             false,
                                                                             true,
                                                                             MmcHeaderCodes.AllHeaders,
                                                                             true,
                                                                             true,
                                                                             MmcErrorField.None,
                                                                             MmcSubchannel.None,
                                                                             _dev.Timeout,
                                                                             out _);

            report.GdRomSwapDiscCapabilities.Lba45000Data = lba45000Buffer;
            report.GdRomSwapDiscCapabilities.Lba45000Sense = lba45000SenseBuffer.ToArray();
            report.GdRomSwapDiscCapabilities.Lba45000DecodedSense = Sense.PrettifySense(lba45000SenseBuffer.ToArray());
            report.GdRomSwapDiscCapabilities.Lba45000ReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba45000Readable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba45000Readable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_44990);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba44990Readable = !_dev.ReadCd(out byte[] lba44990Buffer,
                                                                             out ReadOnlySpan<byte> lba44990SenseBuffer,
                                                                             44990,
                                                                             2352,
                                                                             cluster,
                                                                             MmcSectorTypes.AllTypes,
                                                                             false,
                                                                             false,
                                                                             true,
                                                                             MmcHeaderCodes.AllHeaders,
                                                                             true,
                                                                             true,
                                                                             MmcErrorField.None,
                                                                             MmcSubchannel.None,
                                                                             _dev.Timeout,
                                                                             out _);

            report.GdRomSwapDiscCapabilities.Lba44990Data = lba44990Buffer;
            report.GdRomSwapDiscCapabilities.Lba44990Sense = lba44990SenseBuffer.ToArray();
            report.GdRomSwapDiscCapabilities.Lba44990DecodedSense = Sense.PrettifySense(lba44990SenseBuffer.ToArray());
            report.GdRomSwapDiscCapabilities.Lba44990ReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba44990Readable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba44990Readable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_100000_with_PQ_subchannel);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba100000PqReadable = !_dev.ReadCd(out byte[] lba100000PqBuffer,
                                                                                    out ReadOnlySpan<byte>
                                                                                        lba100000PqSenseBuffer,
                                                                                    100000,
                                                                                    2368,
                                                                                    cluster,
                                                                                    MmcSectorTypes.AllTypes,
                                                                                    false,
                                                                                    false,
                                                                                    true,
                                                                                    MmcHeaderCodes.AllHeaders,
                                                                                    true,
                                                                                    true,
                                                                                    MmcErrorField.None,
                                                                                    MmcSubchannel.Q16,
                                                                                    _dev.Timeout,
                                                                                    out _);

            report.GdRomSwapDiscCapabilities.Lba100000PqData  = lba100000PqBuffer;
            report.GdRomSwapDiscCapabilities.Lba100000PqSense = lba100000PqSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba100000PqDecodedSense =
                Sense.PrettifySense(lba100000PqSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba100000PqReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba100000PqReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba100000PqReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_50000_with_PQ_subchannel);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba50000PqReadable = !_dev.ReadCd(out byte[] lba50000PqBuffer,
                                                                               out ReadOnlySpan<byte>
                                                                                   lba50000PqSenseBuffer,
                                                                               50000,
                                                                               2368,
                                                                               cluster,
                                                                               MmcSectorTypes.AllTypes,
                                                                               false,
                                                                               false,
                                                                               true,
                                                                               MmcHeaderCodes.AllHeaders,
                                                                               true,
                                                                               true,
                                                                               MmcErrorField.None,
                                                                               MmcSubchannel.Q16,
                                                                               _dev.Timeout,
                                                                               out _);

            report.GdRomSwapDiscCapabilities.Lba50000PqData  = lba50000PqBuffer;
            report.GdRomSwapDiscCapabilities.Lba50000PqSense = lba50000PqSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba50000PqDecodedSense =
                Sense.PrettifySense(lba50000PqSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba50000PqReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba50000PqReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba50000PqReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_450000_with_PQ_subchannel);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba450000PqReadable = !_dev.ReadCd(out byte[] lba450000PqBuffer,
                                                                                    out ReadOnlySpan<byte>
                                                                                        lba450000PqSenseBuffer,
                                                                                    450000,
                                                                                    2368,
                                                                                    cluster,
                                                                                    MmcSectorTypes.AllTypes,
                                                                                    false,
                                                                                    false,
                                                                                    true,
                                                                                    MmcHeaderCodes.AllHeaders,
                                                                                    true,
                                                                                    true,
                                                                                    MmcErrorField.None,
                                                                                    MmcSubchannel.Q16,
                                                                                    _dev.Timeout,
                                                                                    out _);

            report.GdRomSwapDiscCapabilities.Lba450000PqData  = lba450000PqBuffer;
            report.GdRomSwapDiscCapabilities.Lba450000PqSense = lba450000PqSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba450000PqDecodedSense =
                Sense.PrettifySense(lba450000PqSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba450000PqReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba450000PqReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba450000PqReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_400000_with_PQ_subchannel);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba400000PqReadable = !_dev.ReadCd(out byte[] lba400000PqBuffer,
                                                                                    out ReadOnlySpan<byte>
                                                                                        lba400000PqSenseBuffer,
                                                                                    400000,
                                                                                    2368,
                                                                                    cluster,
                                                                                    MmcSectorTypes.AllTypes,
                                                                                    false,
                                                                                    false,
                                                                                    true,
                                                                                    MmcHeaderCodes.AllHeaders,
                                                                                    true,
                                                                                    true,
                                                                                    MmcErrorField.None,
                                                                                    MmcSubchannel.Q16,
                                                                                    _dev.Timeout,
                                                                                    out _);

            report.GdRomSwapDiscCapabilities.Lba400000PqData  = lba400000PqBuffer;
            report.GdRomSwapDiscCapabilities.Lba400000PqSense = lba400000PqSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba400000PqDecodedSense =
                Sense.PrettifySense(lba400000PqSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba400000PqReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba400000PqReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba400000PqReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_45000_with_PQ_subchannel);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba45000PqReadable = !_dev.ReadCd(out byte[] lba45000PqBuffer,
                                                                               out ReadOnlySpan<byte>
                                                                                   lba45000PqSenseBuffer,
                                                                               45000,
                                                                               2368,
                                                                               cluster,
                                                                               MmcSectorTypes.AllTypes,
                                                                               false,
                                                                               false,
                                                                               true,
                                                                               MmcHeaderCodes.AllHeaders,
                                                                               true,
                                                                               true,
                                                                               MmcErrorField.None,
                                                                               MmcSubchannel.Q16,
                                                                               _dev.Timeout,
                                                                               out _);

            report.GdRomSwapDiscCapabilities.Lba45000PqData  = lba45000PqBuffer;
            report.GdRomSwapDiscCapabilities.Lba45000PqSense = lba45000PqSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba45000PqDecodedSense =
                Sense.PrettifySense(lba45000PqSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba45000PqReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba45000PqReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba45000PqReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_44990_with_PQ_subchannel);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba44990PqReadable = !_dev.ReadCd(out byte[] lba44990PqBuffer,
                                                                               out ReadOnlySpan<byte>
                                                                                   lba44990PqSenseBuffer,
                                                                               44990,
                                                                               2368,
                                                                               cluster,
                                                                               MmcSectorTypes.AllTypes,
                                                                               false,
                                                                               false,
                                                                               true,
                                                                               MmcHeaderCodes.AllHeaders,
                                                                               true,
                                                                               true,
                                                                               MmcErrorField.None,
                                                                               MmcSubchannel.Q16,
                                                                               _dev.Timeout,
                                                                               out _);

            report.GdRomSwapDiscCapabilities.Lba44990PqData  = lba44990PqBuffer;
            report.GdRomSwapDiscCapabilities.Lba44990PqSense = lba44990PqSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba44990PqDecodedSense =
                Sense.PrettifySense(lba44990PqSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba44990PqReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba44990PqReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba44990PqReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_100000_with_RW_subchannel);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba100000RwReadable = !_dev.ReadCd(out byte[] lba100000RwBuffer,
                                                                                    out ReadOnlySpan<byte>
                                                                                        lba100000RwSenseBuffer,
                                                                                    100000,
                                                                                    2448,
                                                                                    cluster,
                                                                                    MmcSectorTypes.AllTypes,
                                                                                    false,
                                                                                    false,
                                                                                    true,
                                                                                    MmcHeaderCodes.AllHeaders,
                                                                                    true,
                                                                                    true,
                                                                                    MmcErrorField.None,
                                                                                    MmcSubchannel.Raw,
                                                                                    _dev.Timeout,
                                                                                    out _);

            report.GdRomSwapDiscCapabilities.Lba100000RwData  = lba100000RwBuffer;
            report.GdRomSwapDiscCapabilities.Lba100000RwSense = lba100000RwSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba100000RwDecodedSense =
                Sense.PrettifySense(lba100000RwSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba100000RwReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba100000RwReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba100000RwReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_50000_with_RW_subchannel);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba50000RwReadable = !_dev.ReadCd(out byte[] lba50000RwBuffer,
                                                                               out ReadOnlySpan<byte>
                                                                                   lba50000RwSenseBuffer,
                                                                               50000,
                                                                               2448,
                                                                               cluster,
                                                                               MmcSectorTypes.AllTypes,
                                                                               false,
                                                                               false,
                                                                               true,
                                                                               MmcHeaderCodes.AllHeaders,
                                                                               true,
                                                                               true,
                                                                               MmcErrorField.None,
                                                                               MmcSubchannel.Raw,
                                                                               _dev.Timeout,
                                                                               out _);

            report.GdRomSwapDiscCapabilities.Lba50000RwData  = lba50000RwBuffer;
            report.GdRomSwapDiscCapabilities.Lba50000RwSense = lba50000RwSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba50000RwDecodedSense =
                Sense.PrettifySense(lba50000RwSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba50000RwReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba50000RwReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba50000RwReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_450000_with_RW_subchannel);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba450000RwReadable = !_dev.ReadCd(out byte[] lba450000RwBuffer,
                                                                                    out ReadOnlySpan<byte>
                                                                                        lba450000RwSenseBuffer,
                                                                                    450000,
                                                                                    2448,
                                                                                    cluster,
                                                                                    MmcSectorTypes.AllTypes,
                                                                                    false,
                                                                                    false,
                                                                                    true,
                                                                                    MmcHeaderCodes.AllHeaders,
                                                                                    true,
                                                                                    true,
                                                                                    MmcErrorField.None,
                                                                                    MmcSubchannel.Raw,
                                                                                    _dev.Timeout,
                                                                                    out _);

            report.GdRomSwapDiscCapabilities.Lba450000RwData  = lba450000RwBuffer;
            report.GdRomSwapDiscCapabilities.Lba450000RwSense = lba450000RwSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba450000RwDecodedSense =
                Sense.PrettifySense(lba450000RwSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba450000RwReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba450000RwReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba450000RwReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_400000_with_RW_subchannel);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba400000RwReadable = !_dev.ReadCd(out byte[] lba400000RwBuffer,
                                                                                    out ReadOnlySpan<byte>
                                                                                        lba400000RwSenseBuffer,
                                                                                    400000,
                                                                                    2448,
                                                                                    cluster,
                                                                                    MmcSectorTypes.AllTypes,
                                                                                    false,
                                                                                    false,
                                                                                    true,
                                                                                    MmcHeaderCodes.AllHeaders,
                                                                                    true,
                                                                                    true,
                                                                                    MmcErrorField.None,
                                                                                    MmcSubchannel.Raw,
                                                                                    _dev.Timeout,
                                                                                    out _);

            report.GdRomSwapDiscCapabilities.Lba400000RwData  = lba400000RwBuffer;
            report.GdRomSwapDiscCapabilities.Lba400000RwSense = lba400000RwSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba400000RwDecodedSense =
                Sense.PrettifySense(lba400000RwSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba400000RwReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba400000RwReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba400000RwReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_45000_with_RW_subchannel);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba45000RwReadable = !_dev.ReadCd(out byte[] lba45000RwBuffer,
                                                                               out ReadOnlySpan<byte>
                                                                                   lba45000RwSenseBuffer,
                                                                               45000,
                                                                               2448,
                                                                               cluster,
                                                                               MmcSectorTypes.AllTypes,
                                                                               false,
                                                                               false,
                                                                               true,
                                                                               MmcHeaderCodes.AllHeaders,
                                                                               true,
                                                                               true,
                                                                               MmcErrorField.None,
                                                                               MmcSubchannel.Raw,
                                                                               _dev.Timeout,
                                                                               out _);

            report.GdRomSwapDiscCapabilities.Lba45000RwData  = lba45000RwBuffer;
            report.GdRomSwapDiscCapabilities.Lba45000RwSense = lba45000RwSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba45000RwDecodedSense =
                Sense.PrettifySense(lba45000RwSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba45000RwReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba45000RwReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba45000RwReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        AaruLogging.Write(Localization.Core.Reading_LBA_44990_with_RW_subchannel);
        cluster = 16;

        while(true)
        {
            report.GdRomSwapDiscCapabilities.Lba44990RwReadable = !_dev.ReadCd(out byte[] lba44990RwBuffer,
                                                                               out ReadOnlySpan<byte>
                                                                                   lba44990RwSenseBuffer,
                                                                               44990,
                                                                               2448,
                                                                               cluster,
                                                                               MmcSectorTypes.AllTypes,
                                                                               false,
                                                                               false,
                                                                               true,
                                                                               MmcHeaderCodes.AllHeaders,
                                                                               true,
                                                                               true,
                                                                               MmcErrorField.None,
                                                                               MmcSubchannel.Raw,
                                                                               _dev.Timeout,
                                                                               out _);

            report.GdRomSwapDiscCapabilities.Lba44990RwData  = lba44990RwBuffer;
            report.GdRomSwapDiscCapabilities.Lba44990RwSense = lba44990RwSenseBuffer.ToArray();

            report.GdRomSwapDiscCapabilities.Lba44990RwDecodedSense =
                Sense.PrettifySense(lba44990RwSenseBuffer.ToArray());

            report.GdRomSwapDiscCapabilities.Lba44990RwReadableCluster = (int)cluster;

            if(report.GdRomSwapDiscCapabilities.Lba44990RwReadable) break;

            if(cluster == 1) break;

            cluster /= 2;
        }

        AaruLogging.WriteLine(report.GdRomSwapDiscCapabilities.Lba44990RwReadable
                                  ? Localization.Core.Success
                                  : Localization.Core.FAIL);

        if(!report.GdRomSwapDiscCapabilities.Lba45000Readable       &&
           !report.GdRomSwapDiscCapabilities.Lba50000Readable       &&
           !report.GdRomSwapDiscCapabilities.Lba100000Readable      &&
           !report.GdRomSwapDiscCapabilities.Lba400000Readable      &&
           !report.GdRomSwapDiscCapabilities.Lba450000Readable      &&
           !report.GdRomSwapDiscCapabilities.Lba45000AudioReadable  &&
           !report.GdRomSwapDiscCapabilities.Lba50000AudioReadable  &&
           !report.GdRomSwapDiscCapabilities.Lba100000AudioReadable &&
           !report.GdRomSwapDiscCapabilities.Lba400000AudioReadable &&
           !report.GdRomSwapDiscCapabilities.Lba450000AudioReadable)
            return;

        pressedKey = new ConsoleKeyInfo();

        while(pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N)
        {
            AaruLogging.Write(Localization.Core.Test_read_whole_high_density_area_proceed_Q);

            pressedKey = Console.ReadKey();
            AaruLogging.WriteLine();
        }

        if(pressedKey.Key == ConsoleKey.N) return;

        uint          startingSector = 45000;
        var           readAsAudio    = false;
        var           aborted        = false;
        MmcSubchannel subchannel     = MmcSubchannel.None;
        uint          blockSize      = 2352;

        if(!report.GdRomSwapDiscCapabilities.Lba45000Readable)
        {
            startingSector = 45000;
            readAsAudio    = false;
            cluster        = (uint)report.GdRomSwapDiscCapabilities.Lba45000ReadableCluster;

            if(report.GdRomSwapDiscCapabilities.Lba45000RwReadable)
                subchannel                                                          = MmcSubchannel.Raw;
            else if(report.GdRomSwapDiscCapabilities.Lba45000PqReadable) subchannel = MmcSubchannel.Q16;
        }
        else if(!report.GdRomSwapDiscCapabilities.Lba50000Readable)
        {
            startingSector = 50000;
            readAsAudio    = false;
            cluster        = (uint)report.GdRomSwapDiscCapabilities.Lba50000ReadableCluster;

            if(report.GdRomSwapDiscCapabilities.Lba50000RwReadable)
                subchannel                                                          = MmcSubchannel.Raw;
            else if(report.GdRomSwapDiscCapabilities.Lba50000PqReadable) subchannel = MmcSubchannel.Q16;
        }
        else if(!report.GdRomSwapDiscCapabilities.Lba100000Readable)
        {
            startingSector = 100000;
            readAsAudio    = false;
            cluster        = (uint)report.GdRomSwapDiscCapabilities.Lba100000ReadableCluster;

            if(report.GdRomSwapDiscCapabilities.Lba100000RwReadable)
                subchannel                                                           = MmcSubchannel.Raw;
            else if(report.GdRomSwapDiscCapabilities.Lba100000PqReadable) subchannel = MmcSubchannel.Q16;
        }
        else if(!report.GdRomSwapDiscCapabilities.Lba400000Readable)
        {
            startingSector = 400000;
            readAsAudio    = false;
            cluster        = (uint)report.GdRomSwapDiscCapabilities.Lba400000ReadableCluster;

            if(report.GdRomSwapDiscCapabilities.Lba400000RwReadable)
                subchannel                                                           = MmcSubchannel.Raw;
            else if(report.GdRomSwapDiscCapabilities.Lba400000PqReadable) subchannel = MmcSubchannel.Q16;
        }
        else if(!report.GdRomSwapDiscCapabilities.Lba450000Readable)
        {
            startingSector = 450000;
            readAsAudio    = false;
            cluster        = (uint)report.GdRomSwapDiscCapabilities.Lba450000ReadableCluster;

            if(report.GdRomSwapDiscCapabilities.Lba450000RwReadable)
                subchannel                                                           = MmcSubchannel.Raw;
            else if(report.GdRomSwapDiscCapabilities.Lba450000PqReadable) subchannel = MmcSubchannel.Q16;
        }
        else if(!report.GdRomSwapDiscCapabilities.Lba45000AudioReadable)
        {
            startingSector = 45000;
            readAsAudio    = true;
            cluster        = (uint)report.GdRomSwapDiscCapabilities.Lba45000AudioReadableCluster;

            if(report.GdRomSwapDiscCapabilities.Lba45000AudioRwReadable)
                subchannel                                                               = MmcSubchannel.Raw;
            else if(report.GdRomSwapDiscCapabilities.Lba45000AudioPqReadable) subchannel = MmcSubchannel.Q16;
        }
        else if(!report.GdRomSwapDiscCapabilities.Lba50000AudioReadable)
        {
            startingSector = 50000;
            readAsAudio    = true;
            cluster        = (uint)report.GdRomSwapDiscCapabilities.Lba50000AudioReadableCluster;

            if(report.GdRomSwapDiscCapabilities.Lba50000AudioRwReadable)
                subchannel                                                               = MmcSubchannel.Raw;
            else if(report.GdRomSwapDiscCapabilities.Lba50000AudioPqReadable) subchannel = MmcSubchannel.Q16;
        }
        else if(!report.GdRomSwapDiscCapabilities.Lba100000AudioReadable)
        {
            startingSector = 100000;
            readAsAudio    = true;
            cluster        = (uint)report.GdRomSwapDiscCapabilities.Lba100000AudioReadableCluster;

            if(report.GdRomSwapDiscCapabilities.Lba100000AudioRwReadable)
                subchannel                                                                = MmcSubchannel.Raw;
            else if(report.GdRomSwapDiscCapabilities.Lba100000AudioPqReadable) subchannel = MmcSubchannel.Q16;
        }
        else if(!report.GdRomSwapDiscCapabilities.Lba400000AudioReadable)
        {
            startingSector = 400000;
            readAsAudio    = true;
            cluster        = (uint)report.GdRomSwapDiscCapabilities.Lba400000AudioReadableCluster;

            if(report.GdRomSwapDiscCapabilities.Lba400000AudioRwReadable)
                subchannel                                                                = MmcSubchannel.Raw;
            else if(report.GdRomSwapDiscCapabilities.Lba400000AudioPqReadable) subchannel = MmcSubchannel.Q16;
        }
        else if(!report.GdRomSwapDiscCapabilities.Lba450000AudioReadable)
        {
            startingSector = 450000;
            readAsAudio    = true;
            cluster        = (uint)report.GdRomSwapDiscCapabilities.Lba450000AudioReadableCluster;

            if(report.GdRomSwapDiscCapabilities.Lba450000AudioRwReadable)
                subchannel                                                                = MmcSubchannel.Raw;
            else if(report.GdRomSwapDiscCapabilities.Lba450000AudioPqReadable) subchannel = MmcSubchannel.Q16;
        }

        Console.CancelKeyPress += (_, e) =>
        {
            e.Cancel = true;
            aborted  = true;
        };

        report.GdRomSwapDiscCapabilities.MinimumReadableSectorInHdArea = startingSector;

        switch(subchannel)
        {
            case MmcSubchannel.Raw:
                blockSize += 96;

                break;
            case MmcSubchannel.Q16:
                blockSize += 16;

                break;
        }

        byte[] lastSuccessfulPq = null;
        byte[] lastSuccessfulRw = null;
        var    trackModeChange  = false;

        AaruLogging.WriteLine();

        for(uint lba = startingSector; lba < sectors; lba += cluster)
        {
            if(aborted)
            {
                AaruLogging.WriteLine();
                AaruLogging.WriteLine(Localization.Core.Aborted);

                break;
            }

            AaruLogging.Write("\r");
            AaruLogging.Write(Localization.Core.Reading_LBA_0_of_1, lba, sectors);

            sense = readAsAudio
                        ? _dev.ReadCd(out buffer,
                                      out senseBuffer,
                                      lba,
                                      blockSize,
                                      cluster,
                                      MmcSectorTypes.Cdda,
                                      false,
                                      false,
                                      false,
                                      MmcHeaderCodes.None,
                                      true,
                                      false,
                                      MmcErrorField.None,
                                      subchannel,
                                      _dev.Timeout,
                                      out _)
                        : _dev.ReadCd(out buffer,
                                      out senseBuffer,
                                      lba,
                                      blockSize,
                                      cluster,
                                      MmcSectorTypes.AllTypes,
                                      false,
                                      false,
                                      true,
                                      MmcHeaderCodes.AllHeaders,
                                      true,
                                      true,
                                      MmcErrorField.None,
                                      subchannel,
                                      _dev.Timeout,
                                      out _);

            if(sense)
            {
                if(trackModeChange) break;

                DecodedSense? decoded = Sense.Decode(senseBuffer);

                if(decoded is not { ASC: 0x64, ASCQ: 0x00 }) break;

                trackModeChange = true;
                readAsAudio     = !readAsAudio;

                continue;
            }

            trackModeChange = false;

            switch(subchannel)
            {
                case MmcSubchannel.Raw:
                    lastSuccessfulRw = buffer;

                    break;
                case MmcSubchannel.Q16:
                    lastSuccessfulPq = buffer;

                    break;
            }

            report.GdRomSwapDiscCapabilities.MaximumReadableSectorInHdArea = lba + cluster - 1;
        }

        AaruLogging.WriteLine();

        report.GdRomSwapDiscCapabilities.MaximumReadablePqInHdArea = lastSuccessfulPq;
        report.GdRomSwapDiscCapabilities.MaximumReadableRwInHdArea = lastSuccessfulRw;
    }
}