public override int Invoke(IEnumerable <string> arguments)
        {
            List <string> extra = Options.Parse(arguments);

            if (showHelp)
            {
                Options.WriteOptionDescriptions(CommandSet.Out);
                return((int)ErrorNumber.HelpRequested);
            }

            MainClass.PrintCopyright();
            if (MainClass.Debug)
            {
                DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
            }
            if (MainClass.Verbose)
            {
                DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
            }
            Statistics.AddCommand("print-hex");

            if (extra.Count > 1)
            {
                DicConsole.ErrorWriteLine("Too many arguments.");
                return((int)ErrorNumber.UnexpectedArgumentCount);
            }

            if (extra.Count == 0)
            {
                DicConsole.ErrorWriteLine("Missing input image.");
                return((int)ErrorNumber.MissingArgument);
            }

            if (startSector is null)
            {
                DicConsole.ErrorWriteLine("Missing starting sector.");
                return((int)ErrorNumber.MissingArgument);
            }

            inputFile = extra[0];

            DicConsole.DebugWriteLine("PrintHex command", "--debug={0}", MainClass.Debug);
            DicConsole.DebugWriteLine("PrintHex command", "--input={0}", inputFile);
            DicConsole.DebugWriteLine("PrintHex command", "--length={0}", length);
            DicConsole.DebugWriteLine("PrintHex command", "--long-sectors={0}", longSectors);
            DicConsole.DebugWriteLine("PrintHex command", "--start={0}", startSector);
            DicConsole.DebugWriteLine("PrintHex command", "--verbose={0}", MainClass.Verbose);
            DicConsole.DebugWriteLine("PrintHex command", "--WidthBytes={0}", widthBytes);

            FiltersList filtersList = new FiltersList();
            IFilter     inputFilter = filtersList.GetFilter(inputFile);

            if (inputFilter == null)
            {
                DicConsole.ErrorWriteLine("Cannot open specified file.");
                return((int)ErrorNumber.CannotOpenFile);
            }

            IMediaImage inputFormat = ImageFormat.Detect(inputFilter);

            if (inputFormat == null)
            {
                DicConsole.ErrorWriteLine("Unable to recognize image format, not verifying");
                return((int)ErrorNumber.UnrecognizedFormat);
            }

            inputFormat.Open(inputFilter);

            for (ulong i = 0; i < length; i++)
            {
                DicConsole.WriteLine("Sector {0}", startSector + i);

                if (inputFormat.Info.ReadableSectorTags == null)
                {
                    DicConsole
                    .WriteLine("Requested sectors with tags, unsupported by underlying image format, printing only user data.");
                    longSectors = false;
                }
                else
                {
                    if (inputFormat.Info.ReadableSectorTags.Count == 0)
                    {
                        DicConsole
                        .WriteLine("Requested sectors with tags, unsupported by underlying image format, printing only user data.");
                        longSectors = false;
                    }
                }

                byte[] sector = longSectors
                                    ? inputFormat.ReadSectorLong(startSector.Value + i)
                                    : inputFormat.ReadSector(startSector.Value + i);

                PrintHex.PrintHexArray(sector, widthBytes);
            }

            return((int)ErrorNumber.NoError);
        }
        public override int Invoke(IEnumerable <string> arguments)
        {
            List <string> extra = Options.Parse(arguments);

            if (showHelp)
            {
                Options.WriteOptionDescriptions(CommandSet.Out);
                return((int)ErrorNumber.HelpRequested);
            }

            MainClass.PrintCopyright();
            if (MainClass.Debug)
            {
                DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
            }
            if (MainClass.Verbose)
            {
                DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
            }
            Statistics.AddCommand("media-scan");

            if (extra.Count > 1)
            {
                DicConsole.ErrorWriteLine("Too many arguments.");
                return((int)ErrorNumber.UnexpectedArgumentCount);
            }

            if (extra.Count == 0)
            {
                DicConsole.ErrorWriteLine("Missing device path.");
                return((int)ErrorNumber.MissingArgument);
            }

            devicePath = extra[0];

            DicConsole.DebugWriteLine("Media-Scan command", "--debug={0}", MainClass.Debug);
            DicConsole.DebugWriteLine("Media-Scan command", "--device={0}", devicePath);
            DicConsole.DebugWriteLine("Media-Scan command", "--ibg-log={0}", ibgLogPath);
            DicConsole.DebugWriteLine("Media-Scan command", "--mhdd-log={0}", mhddLogPath);
            DicConsole.DebugWriteLine("Media-Scan command", "--verbose={0}", MainClass.Verbose);

            if (devicePath.Length == 2 && devicePath[1] == ':' && devicePath[0] != '/' && char.IsLetter(devicePath[0]))
            {
                devicePath = "\\\\.\\" + char.ToUpper(devicePath[0]) + ':';
            }

            Device dev = new Device(devicePath);

            if (dev.Error)
            {
                DicConsole.ErrorWriteLine("Error {0} opening device.", dev.LastError);
                return((int)ErrorNumber.CannotOpenDevice);
            }

            Statistics.AddDevice(dev);

            MediaScan scanner = new MediaScan(mhddLogPath, ibgLogPath, devicePath, dev);

            scanner.UpdateStatus          += Progress.UpdateStatus;
            scanner.StoppingErrorMessage  += Progress.ErrorMessage;
            scanner.UpdateProgress        += Progress.UpdateProgress;
            scanner.PulseProgress         += Progress.PulseProgress;
            scanner.InitProgress          += Progress.InitProgress;
            scanner.EndProgress           += Progress.EndProgress;
            System.Console.CancelKeyPress += (sender, e) =>
            {
                e.Cancel = true;
                scanner.Abort();
            };
            ScanResults results = scanner.Scan();

            DicConsole.WriteLine("Took a total of {0} seconds ({1} processing commands).", results.TotalTime,
                                 results.ProcessingTime);
            DicConsole.WriteLine("Average speed: {0:F3} MiB/sec.", results.AvgSpeed);
            DicConsole.WriteLine("Fastest speed burst: {0:F3} MiB/sec.", results.MaxSpeed);
            DicConsole.WriteLine("Slowest speed burst: {0:F3} MiB/sec.", results.MinSpeed);
            DicConsole.WriteLine("Summary:");
            DicConsole.WriteLine("{0} sectors took less than 3 ms.", results.A);
            DicConsole.WriteLine("{0} sectors took less than 10 ms but more than 3 ms.", results.B);
            DicConsole.WriteLine("{0} sectors took less than 50 ms but more than 10 ms.", results.C);
            DicConsole.WriteLine("{0} sectors took less than 150 ms but more than 50 ms.", results.D);
            DicConsole.WriteLine("{0} sectors took less than 500 ms but more than 150 ms.", results.E);
            DicConsole.WriteLine("{0} sectors took more than 500 ms.", results.F);
            DicConsole.WriteLine("{0} sectors could not be read.",
                                 results.UnreadableSectors.Count);
            if (results.UnreadableSectors.Count > 0)
            {
                foreach (ulong bad in results.UnreadableSectors)
                {
                    DicConsole.WriteLine("Sector {0} could not be read", bad);
                }
            }

            DicConsole.WriteLine();

            #pragma warning disable RECS0018     // Comparison of floating point numbers with equality operator
            if (results.SeekTotal != 0 || results.SeekMin != double.MaxValue || results.SeekMax != double.MinValue)
                #pragma warning restore RECS0018 // Comparison of floating point numbers with equality operator
            {
                DicConsole.WriteLine("Testing {0} seeks, longest seek took {1:F3} ms, fastest one took {2:F3} ms. ({3:F3} ms average)",
                                     results.SeekTimes, results.SeekMax, results.SeekMin, results.SeekTotal / 1000);
            }

            dev.Close();
            return((int)ErrorNumber.NoError);
        }
        public override int Invoke(IEnumerable <string> arguments)
        {
            List <string> extra = Options.Parse(arguments);

            if (showHelp)
            {
                Options.WriteOptionDescriptions(CommandSet.Out);
                return((int)ErrorNumber.HelpRequested);
            }

            MainClass.PrintCopyright();
            if (MainClass.Debug)
            {
                DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
            }
            if (MainClass.Verbose)
            {
                DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
            }
            Statistics.AddCommand("media-info");

            if (extra.Count > 1)
            {
                DicConsole.ErrorWriteLine("Too many arguments.");
                return((int)ErrorNumber.UnexpectedArgumentCount);
            }

            if (extra.Count == 0)
            {
                DicConsole.ErrorWriteLine("Missing device path.");
                return((int)ErrorNumber.MissingArgument);
            }

            devicePath = extra[0];

            DicConsole.DebugWriteLine("Media-Info command", "--debug={0}", MainClass.Debug);
            DicConsole.DebugWriteLine("Media-Info command", "--device={0}", devicePath);
            DicConsole.DebugWriteLine("Media-Info command", "--output-prefix={0}", outputPrefix);
            DicConsole.DebugWriteLine("Media-Info command", "--verbose={0}", MainClass.Verbose);

            if (devicePath.Length == 2 && devicePath[1] == ':' && devicePath[0] != '/' && char.IsLetter(devicePath[0]))
            {
                devicePath = "\\\\.\\" + char.ToUpper(devicePath[0]) + ':';
            }

            Device dev = new Device(devicePath);

            if (dev.Error)
            {
                DicConsole.ErrorWriteLine("Error {0} opening device.", dev.LastError);
                return((int)ErrorNumber.CannotOpenDevice);
            }

            Statistics.AddDevice(dev);

            switch (dev.Type)
            {
            case DeviceType.ATA:
                DoAtaMediaInfo();
                break;

            case DeviceType.MMC:
            case DeviceType.SecureDigital:
                DoSdMediaInfo();
                break;

            case DeviceType.NVMe:
                DoNvmeMediaInfo(outputPrefix, dev);
                break;

            case DeviceType.ATAPI:
            case DeviceType.SCSI:
                DoScsiMediaInfo(outputPrefix, dev);
                break;

            default: throw new NotSupportedException("Unknown device type.");
            }

            return((int)ErrorNumber.NoError);
        }
        static void DoScsiMediaInfo(string outputPrefix, Device dev)
        {
            ScsiInfo scsiInfo = new ScsiInfo(dev);

            if (!scsiInfo.MediaInserted)
            {
                return;
            }

            if (scsiInfo.DeviceInfo.ScsiModeSense6 != null)
            {
                DataFile.WriteTo("Media-Info command", outputPrefix, "_scsi_modesense6.bin", "SCSI MODE SENSE (6)",
                                 scsiInfo.DeviceInfo.ScsiModeSense6);
            }
            if (scsiInfo.DeviceInfo.ScsiModeSense10 != null)
            {
                DataFile.WriteTo("Media-Info command", outputPrefix, "_scsi_modesense10.bin", "SCSI MODE SENSE (10)",
                                 scsiInfo.DeviceInfo.ScsiModeSense10);
            }

            switch (dev.ScsiType)
            {
            case PeripheralDeviceTypes.DirectAccess:
            case PeripheralDeviceTypes.MultiMediaDevice:
            case PeripheralDeviceTypes.OCRWDevice:
            case PeripheralDeviceTypes.OpticalDevice:
            case PeripheralDeviceTypes.SimplifiedDevice:
            case PeripheralDeviceTypes.WriteOnceDevice:
                if (scsiInfo.ReadCapacity != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readcapacity.bin", "SCSI READ CAPACITY",
                                     scsiInfo.ReadCapacity);
                }

                if (scsiInfo.ReadCapacity16 != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readcapacity16.bin",
                                     "SCSI READ CAPACITY(16)", scsiInfo.ReadCapacity16);
                }

                if (scsiInfo.Blocks != 0 && scsiInfo.BlockSize != 0)
                {
                    DicConsole.WriteLine("Media has {0} blocks of {1} bytes/each. (for a total of {2} bytes)",
                                         scsiInfo.Blocks, scsiInfo.BlockSize, scsiInfo.Blocks * scsiInfo.BlockSize);
                }

                break;

            case PeripheralDeviceTypes.SequentialAccess:
                if (scsiInfo.DensitySupport != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_ssc_reportdensitysupport_media.bin",
                                     "SSC REPORT DENSITY SUPPORT (MEDIA)", scsiInfo.DensitySupport);
                    if (scsiInfo.DensitySupportHeader.HasValue)
                    {
                        DicConsole.WriteLine("Densities supported by currently inserted media:");
                        DicConsole.WriteLine(DensitySupport.PrettifyDensity(scsiInfo.DensitySupportHeader));
                    }
                }

                if (scsiInfo.MediaTypeSupport != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix,
                                     "_ssc_reportdensitysupport_medium_media.bin",
                                     "SSC REPORT DENSITY SUPPORT (MEDIUM & MEDIA)", scsiInfo.MediaTypeSupport);
                    if (scsiInfo.MediaTypeSupportHeader.HasValue)
                    {
                        DicConsole.WriteLine("Medium types currently inserted in device:");
                        DicConsole.WriteLine(DensitySupport.PrettifyMediumType(scsiInfo.MediaTypeSupportHeader));
                    }

                    DicConsole.WriteLine(DensitySupport.PrettifyMediumType(scsiInfo.MediaTypeSupport));
                }

                break;
            }

            if (dev.ScsiType == PeripheralDeviceTypes.MultiMediaDevice)
            {
                if (scsiInfo.MmcConfiguration != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_getconfiguration_current.bin",
                                     "SCSI GET CONFIGURATION", scsiInfo.MmcConfiguration);
                }

                if (scsiInfo.RecognizedFormatLayers != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_formatlayers.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.RecognizedFormatLayers);
                }

                if (scsiInfo.WriteProtectionStatus != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_writeprotection.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.WriteProtectionStatus);
                }

                if (scsiInfo.DvdPfi != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_dvd_pfi.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.DvdPfi);

                    if (scsiInfo.DecodedPfi.HasValue)
                    {
                        DicConsole.WriteLine("PFI:\n{0}", PFI.Prettify(scsiInfo.DecodedPfi));
                    }
                }

                if (scsiInfo.DvdDmi != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_dvd_dmi.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.DvdDmi);
                    if (DMI.IsXbox(scsiInfo.DvdDmi))
                    {
                        DicConsole.WriteLine("Xbox DMI:\n{0}", DMI.PrettifyXbox(scsiInfo.DvdDmi));
                    }
                    else if (DMI.IsXbox360(scsiInfo.DvdDmi))
                    {
                        DicConsole.WriteLine("Xbox 360 DMI:\n{0}", DMI.PrettifyXbox360(scsiInfo.DvdDmi));
                    }
                }

                if (scsiInfo.DvdCmi != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_dvd_cmi.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.DvdCmi);
                    DicConsole.WriteLine("Lead-In CMI:\n{0}", CSS_CPRM.PrettifyLeadInCopyright(scsiInfo.DvdCmi));
                }

                if (scsiInfo.DvdBca != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_dvd_bca.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.DvdBca);
                }
                if (scsiInfo.DvdAacs != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_dvd_aacs.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.DvdAacs);
                }
                if (scsiInfo.DvdRamDds != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_dvdram_dds.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.DvdRamDds);
                    DicConsole.WriteLine("Disc Definition Structure:\n{0}", DDS.Prettify(scsiInfo.DvdRamDds));
                }

                if (scsiInfo.DvdRamCartridgeStatus != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_dvdram_status.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.DvdRamCartridgeStatus);
                    DicConsole.WriteLine("Medium Status:\n{0}", Cartridge.Prettify(scsiInfo.DvdRamCartridgeStatus));
                }

                if (scsiInfo.DvdRamSpareArea != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_dvdram_spare.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.DvdRamSpareArea);
                    DicConsole.WriteLine("Spare Area Information:\n{0}", Spare.Prettify(scsiInfo.DvdRamSpareArea));
                }

                if (scsiInfo.LastBorderOutRmd != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_dvd_lastrmd.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.LastBorderOutRmd);
                }

                if (scsiInfo.DvdPreRecordedInfo != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_dvd_pri.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.DvdPreRecordedInfo);
                }

                if (scsiInfo.DvdrMediaIdentifier != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_dvdr_mediaid.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.DvdrMediaIdentifier);
                }
                if (scsiInfo.DvdrPhysicalInformation != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_dvdr_pfi.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.DvdrPhysicalInformation);
                }
                if (scsiInfo.DvdPlusAdip != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_dvd+_adip.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.DvdPlusAdip);
                }

                if (scsiInfo.DvdPlusDcb != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_dvd+_dcb.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.DvdPlusDcb);
                }
                if (scsiInfo.HddvdCopyrightInformation != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_hddvd_cmi.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.HddvdCopyrightInformation);
                }
                if (scsiInfo.HddvdrMediumStatus != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_hddvdr_status.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.HddvdrMediumStatus);
                }

                if (scsiInfo.HddvdrLastRmd != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_hddvdr_lastrmd.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.HddvdrLastRmd);
                }

                if (scsiInfo.DvdrLayerCapacity != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_dvdr_layercap.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.DvdrLayerCapacity);
                }

                if (scsiInfo.DvdrDlMiddleZoneStart != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_dvd_mzs.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.DvdrDlMiddleZoneStart);
                }

                if (scsiInfo.DvdrDlJumpIntervalSize != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_dvd_jis.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.DvdrDlJumpIntervalSize);
                }

                if (scsiInfo.DvdrDlManualLayerJumpStartLba != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_dvd_manuallj.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.DvdrDlManualLayerJumpStartLba);
                }

                if (scsiInfo.DvdrDlRemapAnchorPoint != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_dvd_remapanchor.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.DvdrDlRemapAnchorPoint);
                }
                if (scsiInfo.BlurayDiscInformation != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_bd_di.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.BlurayDiscInformation);
                    DicConsole.WriteLine("Blu-ray Disc Information:\n{0}", DI.Prettify(scsiInfo.BlurayDiscInformation));
                }

                if (scsiInfo.BlurayPac != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_bd_pac.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.BlurayPac);
                }

                if (scsiInfo.BlurayBurstCuttingArea != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_bd_bca.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.BlurayBurstCuttingArea);
                    DicConsole.WriteLine("Blu-ray Burst Cutting Area:\n{0}",
                                         BCA.Prettify(scsiInfo.BlurayBurstCuttingArea));
                }

                if (scsiInfo.BlurayDds != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_bd_dds.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.BlurayDds);
                    DicConsole.WriteLine("Blu-ray Disc Definition Structure:\n{0}",
                                         Decoders.Bluray.DDS.Prettify(scsiInfo.BlurayDds));
                }

                if (scsiInfo.BlurayCartridgeStatus != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_bd_cartstatus.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.BlurayCartridgeStatus);
                    DicConsole.WriteLine("Blu-ray Cartridge Status:\n{0}",
                                         Decoders.Bluray.Cartridge.Prettify(scsiInfo.BlurayCartridgeStatus));
                }

                if (scsiInfo.BluraySpareAreaInformation != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_bd_spare.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.BluraySpareAreaInformation);
                    DicConsole.WriteLine("Blu-ray Spare Area Information:\n{0}",
                                         Decoders.Bluray.Spare.Prettify(scsiInfo.BluraySpareAreaInformation));
                }

                if (scsiInfo.BlurayRawDfl != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscstructure_bd_dfl.bin",
                                     "SCSI READ DISC STRUCTURE", scsiInfo.BlurayRawDfl);
                }

                if (scsiInfo.BlurayTrackResources != null)
                {
                    DicConsole.WriteLine("Track Resources Information:\n{0}",
                                         DiscInformation.Prettify(scsiInfo.BlurayTrackResources));
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscinformation_001b.bin",
                                     "SCSI READ DISC INFORMATION", scsiInfo.BlurayTrackResources);
                }

                if (scsiInfo.BlurayPowResources != null)
                {
                    DicConsole.WriteLine("POW Resources Information:\n{0}",
                                         DiscInformation.Prettify(scsiInfo.BlurayPowResources));
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscinformation_010b.bin",
                                     "SCSI READ DISC INFORMATION", scsiInfo.BlurayPowResources);
                }

                if (scsiInfo.Toc != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_toc.bin", "SCSI READ TOC/PMA/ATIP",
                                     scsiInfo.Toc);
                    if (scsiInfo.DecodedToc.HasValue)
                    {
                        DicConsole.WriteLine("TOC:\n{0}", TOC.Prettify(scsiInfo.DecodedToc));
                    }
                }

                if (scsiInfo.Atip != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_atip.bin", "SCSI READ TOC/PMA/ATIP",
                                     scsiInfo.Atip);
                    if (scsiInfo.DecodedAtip.HasValue)
                    {
                        DicConsole.WriteLine("ATIP:\n{0}", ATIP.Prettify(scsiInfo.DecodedAtip));
                    }
                }

                if (scsiInfo.CompactDiscInformation != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_readdiscinformation_000b.bin",
                                     "SCSI READ DISC INFORMATION", scsiInfo.CompactDiscInformation);
                    if (scsiInfo.DecodedCompactDiscInformation.HasValue)
                    {
                        DicConsole.WriteLine("Standard Disc Information:\n{0}",
                                             DiscInformation.Prettify000b(scsiInfo.DecodedCompactDiscInformation));
                    }
                }

                if (scsiInfo.Session != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_session.bin", "SCSI READ TOC/PMA/ATIP",
                                     scsiInfo.Session);
                    if (scsiInfo.DecodedSession.HasValue)
                    {
                        DicConsole.WriteLine("Session information:\n{0}", Session.Prettify(scsiInfo.DecodedSession));
                    }
                }

                if (scsiInfo.RawToc != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_rawtoc.bin", "SCSI READ TOC/PMA/ATIP",
                                     scsiInfo.RawToc);
                    if (scsiInfo.FullToc.HasValue)
                    {
                        DicConsole.WriteLine("Raw TOC:\n{0}", FullTOC.Prettify(scsiInfo.RawToc));
                    }
                }

                if (scsiInfo.Pma != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_pma.bin", "SCSI READ TOC/PMA/ATIP",
                                     scsiInfo.Pma);
                    DicConsole.WriteLine("PMA:\n{0}", PMA.Prettify(scsiInfo.Pma));
                }

                if (scsiInfo.CdTextLeadIn != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_cdtext.bin", "SCSI READ TOC/PMA/ATIP",
                                     scsiInfo.CdTextLeadIn);
                    if (scsiInfo.DecodedCdTextLeadIn.HasValue)
                    {
                        DicConsole.WriteLine("CD-TEXT on Lead-In:\n{0}",
                                             CDTextOnLeadIn.Prettify(scsiInfo.DecodedCdTextLeadIn));
                    }
                }

                if (!string.IsNullOrEmpty(scsiInfo.Mcn))
                {
                    DicConsole.WriteLine("MCN: {0}", scsiInfo.Mcn);
                }

                if (scsiInfo.Isrcs != null)
                {
                    foreach (KeyValuePair <byte, string> isrc in scsiInfo.Isrcs)
                    {
                        DicConsole.WriteLine("Track's {0} ISRC: {1}", isrc.Key, isrc.Value);
                    }
                }

                if (scsiInfo.XboxSecuritySector != null)
                {
                    DataFile.WriteTo("Media-Info command", outputPrefix, "_xbox_ss.bin", "KREON EXTRACT SS",
                                     scsiInfo.XboxSecuritySector);
                }

                if (scsiInfo.DecodedXboxSecuritySector.HasValue)
                {
                    DicConsole.WriteLine("Xbox Security Sector:\n{0}", SS.Prettify(scsiInfo.DecodedXboxSecuritySector));
                }

                if (scsiInfo.XgdInfo != null)
                {
                    DicConsole.WriteLine("Video layer 0 size: {0} sectors", scsiInfo.XgdInfo.L0Video);
                    DicConsole.WriteLine("Video layer 1 size: {0} sectors", scsiInfo.XgdInfo.L1Video);
                    DicConsole.WriteLine("Middle zone size: {0} sectors", scsiInfo.XgdInfo.MiddleZone);
                    DicConsole.WriteLine("Game data size: {0} sectors", scsiInfo.XgdInfo.GameSize);
                    DicConsole.WriteLine("Total size: {0} sectors", scsiInfo.XgdInfo.TotalSize);
                    DicConsole.WriteLine("Real layer break: {0}", scsiInfo.XgdInfo.LayerBreak);
                    DicConsole.WriteLine();
                }
            }

            if (scsiInfo.MediaSerialNumber != null)
            {
                DataFile.WriteTo("Media-Info command", outputPrefix, "_mediaserialnumber.bin",
                                 "SCSI READ MEDIA SERIAL NUMBER", scsiInfo.MediaSerialNumber);

                DicConsole.Write("Media Serial Number: ");
                for (int i = 4; i < scsiInfo.MediaSerialNumber.Length; i++)
                {
                    DicConsole.Write("{0:X2}", scsiInfo.MediaSerialNumber[i]);
                }

                DicConsole.WriteLine();
            }

            DicConsole.WriteLine("Media identified as {0}", scsiInfo.MediaType);
            Statistics.AddMedia(scsiInfo.MediaType, true);

            dev.Close();
        }
Beispiel #5
0
        public override int Invoke(IEnumerable <string> arguments)
        {
            List <string> extra = Options.Parse(arguments);

            if (showHelp)
            {
                Options.WriteOptionDescriptions(CommandSet.Out);
                return((int)ErrorNumber.HelpRequested);
            }

            MainClass.PrintCopyright();
            if (MainClass.Debug)
            {
                DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
            }
            if (MainClass.Verbose)
            {
                DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
            }
            Statistics.AddCommand("verify");

            if (extra.Count > 1)
            {
                DicConsole.ErrorWriteLine("Too many arguments.");
                return((int)ErrorNumber.UnexpectedArgumentCount);
            }

            if (extra.Count == 0)
            {
                DicConsole.ErrorWriteLine("Missing input image.");
                return((int)ErrorNumber.MissingArgument);
            }

            inputFile = extra[0];

            DicConsole.DebugWriteLine("Verify command", "--debug={0}", MainClass.Debug);
            DicConsole.DebugWriteLine("Verify command", "--input={0}", inputFile);
            DicConsole.DebugWriteLine("Verify command", "--verbose={0}", MainClass.Verbose);
            DicConsole.DebugWriteLine("Verify command", "--verify-disc={0}", verifyDisc);
            DicConsole.DebugWriteLine("Verify command", "--verify-sectors={0}", verifySectors);

            FiltersList filtersList = new FiltersList();
            IFilter     inputFilter = filtersList.GetFilter(inputFile);

            if (inputFilter == null)
            {
                DicConsole.ErrorWriteLine("Cannot open specified file.");
                return((int)ErrorNumber.CannotOpenFile);
            }

            IMediaImage inputFormat = ImageFormat.Detect(inputFilter);

            if (inputFormat == null)
            {
                DicConsole.ErrorWriteLine("Unable to recognize image format, not verifying");
                return((int)ErrorNumber.FormatNotFound);
            }

            inputFormat.Open(inputFilter);
            Statistics.AddMediaFormat(inputFormat.Format);
            Statistics.AddMedia(inputFormat.Info.MediaType, false);
            Statistics.AddFilter(inputFilter.Name);

            bool?correctImage   = null;
            long totalSectors   = 0;
            long errorSectors   = 0;
            bool?correctSectors = null;
            long unknownSectors = 0;

            IVerifiableImage        verifiableImage        = inputFormat as IVerifiableImage;
            IVerifiableSectorsImage verifiableSectorsImage = inputFormat as IVerifiableSectorsImage;

            if (verifiableImage is null && verifiableSectorsImage is null)
            {
                DicConsole.ErrorWriteLine("The specified image does not support any kind of verification");
                return((int)ErrorNumber.NotVerificable);
            }

            if (verifyDisc)
            {
                DateTime startCheck      = DateTime.UtcNow;
                bool?    discCheckStatus = verifiableImage.VerifyMediaImage();
                DateTime endCheck        = DateTime.UtcNow;

                TimeSpan checkTime = endCheck - startCheck;

                switch (discCheckStatus)
                {
                case true:
                    DicConsole.WriteLine("Disc image checksums are correct");
                    break;

                case false:
                    DicConsole.WriteLine("Disc image checksums are incorrect");
                    break;

                case null:
                    DicConsole.WriteLine("Disc image does not contain checksums");
                    break;
                }

                correctImage = discCheckStatus;
                DicConsole.VerboseWriteLine("Checking disc image checksums took {0} seconds", checkTime.TotalSeconds);
            }

            if (verifySectors)
            {
                DateTime     startCheck  = DateTime.Now;
                DateTime     endCheck    = startCheck;
                List <ulong> failingLbas = new List <ulong>();
                List <ulong> unknownLbas = new List <ulong>();

                if (inputFormat is IOpticalMediaImage opticalMediaImage)
                {
                    List <Track> inputTracks      = opticalMediaImage.Tracks;
                    ulong        currentSectorAll = 0;

                    startCheck = DateTime.UtcNow;
                    foreach (Track currentTrack in inputTracks)
                    {
                        ulong remainingSectors = currentTrack.TrackEndSector - currentTrack.TrackStartSector;
                        ulong currentSector    = 0;

                        while (remainingSectors > 0)
                        {
                            DicConsole.Write("\rChecking sector {0} of {1}, on track {2}", currentSectorAll,
                                             inputFormat.Info.Sectors, currentTrack.TrackSequence);

                            List <ulong> tempfailingLbas;
                            List <ulong> tempunknownLbas;

                            if (remainingSectors < 512)
                            {
                                opticalMediaImage.VerifySectors(currentSector, (uint)remainingSectors,
                                                                currentTrack.TrackSequence, out tempfailingLbas,
                                                                out tempunknownLbas);
                            }
                            else
                            {
                                opticalMediaImage.VerifySectors(currentSector, 512, currentTrack.TrackSequence,
                                                                out tempfailingLbas, out tempunknownLbas);
                            }

                            failingLbas.AddRange(tempfailingLbas);

                            unknownLbas.AddRange(tempunknownLbas);

                            if (remainingSectors < 512)
                            {
                                currentSector    += remainingSectors;
                                currentSectorAll += remainingSectors;
                                remainingSectors  = 0;
                            }
                            else
                            {
                                currentSector    += 512;
                                currentSectorAll += 512;
                                remainingSectors -= 512;
                            }
                        }
                    }

                    endCheck = DateTime.UtcNow;
                }
                else if (verifiableSectorsImage != null)
                {
                    ulong remainingSectors = inputFormat.Info.Sectors;
                    ulong currentSector    = 0;

                    startCheck = DateTime.UtcNow;
                    while (remainingSectors > 0)
                    {
                        DicConsole.Write("\rChecking sector {0} of {1}", currentSector, inputFormat.Info.Sectors);

                        List <ulong> tempfailingLbas;
                        List <ulong> tempunknownLbas;

                        if (remainingSectors < 512)
                        {
                            verifiableSectorsImage.VerifySectors(currentSector, (uint)remainingSectors,
                                                                 out tempfailingLbas, out tempunknownLbas);
                        }
                        else
                        {
                            verifiableSectorsImage.VerifySectors(currentSector, 512, out tempfailingLbas,
                                                                 out tempunknownLbas);
                        }

                        failingLbas.AddRange(tempfailingLbas);

                        unknownLbas.AddRange(tempunknownLbas);

                        if (remainingSectors < 512)
                        {
                            currentSector   += remainingSectors;
                            remainingSectors = 0;
                        }
                        else
                        {
                            currentSector    += 512;
                            remainingSectors -= 512;
                        }
                    }

                    endCheck = DateTime.UtcNow;
                }

                TimeSpan checkTime = endCheck - startCheck;

                DicConsole.Write("\r" + new string(' ', System.Console.WindowWidth - 1) + "\r");

                if (unknownSectors > 0)
                {
                    DicConsole.WriteLine("There is at least one sector that does not contain a checksum");
                }
                if (errorSectors > 0)
                {
                    DicConsole.WriteLine("There is at least one sector with incorrect checksum or errors");
                }
                if (unknownSectors == 0 && errorSectors == 0)
                {
                    DicConsole.WriteLine("All sector checksums are correct");
                }

                DicConsole.VerboseWriteLine("Checking sector checksums took {0} seconds", checkTime.TotalSeconds);

                if (MainClass.Verbose)
                {
                    DicConsole.VerboseWriteLine("LBAs with error:");
                    if (failingLbas.Count == (int)inputFormat.Info.Sectors)
                    {
                        DicConsole.VerboseWriteLine("\tall sectors.");
                    }
                    else
                    {
                        foreach (ulong t in failingLbas)
                        {
                            DicConsole.VerboseWriteLine("\t{0}", t);
                        }
                    }

                    DicConsole.WriteLine("LBAs without checksum:");
                    if (unknownLbas.Count == (int)inputFormat.Info.Sectors)
                    {
                        DicConsole.VerboseWriteLine("\tall sectors.");
                    }
                    else
                    {
                        foreach (ulong t in unknownLbas)
                        {
                            DicConsole.VerboseWriteLine("\t{0}", t);
                        }
                    }
                }

                DicConsole.WriteLine("Total sectors........... {0}", inputFormat.Info.Sectors);
                DicConsole.WriteLine("Total errors............ {0}", failingLbas.Count);
                DicConsole.WriteLine("Total unknowns.......... {0}", unknownLbas.Count);
                DicConsole.WriteLine("Total errors+unknowns... {0}", failingLbas.Count + unknownLbas.Count);

                totalSectors   = (long)inputFormat.Info.Sectors;
                errorSectors   = failingLbas.Count;
                unknownSectors = unknownLbas.Count;
                if (failingLbas.Count > 0)
                {
                    correctSectors = false;
                }
                else if ((ulong)unknownLbas.Count < inputFormat.Info.Sectors)
                {
                    correctSectors = true;
                }
            }

            switch (correctImage)
            {
            case null when correctSectors is null:   return((int)ErrorNumber.NotVerificable);

            case null when correctSectors == false:  return((int)ErrorNumber.BadSectorsImageNotVerified);

            case null when correctSectors == true:   return((int)ErrorNumber.CorrectSectorsImageNotVerified);

            case false when correctSectors is null:  return((int)ErrorNumber.BadImageSectorsNotVerified);

            case false when correctSectors == false: return((int)ErrorNumber.BadImageBadSectors);

            case false when correctSectors == true:  return((int)ErrorNumber.CorrectSectorsBadImage);

            case true when correctSectors is null:   return((int)ErrorNumber.CorrectImageSectorsNotVerified);

            case true when correctSectors == false:  return((int)ErrorNumber.CorrectImageBadSectors);

            case true when correctSectors == true:   return((int)ErrorNumber.NoError);
            }

            return((int)ErrorNumber.NoError);
        }
Beispiel #6
0
 internal static void DoUpdate(bool create)
 {
     Remote.UpdateMasterDatabase(create);
     Statistics.AddCommand("update");
 }
Beispiel #7
0
        public override int Invoke(IEnumerable <string> arguments)
        {
            List <string> extra = Options.Parse(arguments);

            if (showHelp)
            {
                Options.WriteOptionDescriptions(CommandSet.Out);
                return((int)ErrorNumber.HelpRequested);
            }

            MainClass.PrintCopyright();
            if (MainClass.Debug)
            {
                DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
            }
            if (MainClass.Verbose)
            {
                DicConsole.VerboseWriteLineEvent += System.Console.WriteLine;
            }
            Statistics.AddCommand("checksum");

            if (extra.Count > 1)
            {
                DicConsole.ErrorWriteLine("Too many arguments.");
                return((int)ErrorNumber.UnexpectedArgumentCount);
            }

            if (extra.Count == 0)
            {
                DicConsole.ErrorWriteLine("Missing input image.");
                return((int)ErrorNumber.MissingArgument);
            }

            inputFile = extra[0];

            DicConsole.DebugWriteLine("Checksum command", "--adler32={0}", doAdler32);
            DicConsole.DebugWriteLine("Checksum command", "--crc16={0}", doCrc16);
            DicConsole.DebugWriteLine("Checksum command", "--crc32={0}", doCrc32);
            DicConsole.DebugWriteLine("Checksum command", "--crc64={0}", doCrc64);
            DicConsole.DebugWriteLine("Checksum command", "--debug={0}", MainClass.Debug);
            DicConsole.DebugWriteLine("Checksum command", "--fletcher16={0}", doFletcher16);
            DicConsole.DebugWriteLine("Checksum command", "--fletcher32={0}", doFletcher32);
            DicConsole.DebugWriteLine("Checksum command", "--input={0}", inputFile);
            DicConsole.DebugWriteLine("Checksum command", "--md5={0}", doMd5);
            DicConsole.DebugWriteLine("Checksum command", "--ripemd160={0}", doRipemd160);
            DicConsole.DebugWriteLine("Checksum command", "--separated-tracks={0}", separatedTracks);
            DicConsole.DebugWriteLine("Checksum command", "--sha1={0}", doSha1);
            DicConsole.DebugWriteLine("Checksum command", "--sha256={0}", doSha256);
            DicConsole.DebugWriteLine("Checksum command", "--sha384={0}", doSha384);
            DicConsole.DebugWriteLine("Checksum command", "--sha512={0}", doSha512);
            DicConsole.DebugWriteLine("Checksum command", "--spamsum={0}", doSpamSum);
            DicConsole.DebugWriteLine("Checksum command", "--verbose={0}", MainClass.Verbose);
            DicConsole.DebugWriteLine("Checksum command", "--whole-disc={0}", wholeDisc);

            FiltersList filtersList = new FiltersList();
            IFilter     inputFilter = filtersList.GetFilter(inputFile);

            if (inputFilter == null)
            {
                DicConsole.ErrorWriteLine("Cannot open specified file.");
                return((int)ErrorNumber.CannotOpenFile);
            }

            IMediaImage inputFormat = ImageFormat.Detect(inputFilter);

            if (inputFormat == null)
            {
                DicConsole.ErrorWriteLine("Unable to recognize image format, not checksumming");
                return((int)ErrorNumber.UnrecognizedFormat);
            }

            inputFormat.Open(inputFilter);
            Statistics.AddMediaFormat(inputFormat.Format);
            Statistics.AddMedia(inputFormat.Info.MediaType, false);
            Statistics.AddFilter(inputFilter.Name);
            EnableChecksum enabledChecksums = new EnableChecksum();

            if (doAdler32)
            {
                enabledChecksums |= EnableChecksum.Adler32;
            }
            if (doCrc16)
            {
                enabledChecksums |= EnableChecksum.Crc16;
            }
            if (doCrc32)
            {
                enabledChecksums |= EnableChecksum.Crc32;
            }
            if (doCrc64)
            {
                enabledChecksums |= EnableChecksum.Crc64;
            }
            if (doMd5)
            {
                enabledChecksums |= EnableChecksum.Md5;
            }
            if (doRipemd160)
            {
                enabledChecksums |= EnableChecksum.Ripemd160;
            }
            if (doSha1)
            {
                enabledChecksums |= EnableChecksum.Sha1;
            }
            if (doSha256)
            {
                enabledChecksums |= EnableChecksum.Sha256;
            }
            if (doSha384)
            {
                enabledChecksums |= EnableChecksum.Sha384;
            }
            if (doSha512)
            {
                enabledChecksums |= EnableChecksum.Sha512;
            }
            if (doSpamSum)
            {
                enabledChecksums |= EnableChecksum.SpamSum;
            }
            if (doFletcher16)
            {
                enabledChecksums |= EnableChecksum.Fletcher16;
            }
            if (doFletcher32)
            {
                enabledChecksums |= EnableChecksum.Fletcher32;
            }

            Checksum mediaChecksum = null;

            switch (inputFormat)
            {
            case IOpticalMediaImage opticalInput when opticalInput.Tracks != null:
                try
                {
                    Checksum trackChecksum = null;

                    if (wholeDisc)
                    {
                        mediaChecksum = new Checksum(enabledChecksums);
                    }

                    ulong previousTrackEnd = 0;

                    List <Track> inputTracks = opticalInput.Tracks;
                    foreach (Track currentTrack in inputTracks)
                    {
                        if (currentTrack.TrackStartSector - previousTrackEnd != 0 && wholeDisc)
                        {
                            for (ulong i = previousTrackEnd + 1; i < currentTrack.TrackStartSector; i++)
                            {
                                DicConsole.Write("\rHashing track-less sector {0}", i);

                                byte[] hiddenSector = inputFormat.ReadSector(i);

                                mediaChecksum?.Update(hiddenSector);
                            }
                        }

                        DicConsole.DebugWriteLine("Checksum command",
                                                  "Track {0} starts at sector {1} and ends at sector {2}",
                                                  currentTrack.TrackSequence, currentTrack.TrackStartSector,
                                                  currentTrack.TrackEndSector);

                        if (separatedTracks)
                        {
                            trackChecksum = new Checksum(enabledChecksums);
                        }

                        ulong sectors     = currentTrack.TrackEndSector - currentTrack.TrackStartSector + 1;
                        ulong doneSectors = 0;
                        DicConsole.WriteLine("Track {0} has {1} sectors", currentTrack.TrackSequence, sectors);

                        while (doneSectors < sectors)
                        {
                            byte[] sector;

                            if (sectors - doneSectors >= SECTORS_TO_READ)
                            {
                                sector = opticalInput.ReadSectors(doneSectors, SECTORS_TO_READ,
                                                                  currentTrack.TrackSequence);
                                DicConsole.Write("\rHashings sectors {0} to {2} of track {1}", doneSectors,
                                                 currentTrack.TrackSequence, doneSectors + SECTORS_TO_READ);
                                doneSectors += SECTORS_TO_READ;
                            }
                            else
                            {
                                sector = opticalInput.ReadSectors(doneSectors, (uint)(sectors - doneSectors),
                                                                  currentTrack.TrackSequence);
                                DicConsole.Write("\rHashings sectors {0} to {2} of track {1}", doneSectors,
                                                 currentTrack.TrackSequence, doneSectors + (sectors - doneSectors));
                                doneSectors += sectors - doneSectors;
                            }

                            if (wholeDisc)
                            {
                                mediaChecksum?.Update(sector);
                            }

                            if (separatedTracks)
                            {
                                trackChecksum?.Update(sector);
                            }
                        }

                        DicConsole.WriteLine();

                        if (separatedTracks)
                        {
                            if (trackChecksum != null)
                            {
                                foreach (ChecksumType chk in trackChecksum.End())
                                {
                                    DicConsole.WriteLine("Track {0}'s {1}: {2}", currentTrack.TrackSequence,
                                                         chk.type, chk.Value);
                                }
                            }
                        }

                        previousTrackEnd = currentTrack.TrackEndSector;
                    }

                    if (opticalInput.Info.Sectors - previousTrackEnd != 0 && wholeDisc)
                    {
                        for (ulong i = previousTrackEnd + 1; i < opticalInput.Info.Sectors; i++)
                        {
                            DicConsole.Write("\rHashing track-less sector {0}", i);

                            byte[] hiddenSector = inputFormat.ReadSector(i);
                            mediaChecksum?.Update(hiddenSector);
                        }
                    }

                    if (wholeDisc)
                    {
                        if (mediaChecksum != null)
                        {
                            foreach (ChecksumType chk in mediaChecksum.End())
                            {
                                DicConsole.WriteLine("Disk's {0}: {1}", chk.type, chk.Value);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    if (MainClass.Debug)
                    {
                        DicConsole.DebugWriteLine("Could not get tracks because {0}", ex.Message);
                    }
                    else
                    {
                        DicConsole.WriteLine("Unable to get separate tracks, not checksumming them");
                    }
                }

                break;

            case ITapeImage tapeImage when tapeImage.IsTape && tapeImage.Files?.Count > 0:
            {
                Checksum trackChecksum = null;

                if (wholeDisc)
                {
                    mediaChecksum = new Checksum(enabledChecksums);
                }

                ulong previousTrackEnd = 0;

                foreach (TapeFile currentFile in tapeImage.Files)
                {
                    if (currentFile.FirstBlock - previousTrackEnd != 0 && wholeDisc)
                    {
                        for (ulong i = previousTrackEnd + 1; i < currentFile.FirstBlock; i++)
                        {
                            DicConsole.Write("\rHashing file-less block {0}", i);

                            byte[] hiddenSector = inputFormat.ReadSector(i);

                            mediaChecksum?.Update(hiddenSector);
                        }
                    }

                    DicConsole.DebugWriteLine("Checksum command",
                                              "Track {0} starts at sector {1} and ends at block {2}",
                                              currentFile.File, currentFile.FirstBlock, currentFile.LastBlock);

                    if (separatedTracks)
                    {
                        trackChecksum = new Checksum(enabledChecksums);
                    }

                    ulong sectors     = currentFile.LastBlock - currentFile.FirstBlock + 1;
                    ulong doneSectors = 0;
                    DicConsole.WriteLine("File {0} has {1} sectors", currentFile.File, sectors);

                    while (doneSectors < sectors)
                    {
                        byte[] sector;

                        if (sectors - doneSectors >= SECTORS_TO_READ)
                        {
                            sector = tapeImage.ReadSectors(doneSectors + currentFile.FirstBlock, SECTORS_TO_READ);
                            DicConsole.Write("\rHashings blocks {0} to {2} of file {1}", doneSectors,
                                             currentFile.File, doneSectors + SECTORS_TO_READ);
                            doneSectors += SECTORS_TO_READ;
                        }
                        else
                        {
                            sector = tapeImage.ReadSectors(doneSectors + currentFile.FirstBlock,
                                                           (uint)(sectors - doneSectors));
                            DicConsole.Write("\rHashings blocks {0} to {2} of file {1}", doneSectors,
                                             currentFile.File, doneSectors + (sectors - doneSectors));
                            doneSectors += sectors - doneSectors;
                        }

                        if (wholeDisc)
                        {
                            mediaChecksum?.Update(sector);
                        }

                        if (separatedTracks)
                        {
                            trackChecksum?.Update(sector);
                        }
                    }

                    DicConsole.WriteLine();

                    if (separatedTracks)
                    {
                        if (trackChecksum != null)
                        {
                            foreach (ChecksumType chk in trackChecksum.End())
                            {
                                DicConsole.WriteLine("File {0}'s {1}: {2}", currentFile.File, chk.type, chk.Value);
                            }
                        }
                    }

                    previousTrackEnd = currentFile.LastBlock;
                }

                if (tapeImage.Info.Sectors - previousTrackEnd != 0 && wholeDisc)
                {
                    for (ulong i = previousTrackEnd + 1; i < tapeImage.Info.Sectors; i++)
                    {
                        DicConsole.Write("\rHashing file-less sector {0}", i);

                        byte[] hiddenSector = inputFormat.ReadSector(i);
                        mediaChecksum?.Update(hiddenSector);
                    }
                }

                if (wholeDisc)
                {
                    if (mediaChecksum != null)
                    {
                        foreach (ChecksumType chk in mediaChecksum.End())
                        {
                            DicConsole.WriteLine("Tape's {0}: {1}", chk.type, chk.Value);
                        }
                    }
                }
                break;
            }

            default:
            {
                mediaChecksum = new Checksum(enabledChecksums);

                ulong sectors = inputFormat.Info.Sectors;
                DicConsole.WriteLine("Sectors {0}", sectors);
                ulong doneSectors = 0;

                while (doneSectors < sectors)
                {
                    byte[] sector;

                    if (sectors - doneSectors >= SECTORS_TO_READ)
                    {
                        sector = inputFormat.ReadSectors(doneSectors, SECTORS_TO_READ);
                        DicConsole.Write("\rHashings sectors {0} to {1}", doneSectors,
                                         doneSectors + SECTORS_TO_READ);
                        doneSectors += SECTORS_TO_READ;
                    }
                    else
                    {
                        sector = inputFormat.ReadSectors(doneSectors, (uint)(sectors - doneSectors));
                        DicConsole.Write("\rHashings sectors {0} to {1}", doneSectors,
                                         doneSectors + (sectors - doneSectors));
                        doneSectors += sectors - doneSectors;
                    }

                    mediaChecksum.Update(sector);
                }

                DicConsole.WriteLine();

                foreach (ChecksumType chk in mediaChecksum.End())
                {
                    DicConsole.WriteLine("Disk's {0}: {1}", chk.type, chk.Value);
                }
                break;
            }
            }

            return((int)ErrorNumber.NoError);
        }