コード例 #1
0
        public void Convert()
        {
            Environment.CurrentDirectory = DataFolder;

            Resume           resume  = null;
            CICMMetadataType sidecar = null;

            var     filtersList = new FiltersList();
            IFilter inputFilter = filtersList.GetFilter(InputPath);

            Assert.IsNotNull(inputFilter, "Cannot open specified file.");

            string outputPath = Path.Combine(Path.GetTempPath(), SuggestedOutputFilename);

            Assert.IsFalse(File.Exists(outputPath), "Output file already exists, not continuing.");

            IMediaImage inputFormat = ImageFormat.Detect(inputFilter);

            Assert.IsNotNull(inputFormat, "Input image format not identified, not proceeding with conversion.");

            Assert.IsTrue(inputFormat.Open(inputFilter), "Unable to open image format");

            Assert.IsTrue(OutputFormat.SupportedMediaTypes.Contains(inputFormat.Info.MediaType),
                          "Output format does not support media type, cannot continue...");

            if (inputFormat.Info.ReadableSectorTags.Count == 0)
            {
                Assert.IsFalse(UseLong, "Input image does not support long sectors.");
            }

            var inputOptical  = inputFormat as IOpticalMediaImage;
            var outputOptical = OutputFormat as IWritableOpticalImage;

            Assert.IsNotNull(inputOptical, "Could not treat existing image as optical disc.");
            Assert.IsNotNull(outputOptical, "Could not treat new image as optical disc.");
            Assert.IsNotNull(inputOptical.Tracks, "Existing image contains no tracks.");

            Assert.IsTrue(outputOptical.Create(outputPath, inputFormat.Info.MediaType, ParsedOptions, inputFormat.Info.Sectors, inputFormat.Info.SectorSize),
                          $"Error {outputOptical.ErrorMessage} creating output image.");

            var metadata = new ImageInfo
            {
                Application           = "Aaru",
                ApplicationVersion    = Version.GetVersion(),
                Comments              = inputFormat.Info.Comments,
                Creator               = inputFormat.Info.Creator,
                DriveFirmwareRevision = inputFormat.Info.DriveFirmwareRevision,
                DriveManufacturer     = inputFormat.Info.DriveManufacturer,
                DriveModel            = inputFormat.Info.DriveModel,
                DriveSerialNumber     = inputFormat.Info.DriveSerialNumber,
                LastMediaSequence     = inputFormat.Info.LastMediaSequence,
                MediaBarcode          = inputFormat.Info.MediaBarcode,
                MediaManufacturer     = inputFormat.Info.MediaManufacturer,
                MediaModel            = inputFormat.Info.MediaModel,
                MediaPartNumber       = inputFormat.Info.MediaPartNumber,
                MediaSequence         = inputFormat.Info.MediaSequence,
                MediaSerialNumber     = inputFormat.Info.MediaSerialNumber,
                MediaTitle            = inputFormat.Info.MediaTitle
            };

            Assert.IsTrue(outputOptical.SetMetadata(metadata),
                          $"Error {outputOptical.ErrorMessage} setting metadata, ");

            CICMMetadataType        cicmMetadata = inputFormat.CicmMetadata;
            List <DumpHardwareType> dumpHardware = inputFormat.DumpHardware;

            foreach (MediaTagType mediaTag in inputFormat.Info.ReadableMediaTags.Where(mediaTag =>
                                                                                       outputOptical.SupportedMediaTags.Contains(mediaTag)))
            {
                AaruConsole.WriteLine("Converting media tag {0}", mediaTag);
                byte[] tag = inputFormat.ReadDiskTag(mediaTag);

                Assert.IsTrue(outputOptical.WriteMediaTag(tag, mediaTag));
            }

            AaruConsole.WriteLine("{0} sectors to convert", inputFormat.Info.Sectors);
            ulong doneSectors;

            Assert.IsTrue(outputOptical.SetTracks(inputOptical.Tracks),
                          $"Error {outputOptical.ErrorMessage} sending tracks list to output image.");

            foreach (Track track in inputOptical.Tracks)
            {
                doneSectors = 0;
                ulong trackSectors = track.TrackEndSector - track.TrackStartSector + 1;

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

                    uint sectorsToDo;

                    if (trackSectors - doneSectors >= SECTORS_TO_READ)
                    {
                        sectorsToDo = SECTORS_TO_READ;
                    }
                    else
                    {
                        sectorsToDo = (uint)(trackSectors - doneSectors);
                    }

                    bool useNotLong = false;
                    bool result     = false;

                    if (UseLong)
                    {
                        if (sectorsToDo == 1)
                        {
                            sector = inputFormat.ReadSectorLong(doneSectors + track.TrackStartSector);
                            result = outputOptical.WriteSectorLong(sector, doneSectors + track.TrackStartSector);
                        }
                        else
                        {
                            sector = inputFormat.ReadSectorsLong(doneSectors + track.TrackStartSector, sectorsToDo);

                            result = outputOptical.WriteSectorsLong(sector, doneSectors + track.TrackStartSector,
                                                                    sectorsToDo);
                        }

                        if (!result &&
                            sector.Length % 2352 != 0)
                        {
                            useNotLong = true;
                        }
                    }

                    if (!UseLong || useNotLong)
                    {
                        if (sectorsToDo == 1)
                        {
                            sector = inputFormat.ReadSector(doneSectors + track.TrackStartSector);
                            result = outputOptical.WriteSector(sector, doneSectors + track.TrackStartSector);
                        }
                        else
                        {
                            sector = inputFormat.ReadSectors(doneSectors + track.TrackStartSector, sectorsToDo);

                            result = outputOptical.WriteSectors(sector, doneSectors + track.TrackStartSector,
                                                                sectorsToDo);
                        }
                    }

                    Assert.IsTrue(result,
                                  $"Error {outputOptical.ErrorMessage} writing sector {doneSectors + track.TrackStartSector}, not continuing...");

                    doneSectors += sectorsToDo;
                }
            }

            Dictionary <byte, string> isrcs                  = new Dictionary <byte, string>();
            Dictionary <byte, byte>   trackFlags             = new Dictionary <byte, byte>();
            string                 mcn                       = null;
            HashSet <int>          subchannelExtents         = new HashSet <int>();
            Dictionary <byte, int> smallestPregapLbaPerTrack = new Dictionary <byte, int>();

            Track[] tracks = new Track[inputOptical.Tracks.Count];

            for (int i = 0; i < tracks.Length; i++)
            {
                tracks[i] = new Track
                {
                    Indexes                = new Dictionary <ushort, int>(),
                    TrackDescription       = inputOptical.Tracks[i].TrackDescription,
                    TrackEndSector         = inputOptical.Tracks[i].TrackEndSector,
                    TrackStartSector       = inputOptical.Tracks[i].TrackStartSector,
                    TrackPregap            = inputOptical.Tracks[i].TrackPregap,
                    TrackSequence          = inputOptical.Tracks[i].TrackSequence,
                    TrackSession           = inputOptical.Tracks[i].TrackSession,
                    TrackBytesPerSector    = inputOptical.Tracks[i].TrackBytesPerSector,
                    TrackRawBytesPerSector = inputOptical.Tracks[i].TrackRawBytesPerSector,
                    TrackType              = inputOptical.Tracks[i].TrackType,
                    TrackSubchannelType    = inputOptical.Tracks[i].TrackSubchannelType
                };

                foreach (KeyValuePair <ushort, int> idx in inputOptical.Tracks[i].Indexes)
                {
                    tracks[i].Indexes[idx.Key] = idx.Value;
                }
            }

            foreach (SectorTagType tag in inputFormat.Info.ReadableSectorTags.Where(t => t == SectorTagType.CdTrackIsrc).
                     OrderBy(t => t))
            {
                foreach (Track track in tracks)
                {
                    byte[] isrc = inputFormat.ReadSectorTag(track.TrackSequence, tag);

                    if (isrc is null)
                    {
                        continue;
                    }

                    isrcs[(byte)track.TrackSequence] = Encoding.UTF8.GetString(isrc);
                }
            }

            foreach (SectorTagType tag in inputFormat.Info.ReadableSectorTags.
                     Where(t => t == SectorTagType.CdTrackFlags).OrderBy(t => t))
            {
                foreach (Track track in tracks)
                {
                    byte[] flags = inputFormat.ReadSectorTag(track.TrackSequence, tag);

                    if (flags is null)
                    {
                        continue;
                    }

                    trackFlags[(byte)track.TrackSequence] = flags[0];
                }
            }

            for (ulong s = 0; s < inputFormat.Info.Sectors; s++)
            {
                if (s > int.MaxValue)
                {
                    break;
                }

                subchannelExtents.Add((int)s);
            }

            foreach (SectorTagType tag in inputFormat.Info.ReadableSectorTags.OrderBy(t => t).TakeWhile(tag => UseLong))
            {
                switch (tag)
                {
                case SectorTagType.AppleSectorTag:
                case SectorTagType.CdSectorSync:
                case SectorTagType.CdSectorHeader:
                case SectorTagType.CdSectorSubHeader:
                case SectorTagType.CdSectorEdc:
                case SectorTagType.CdSectorEccP:
                case SectorTagType.CdSectorEccQ:
                case SectorTagType.CdSectorEcc:
                    // This tags are inline in long sector
                    continue;
                }

                if (!outputOptical.SupportedSectorTags.Contains(tag))
                {
                    continue;
                }

                foreach (Track track in inputOptical.Tracks)
                {
                    doneSectors = 0;
                    ulong  trackSectors = track.TrackEndSector - track.TrackStartSector + 1;
                    byte[] sector;
                    bool   result;

                    switch (tag)
                    {
                    case SectorTagType.CdTrackFlags:
                    case SectorTagType.CdTrackIsrc:
                        sector = inputFormat.ReadSectorTag(track.TrackSequence, tag);
                        result = outputOptical.WriteSectorTag(sector, track.TrackSequence, tag);

                        Assert.IsTrue(result, $"Error {outputOptical.ErrorMessage} writing tag, not continuing...");

                        continue;
                    }

                    while (doneSectors < trackSectors)
                    {
                        uint sectorsToDo;

                        if (trackSectors - doneSectors >= SECTORS_TO_READ)
                        {
                            sectorsToDo = SECTORS_TO_READ;
                        }
                        else
                        {
                            sectorsToDo = (uint)(trackSectors - doneSectors);
                        }

                        if (sectorsToDo == 1)
                        {
                            sector = inputFormat.ReadSectorTag(doneSectors + track.TrackStartSector, tag);

                            if (tag == SectorTagType.CdSectorSubchannel)
                            {
                                bool indexesChanged = CompactDisc.WriteSubchannelToImage(MmcSubchannel.Raw,
                                                                                         MmcSubchannel.Raw, sector, doneSectors + track.TrackStartSector, 1, null,
                                                                                         isrcs, (byte)track.TrackSequence, ref mcn, tracks, subchannelExtents, true,
                                                                                         outputOptical, true, true, null, null, smallestPregapLbaPerTrack, false);

                                if (indexesChanged)
                                {
                                    outputOptical.SetTracks(tracks.ToList());
                                }

                                result = true;
                            }
                            else
                            {
                                result = outputOptical.WriteSectorTag(sector, doneSectors + track.TrackStartSector,
                                                                      tag);
                            }
                        }
                        else
                        {
                            sector = inputFormat.ReadSectorsTag(doneSectors + track.TrackStartSector, sectorsToDo, tag);

                            if (tag == SectorTagType.CdSectorSubchannel)
                            {
                                bool indexesChanged = CompactDisc.WriteSubchannelToImage(MmcSubchannel.Raw,
                                                                                         MmcSubchannel.Raw, sector, doneSectors + track.TrackStartSector, sectorsToDo,
                                                                                         null, isrcs, (byte)track.TrackSequence, ref mcn, tracks, subchannelExtents,
                                                                                         true, outputOptical, true, true, null, null, smallestPregapLbaPerTrack, false);

                                if (indexesChanged)
                                {
                                    outputOptical.SetTracks(tracks.ToList());
                                }

                                result = true;
                            }
                            else
                            {
                                result = outputOptical.WriteSectorsTag(sector, doneSectors + track.TrackStartSector,
                                                                       sectorsToDo, tag);
                            }
                        }

                        Assert.IsTrue(result,
                                      $"Error {outputOptical.ErrorMessage} writing tag for sector {doneSectors + track.TrackStartSector}, not continuing...");

                        doneSectors += sectorsToDo;
                    }
                }
            }

            if (isrcs.Count > 0)
            {
                foreach (KeyValuePair <byte, string> isrc in isrcs)
                {
                    outputOptical.WriteSectorTag(Encoding.UTF8.GetBytes(isrc.Value), isrc.Key,
                                                 SectorTagType.CdTrackIsrc);
                }
            }

            if (trackFlags.Count > 0)
            {
                foreach ((byte track, byte flags) in trackFlags)
                {
                    outputOptical.WriteSectorTag(new[]
                    {
                        flags
                    }, track, SectorTagType.CdTrackFlags);
                }
            }

            if (mcn != null)
            {
                outputOptical.WriteMediaTag(Encoding.UTF8.GetBytes(mcn), MediaTagType.CD_MCN);
            }

            if (resume != null ||
                dumpHardware != null)
            {
                if (resume != null)
                {
                    outputOptical.SetDumpHardware(resume.Tries);
                }
                else if (dumpHardware != null)
                {
                    outputOptical.SetDumpHardware(dumpHardware);
                }
            }

            if (sidecar != null ||
                cicmMetadata != null)
            {
                if (sidecar != null)
                {
                    outputOptical.SetCicmMetadata(sidecar);
                }
                else if (cicmMetadata != null)
                {
                    outputOptical.SetCicmMetadata(cicmMetadata);
                }
            }

            Assert.True(outputOptical.Close(),
                        $"Error {outputOptical.ErrorMessage} closing output image... Contents are not correct.");

            // Some images will never generate the same
            if (Md5 != null)
            {
                string md5 = Md5Context.File(outputPath, out _);

                Assert.AreEqual(Md5, md5, "Hashes are different");
            }

            File.Delete(outputPath);
        }
コード例 #2
0
ファイル: Convert.cs プロジェクト: KailoKyra/DiscImageChef
        public static int Invoke(bool verbose, bool debug, string cicmXml, string comments, int count, string creator,
                                 string driveFirmwareRevision, string driveManufacturer, string driveModel,
                                 string driveSerialNumber, bool force, string inputPath, int lastMediaSequence,
                                 string mediaBarcode, string mediaManufacturer, string mediaModel,
                                 string mediaPartNumber, int mediaSequence, string mediaSerialNumber, string mediaTitle,
                                 string outputPath, string outputOptions, string resumeFile, string format)
        {
            MainClass.PrintCopyright();

            if (debug)
            {
                AaruConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
            }

            if (verbose)
            {
                AaruConsole.VerboseWriteLineEvent += System.Console.WriteLine;
            }

            Statistics.AddCommand("convert-image");

            AaruConsole.DebugWriteLine("Analyze command", "--cicm-xml={0}", cicmXml);
            AaruConsole.DebugWriteLine("Analyze command", "--comments={0}", comments);
            AaruConsole.DebugWriteLine("Analyze command", "--count={0}", count);
            AaruConsole.DebugWriteLine("Analyze command", "--creator={0}", creator);
            AaruConsole.DebugWriteLine("Analyze command", "--debug={0}", debug);
            AaruConsole.DebugWriteLine("Analyze command", "--drive-manufacturer={0}", driveManufacturer);
            AaruConsole.DebugWriteLine("Analyze command", "--drive-model={0}", driveModel);
            AaruConsole.DebugWriteLine("Analyze command", "--drive-revision={0}", driveFirmwareRevision);
            AaruConsole.DebugWriteLine("Analyze command", "--drive-serial={0}", driveSerialNumber);
            AaruConsole.DebugWriteLine("Analyze command", "--force={0}", force);
            AaruConsole.DebugWriteLine("Analyze command", "--format={0}", format);
            AaruConsole.DebugWriteLine("Analyze command", "--input={0}", inputPath);
            AaruConsole.DebugWriteLine("Analyze command", "--media-barcode={0}", mediaBarcode);
            AaruConsole.DebugWriteLine("Analyze command", "--media-lastsequence={0}", lastMediaSequence);
            AaruConsole.DebugWriteLine("Analyze command", "--media-manufacturer={0}", mediaManufacturer);
            AaruConsole.DebugWriteLine("Analyze command", "--media-model={0}", mediaModel);
            AaruConsole.DebugWriteLine("Analyze command", "--media-partnumber={0}", mediaPartNumber);
            AaruConsole.DebugWriteLine("Analyze command", "--media-sequence={0}", mediaSequence);
            AaruConsole.DebugWriteLine("Analyze command", "--media-serial={0}", mediaSerialNumber);
            AaruConsole.DebugWriteLine("Analyze command", "--media-title={0}", mediaTitle);
            AaruConsole.DebugWriteLine("Analyze command", "--options={0}", outputOptions);
            AaruConsole.DebugWriteLine("Analyze command", "--output={0}", outputPath);
            AaruConsole.DebugWriteLine("Analyze command", "--resume-file={0}", resumeFile);
            AaruConsole.DebugWriteLine("Analyze command", "--verbose={0}", verbose);

            Dictionary <string, string> parsedOptions = Core.Options.Parse(outputOptions);

            AaruConsole.DebugWriteLine("Analyze command", "Parsed options:");

            foreach (KeyValuePair <string, string> parsedOption in parsedOptions)
            {
                AaruConsole.DebugWriteLine("Analyze command", "{0} = {1}", parsedOption.Key, parsedOption.Value);
            }

            if (count == 0)
            {
                AaruConsole.ErrorWriteLine("Need to specify more than 0 sectors to copy at once");

                return((int)ErrorNumber.InvalidArgument);
            }

            Resume           resume  = null;
            CICMMetadataType sidecar = null;
            MediaType        mediaType;

            var xs = new XmlSerializer(typeof(CICMMetadataType));

            if (cicmXml != null)
            {
                if (File.Exists(cicmXml))
                {
                    try
                    {
                        var sr = new StreamReader(cicmXml);
                        sidecar = (CICMMetadataType)xs.Deserialize(sr);
                        sr.Close();
                    }
                    catch (Exception ex)
                    {
                        AaruConsole.ErrorWriteLine("Incorrect metadata sidecar file, not continuing...");
                        AaruConsole.DebugWriteLine("Image conversion", $"{ex}");

                        return((int)ErrorNumber.InvalidSidecar);
                    }
                }
                else
                {
                    AaruConsole.ErrorWriteLine("Could not find metadata sidecar, not continuing...");

                    return((int)ErrorNumber.FileNotFound);
                }
            }

            xs = new XmlSerializer(typeof(Resume));

            if (resumeFile != null)
            {
                if (File.Exists(resumeFile))
                {
                    try
                    {
                        var sr = new StreamReader(resumeFile);
                        resume = (Resume)xs.Deserialize(sr);
                        sr.Close();
                    }
                    catch (Exception ex)
                    {
                        AaruConsole.ErrorWriteLine("Incorrect resume file, not continuing...");
                        AaruConsole.DebugWriteLine("Image conversion", $"{ex}");

                        return((int)ErrorNumber.InvalidResume);
                    }
                }
                else
                {
                    AaruConsole.ErrorWriteLine("Could not find resume file, not continuing...");

                    return((int)ErrorNumber.FileNotFound);
                }
            }

            var     filtersList = new FiltersList();
            IFilter inputFilter = filtersList.GetFilter(inputPath);

            if (inputFilter == null)
            {
                AaruConsole.ErrorWriteLine("Cannot open specified file.");

                return((int)ErrorNumber.CannotOpenFile);
            }

            if (File.Exists(outputPath))
            {
                AaruConsole.ErrorWriteLine("Output file already exists, not continuing.");

                return((int)ErrorNumber.DestinationExists);
            }

            PluginBase  plugins     = GetPluginBase.Instance;
            IMediaImage inputFormat = ImageFormat.Detect(inputFilter);

            if (inputFormat == null)
            {
                AaruConsole.WriteLine("Input image format not identified, not proceeding with conversion.");

                return((int)ErrorNumber.UnrecognizedFormat);
            }

            if (verbose)
            {
                AaruConsole.VerboseWriteLine("Input image format identified by {0} ({1}).", inputFormat.Name,
                                             inputFormat.Id);
            }
            else
            {
                AaruConsole.WriteLine("Input image format identified by {0}.", inputFormat.Name);
            }

            try
            {
                if (!inputFormat.Open(inputFilter))
                {
                    AaruConsole.WriteLine("Unable to open image format");
                    AaruConsole.WriteLine("No error given");

                    return((int)ErrorNumber.CannotOpenFormat);
                }

                mediaType = inputFormat.Info.MediaType;

                // Obsolete types
                #pragma warning disable 612
                switch (mediaType)
                {
                case MediaType.SQ1500:
                    mediaType = MediaType.SyJet;

                    break;

                case MediaType.Bernoulli:
                    mediaType = MediaType.Bernoulli10;

                    break;

                case MediaType.Bernoulli2:
                    mediaType = MediaType.BernoulliBox2_20;

                    break;
                }
                #pragma warning restore 612

                AaruConsole.DebugWriteLine("Convert-image command", "Correctly opened image file.");

                AaruConsole.DebugWriteLine("Convert-image command", "Image without headers is {0} bytes.",
                                           inputFormat.Info.ImageSize);

                AaruConsole.DebugWriteLine("Convert-image command", "Image has {0} sectors.", inputFormat.Info.Sectors);

                AaruConsole.DebugWriteLine("Convert-image command", "Image identifies media type as {0}.", mediaType);

                Statistics.AddMediaFormat(inputFormat.Format);
                Statistics.AddMedia(mediaType, false);
                Statistics.AddFilter(inputFilter.Name);
            }
            catch (Exception ex)
            {
                AaruConsole.ErrorWriteLine("Unable to open image format");
                AaruConsole.ErrorWriteLine("Error: {0}", ex.Message);
                AaruConsole.DebugWriteLine("Convert-image command", "Stack trace: {0}", ex.StackTrace);

                return((int)ErrorNumber.CannotOpenFormat);
            }

            List <IWritableImage> candidates = new List <IWritableImage>();

            // Try extension
            if (string.IsNullOrEmpty(format))
            {
                candidates.AddRange(plugins.WritableImages.Values.Where(t =>
                                                                        t.KnownExtensions.
                                                                        Contains(Path.GetExtension(outputPath))));
            }

            // Try Id
            else if (Guid.TryParse(format, out Guid outId))
            {
                candidates.AddRange(plugins.WritableImages.Values.Where(t => t.Id.Equals(outId)));
            }

            // Try name
            else
            {
                candidates.AddRange(plugins.WritableImages.Values.Where(t => string.Equals(t.Name, format,
                                                                                           StringComparison.
                                                                                           InvariantCultureIgnoreCase)));
            }

            if (candidates.Count == 0)
            {
                AaruConsole.WriteLine("No plugin supports requested extension.");

                return((int)ErrorNumber.FormatNotFound);
            }

            if (candidates.Count > 1)
            {
                AaruConsole.WriteLine("More than one plugin supports requested extension.");

                return((int)ErrorNumber.TooManyFormats);
            }

            IWritableImage outputFormat = candidates[0];

            if (verbose)
            {
                AaruConsole.VerboseWriteLine("Output image format: {0} ({1}).", outputFormat.Name, outputFormat.Id);
            }
            else
            {
                AaruConsole.WriteLine("Output image format: {0}.", outputFormat.Name);
            }

            if (!outputFormat.SupportedMediaTypes.Contains(mediaType))
            {
                AaruConsole.ErrorWriteLine("Output format does not support media type, cannot continue...");

                return((int)ErrorNumber.UnsupportedMedia);
            }

            foreach (MediaTagType mediaTag in inputFormat.Info.ReadableMediaTags)
            {
                if (outputFormat.SupportedMediaTags.Contains(mediaTag) || force)
                {
                    continue;
                }

                AaruConsole.ErrorWriteLine("Converting image will lose media tag {0}, not continuing...", mediaTag);
                AaruConsole.ErrorWriteLine("If you don't care, use force option.");

                return((int)ErrorNumber.DataWillBeLost);
            }

            bool useLong = inputFormat.Info.ReadableSectorTags.Count != 0;

            foreach (SectorTagType sectorTag in inputFormat.Info.ReadableSectorTags)
            {
                if (outputFormat.SupportedSectorTags.Contains(sectorTag))
                {
                    continue;
                }

                if (force)
                {
                    if (sectorTag != SectorTagType.CdTrackFlags &&
                        sectorTag != SectorTagType.CdTrackIsrc &&
                        sectorTag != SectorTagType.CdSectorSubchannel)
                    {
                        useLong = false;
                    }

                    continue;
                }

                AaruConsole.ErrorWriteLine("Converting image will lose sector tag {0}, not continuing...", sectorTag);

                AaruConsole.
                ErrorWriteLine("If you don't care, use force option. This will skip all sector tags converting only user data.");

                return((int)ErrorNumber.DataWillBeLost);
            }

            if (!outputFormat.Create(outputPath, mediaType, parsedOptions, inputFormat.Info.Sectors,
                                     inputFormat.Info.SectorSize))
            {
                AaruConsole.ErrorWriteLine("Error {0} creating output image.", outputFormat.ErrorMessage);

                return((int)ErrorNumber.CannotCreateFormat);
            }

            var metadata = new ImageInfo
            {
                Application           = "Aaru",
                ApplicationVersion    = Version.GetVersion(),
                Comments              = comments ?? inputFormat.Info.Comments,
                Creator               = creator ?? inputFormat.Info.Creator,
                DriveFirmwareRevision = driveFirmwareRevision ?? inputFormat.Info.DriveFirmwareRevision,
                DriveManufacturer     = driveManufacturer ?? inputFormat.Info.DriveManufacturer,
                DriveModel            = driveModel ?? inputFormat.Info.DriveModel,
                DriveSerialNumber     = driveSerialNumber ?? inputFormat.Info.DriveSerialNumber,
                LastMediaSequence     = lastMediaSequence != 0 ? lastMediaSequence : inputFormat.Info.LastMediaSequence,
                MediaBarcode          = mediaBarcode ?? inputFormat.Info.MediaBarcode,
                MediaManufacturer     = mediaManufacturer ?? inputFormat.Info.MediaManufacturer,
                MediaModel            = mediaModel ?? inputFormat.Info.MediaModel,
                MediaPartNumber       = mediaPartNumber ?? inputFormat.Info.MediaPartNumber,
                MediaSequence         = mediaSequence != 0 ? mediaSequence : inputFormat.Info.MediaSequence,
                MediaSerialNumber     = mediaSerialNumber ?? inputFormat.Info.MediaSerialNumber,
                MediaTitle            = mediaTitle ?? inputFormat.Info.MediaTitle
            };

            if (!outputFormat.SetMetadata(metadata))
            {
                AaruConsole.ErrorWrite("Error {0} setting metadata, ", outputFormat.ErrorMessage);

                if (!force)
                {
                    AaruConsole.ErrorWriteLine("not continuing...");

                    return((int)ErrorNumber.WriteError);
                }

                AaruConsole.ErrorWriteLine("continuing...");
            }

            CICMMetadataType        cicmMetadata = inputFormat.CicmMetadata;
            List <DumpHardwareType> dumpHardware = inputFormat.DumpHardware;

            foreach (MediaTagType mediaTag in inputFormat.Info.ReadableMediaTags)
            {
                if (force && !outputFormat.SupportedMediaTags.Contains(mediaTag))
                {
                    continue;
                }

                AaruConsole.WriteLine("Converting media tag {0}", mediaTag);
                byte[] tag = inputFormat.ReadDiskTag(mediaTag);

                if (outputFormat.WriteMediaTag(tag, mediaTag))
                {
                    continue;
                }

                if (force)
                {
                    AaruConsole.ErrorWriteLine("Error {0} writing media tag, continuing...", outputFormat.ErrorMessage);
                }
                else
                {
                    AaruConsole.ErrorWriteLine("Error {0} writing media tag, not continuing...",
                                               outputFormat.ErrorMessage);

                    return((int)ErrorNumber.WriteError);
                }
            }

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

            if (inputFormat is IOpticalMediaImage inputOptical &&
                outputFormat is IWritableOpticalImage outputOptical &&
                inputOptical.Tracks != null)
            {
                if (!outputOptical.SetTracks(inputOptical.Tracks))
                {
                    AaruConsole.ErrorWriteLine("Error {0} sending tracks list to output image.",
                                               outputFormat.ErrorMessage);

                    return((int)ErrorNumber.WriteError);
                }

                foreach (Track track in inputOptical.Tracks)
                {
                    doneSectors = 0;
                    ulong trackSectors = (track.TrackEndSector - track.TrackStartSector) + 1;

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

                        uint sectorsToDo;

                        if (trackSectors - doneSectors >= (ulong)count)
                        {
                            sectorsToDo = (uint)count;
                        }
                        else
                        {
                            sectorsToDo = (uint)(trackSectors - doneSectors);
                        }

                        AaruConsole.Write("\rConverting sectors {0} to {1} in track {3} ({2:P2} done)",
                                          doneSectors + track.TrackStartSector,
                                          doneSectors + sectorsToDo + track.TrackStartSector,
                                          (doneSectors + track.TrackStartSector) / (double)inputFormat.Info.Sectors,
                                          track.TrackSequence);

                        bool useNotLong = false;
                        bool result     = false;

                        if (useLong)
                        {
                            if (sectorsToDo == 1)
                            {
                                sector = inputFormat.ReadSectorLong(doneSectors + track.TrackStartSector);
                                result = outputFormat.WriteSectorLong(sector, doneSectors + track.TrackStartSector);
                            }
                            else
                            {
                                sector = inputFormat.ReadSectorsLong(doneSectors + track.TrackStartSector, sectorsToDo);

                                result = outputFormat.WriteSectorsLong(sector, doneSectors + track.TrackStartSector,
                                                                       sectorsToDo);
                            }

                            if (!result &&
                                sector.Length % 2352 != 0)
                            {
                                if (!force)
                                {
                                    AaruConsole.ErrorWriteLine("Input image is not returning raw sectors, use force if you want to continue...");

                                    return((int)Errno.InOutError);
                                }

                                useNotLong = true;
                            }
                        }

                        if (!useLong || useNotLong)
                        {
                            if (sectorsToDo == 1)
                            {
                                sector = inputFormat.ReadSector(doneSectors + track.TrackStartSector);
                                result = outputFormat.WriteSector(sector, doneSectors + track.TrackStartSector);
                            }
                            else
                            {
                                sector = inputFormat.ReadSectors(doneSectors + track.TrackStartSector, sectorsToDo);

                                result = outputFormat.WriteSectors(sector, doneSectors + track.TrackStartSector,
                                                                   sectorsToDo);
                            }
                        }

                        if (!result)
                        {
                            if (force)
                            {
                                AaruConsole.ErrorWriteLine("Error {0} writing sector {1}, continuing...",
                                                           outputFormat.ErrorMessage,
                                                           doneSectors + track.TrackStartSector);
                            }
                            else
                            {
                                AaruConsole.ErrorWriteLine("Error {0} writing sector {1}, not continuing...",
                                                           outputFormat.ErrorMessage,
                                                           doneSectors + track.TrackStartSector);

                                return((int)ErrorNumber.WriteError);
                            }
                        }

                        doneSectors += sectorsToDo;
                    }
                }

                AaruConsole.Write("\rConverting sectors {0} to {1} in track {3} ({2:P2} done)",
                                  inputFormat.Info.Sectors, inputFormat.Info.Sectors, 1.0, inputOptical.Tracks.Count);

                AaruConsole.WriteLine();

                foreach (SectorTagType tag in inputFormat.Info.ReadableSectorTags.OrderBy(t => t))
                {
                    if (!useLong)
                    {
                        break;
                    }

                    switch (tag)
                    {
                    case SectorTagType.AppleSectorTag:
                    case SectorTagType.CdSectorSync:
                    case SectorTagType.CdSectorHeader:
                    case SectorTagType.CdSectorSubHeader:
                    case SectorTagType.CdSectorEdc:
                    case SectorTagType.CdSectorEccP:
                    case SectorTagType.CdSectorEccQ:
                    case SectorTagType.CdSectorEcc:
                        // This tags are inline in long sector
                        continue;
                    }

                    if (force && !outputFormat.SupportedSectorTags.Contains(tag))
                    {
                        continue;
                    }

                    foreach (Track track in inputOptical.Tracks)
                    {
                        doneSectors = 0;
                        ulong  trackSectors = (track.TrackEndSector - track.TrackStartSector) + 1;
                        byte[] sector;
                        bool   result;

                        switch (tag)
                        {
                        case SectorTagType.CdTrackFlags:
                        case SectorTagType.CdTrackIsrc:
                            AaruConsole.Write("\rConverting tag {0} in track {1} ({2:P2} done).", tag,
                                              track.TrackSequence,
                                              track.TrackSequence / (double)inputOptical.Tracks.Count);

                            sector = inputFormat.ReadSectorTag(track.TrackStartSector, tag);
                            result = outputFormat.WriteSectorTag(sector, track.TrackStartSector, tag);

                            if (!result)
                            {
                                if (force)
                                {
                                    AaruConsole.ErrorWriteLine("Error {0} writing tag, continuing...",
                                                               outputFormat.ErrorMessage);
                                }
                                else
                                {
                                    AaruConsole.ErrorWriteLine("Error {0} writing tag, not continuing...",
                                                               outputFormat.ErrorMessage);

                                    return((int)ErrorNumber.WriteError);
                                }
                            }

                            continue;
                        }

                        while (doneSectors < trackSectors)
                        {
                            uint sectorsToDo;

                            if (trackSectors - doneSectors >= (ulong)count)
                            {
                                sectorsToDo = (uint)count;
                            }
                            else
                            {
                                sectorsToDo = (uint)(trackSectors - doneSectors);
                            }

                            AaruConsole.Write("\rConverting tag {4} for sectors {0} to {1} in track {3} ({2:P2} done)",
                                              doneSectors + track.TrackStartSector,
                                              doneSectors + sectorsToDo + track.TrackStartSector,
                                              (doneSectors + track.TrackStartSector) / (double)inputFormat.Info.Sectors,
                                              track.TrackSequence, tag);

                            if (sectorsToDo == 1)
                            {
                                sector = inputFormat.ReadSectorTag(doneSectors + track.TrackStartSector, tag);
                                result = outputFormat.WriteSectorTag(sector, doneSectors + track.TrackStartSector, tag);
                            }
                            else
                            {
                                sector = inputFormat.ReadSectorsTag(doneSectors + track.TrackStartSector, sectorsToDo,
                                                                    tag);

                                result = outputFormat.WriteSectorsTag(sector, doneSectors + track.TrackStartSector,
                                                                      sectorsToDo, tag);
                            }

                            if (!result)
                            {
                                if (force)
                                {
                                    AaruConsole.ErrorWriteLine("Error {0} writing tag for sector {1}, continuing...",
                                                               outputFormat.ErrorMessage,
                                                               doneSectors + track.TrackStartSector);
                                }
                                else
                                {
                                    AaruConsole.
                                    ErrorWriteLine("Error {0} writing tag for sector {1}, not continuing...",
                                                   outputFormat.ErrorMessage, doneSectors + track.TrackStartSector);

                                    return((int)ErrorNumber.WriteError);
                                }
                            }

                            doneSectors += sectorsToDo;
                        }
                    }

                    switch (tag)
                    {
                    case SectorTagType.CdTrackFlags:
                    case SectorTagType.CdTrackIsrc:
                        AaruConsole.Write("\rConverting tag {0} in track {1} ({2:P2} done).", tag,
                                          inputOptical.Tracks.Count, 1.0);

                        break;

                    default:
                        AaruConsole.Write("\rConverting tag {4} for sectors {0} to {1} in track {3} ({2:P2} done)",
                                          inputFormat.Info.Sectors, inputFormat.Info.Sectors, 1.0,
                                          inputOptical.Tracks.Count, tag);

                        break;
                    }

                    AaruConsole.WriteLine();
                }
            }
コード例 #3
0
ファイル: Compare.cs プロジェクト: KailoKyra/DiscImageChef
        public static int Invoke(bool debug, bool verbose, string imagePath1, string imagePath2)
        {
            MainClass.PrintCopyright();

            if (debug)
            {
                AaruConsole.DebugWriteLineEvent += System.Console.Error.WriteLine;
            }

            if (verbose)
            {
                AaruConsole.VerboseWriteLineEvent += System.Console.WriteLine;
            }

            Statistics.AddCommand("compare");

            AaruConsole.DebugWriteLine("Compare command", "--debug={0}", debug);
            AaruConsole.DebugWriteLine("Compare command", "--input1={0}", imagePath1);
            AaruConsole.DebugWriteLine("Compare command", "--input2={0}", imagePath2);
            AaruConsole.DebugWriteLine("Compare command", "--verbose={0}", verbose);

            var     filtersList  = new FiltersList();
            IFilter inputFilter1 = filtersList.GetFilter(imagePath1);

            filtersList = new FiltersList();
            IFilter inputFilter2 = filtersList.GetFilter(imagePath2);

            if (inputFilter1 == null)
            {
                AaruConsole.ErrorWriteLine("Cannot open input file 1");

                return((int)ErrorNumber.CannotOpenFile);
            }

            if (inputFilter2 == null)
            {
                AaruConsole.ErrorWriteLine("Cannot open input file 2");

                return((int)ErrorNumber.CannotOpenFile);
            }

            IMediaImage input1Format = ImageFormat.Detect(inputFilter1);
            IMediaImage input2Format = ImageFormat.Detect(inputFilter2);

            if (input1Format == null)
            {
                AaruConsole.ErrorWriteLine("Input file 1 format not identified, not proceeding with comparison.");

                return((int)ErrorNumber.UnrecognizedFormat);
            }

            if (verbose)
            {
                AaruConsole.VerboseWriteLine("Input file 1 format identified by {0} ({1}).", input1Format.Name,
                                             input1Format.Id);
            }
            else
            {
                AaruConsole.WriteLine("Input file 1 format identified by {0}.", input1Format.Name);
            }

            if (input2Format == null)
            {
                AaruConsole.ErrorWriteLine("Input file 2 format not identified, not proceeding with comparison.");

                return((int)ErrorNumber.UnrecognizedFormat);
            }

            if (verbose)
            {
                AaruConsole.VerboseWriteLine("Input file 2 format identified by {0} ({1}).", input2Format.Name,
                                             input2Format.Id);
            }
            else
            {
                AaruConsole.WriteLine("Input file 2 format identified by {0}.", input2Format.Name);
            }

            input1Format.Open(inputFilter1);
            input2Format.Open(inputFilter2);

            Statistics.AddMediaFormat(input1Format.Format);
            Statistics.AddMediaFormat(input2Format.Format);
            Statistics.AddMedia(input1Format.Info.MediaType, false);
            Statistics.AddMedia(input2Format.Info.MediaType, false);
            Statistics.AddFilter(inputFilter1.Name);
            Statistics.AddFilter(inputFilter2.Name);

            var sb = new StringBuilder();

            if (verbose)
            {
                sb.AppendFormat("{0,50}{1,20}", "Disc image 1", "Disc image 2").AppendLine();
                sb.AppendLine("================================================================================================");
                sb.AppendFormat("{0,-38}{1}", "File", imagePath1).AppendLine();

                sb.AppendFormat("                                                          {0}", imagePath2).
                AppendLine();

                sb.AppendFormat("{0,-38}{1,-20}{2}", "Disc image format", input1Format.Name, input2Format.Name).
                AppendLine();
            }
            else
            {
                sb.AppendFormat("Disc image 1: {0}", imagePath1).AppendLine();
                sb.AppendFormat("Disc image 2: {0}", imagePath2).AppendLine();
            }

            bool imagesDiffer = false;

            ImageInfo      image1Info     = input1Format.Info;
            ImageInfo      image2Info     = input2Format.Info;
            List <Session> image1Sessions = new List <Session>();
            List <Session> image2Sessions = new List <Session>();
            Dictionary <MediaTagType, byte[]> image1DiskTags = new Dictionary <MediaTagType, byte[]>();
            Dictionary <MediaTagType, byte[]> image2DiskTags = new Dictionary <MediaTagType, byte[]>();

            foreach (MediaTagType disktag in Enum.GetValues(typeof(MediaTagType)))
            {
                try
                {
                    byte[] temparray = input1Format.ReadDiskTag(disktag);
                    image1DiskTags.Add(disktag, temparray);
                }
                #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
                catch
                {
                    // ignored
                }
                #pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body
            }

            foreach (MediaTagType disktag in Enum.GetValues(typeof(MediaTagType)))
            {
                try
                {
                    byte[] temparray = input2Format.ReadDiskTag(disktag);
                    image2DiskTags.Add(disktag, temparray);
                }
                #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
                catch
                {
                    // ignored
                }
                #pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body
            }

            if (verbose)
            {
                sb.AppendFormat("{0,-38}{1,-20}{2}", "Has partitions?", image1Info.HasPartitions,
                                image2Info.HasPartitions).AppendLine();

                sb.AppendFormat("{0,-38}{1,-20}{2}", "Has sessions?", image1Info.HasSessions, image2Info.HasSessions).
                AppendLine();

                sb.AppendFormat("{0,-38}{1,-20}{2}", "Image size", image1Info.ImageSize, image2Info.ImageSize).
                AppendLine();

                sb.AppendFormat("{0,-38}{1,-20}{2}", "Sectors", image1Info.Sectors, image2Info.Sectors).AppendLine();

                sb.AppendFormat("{0,-38}{1,-20}{2}", "Sector size", image1Info.SectorSize, image2Info.SectorSize).
                AppendLine();

                sb.AppendFormat("{0,-38}{1,-20}{2}", "Creation time", image1Info.CreationTime, image2Info.CreationTime).
                AppendLine();

                sb.AppendFormat("{0,-38}{1,-20}{2}", "Last modification time", image1Info.LastModificationTime,
                                image2Info.LastModificationTime).AppendLine();

                sb.AppendFormat("{0,-38}{1,-20}{2}", "Disk type", image1Info.MediaType, image2Info.MediaType).
                AppendLine();

                sb.AppendFormat("{0,-38}{1,-20}{2}", "Image version", image1Info.Version, image2Info.Version).
                AppendLine();

                sb.AppendFormat("{0,-38}{1,-20}{2}", "Image application", image1Info.Application,
                                image2Info.Application).AppendLine();

                sb.AppendFormat("{0,-38}{1,-20}{2}", "Image application version", image1Info.ApplicationVersion,
                                image2Info.ApplicationVersion).AppendLine();

                sb.AppendFormat("{0,-38}{1,-20}{2}", "Image creator", image1Info.Creator, image2Info.Creator).
                AppendLine();

                sb.AppendFormat("{0,-38}{1,-20}{2}", "Image name", image1Info.MediaTitle, image2Info.MediaTitle).
                AppendLine();

                sb.AppendFormat("{0,-38}{1,-20}{2}", "Image comments", image1Info.Comments, image2Info.Comments).
                AppendLine();

                sb.AppendFormat("{0,-38}{1,-20}{2}", "Image comments", image1Info.Comments, image2Info.Comments).
                AppendLine();

                sb.AppendFormat("{0,-38}{1,-20}{2}", "Disk manufacturer", image1Info.MediaManufacturer,
                                image2Info.MediaManufacturer).AppendLine();

                sb.AppendFormat("{0,-38}{1,-20}{2}", "Disk model", image1Info.MediaModel, image2Info.MediaModel).
                AppendLine();

                sb.AppendFormat("{0,-38}{1,-20}{2}", "Disk serial number", image1Info.MediaSerialNumber,
                                image2Info.MediaSerialNumber).AppendLine();

                sb.AppendFormat("{0,-38}{1,-20}{2}", "Disk barcode", image1Info.MediaBarcode, image2Info.MediaBarcode).
                AppendLine();

                sb.AppendFormat("{0,-38}{1,-20}{2}", "Disk part no.", image1Info.MediaPartNumber,
                                image2Info.MediaPartNumber).AppendLine();

                sb.AppendFormat("{0,-38}{1,-20}{2}", "Disk sequence", image1Info.MediaSequence,
                                image2Info.MediaSequence).AppendLine();

                sb.AppendFormat("{0,-38}{1,-20}{2}", "Last disk on sequence", image1Info.LastMediaSequence,
                                image2Info.LastMediaSequence).AppendLine();

                sb.AppendFormat("{0,-38}{1,-20}{2}", "Drive manufacturer", image1Info.DriveManufacturer,
                                image2Info.DriveManufacturer).AppendLine();

                sb.AppendFormat("{0,-38}{1,-20}{2}", "Drive firmware revision", image1Info.DriveFirmwareRevision,
                                image2Info.DriveFirmwareRevision).AppendLine();

                sb.AppendFormat("{0,-38}{1,-20}{2}", "Drive model", image1Info.DriveModel, image2Info.DriveModel).
                AppendLine();

                sb.AppendFormat("{0,-38}{1,-20}{2}", "Drive serial number", image1Info.DriveSerialNumber,
                                image2Info.DriveSerialNumber).AppendLine();

                foreach (MediaTagType disktag in
                         (Enum.GetValues(typeof(MediaTagType)) as MediaTagType[]).OrderBy(e => e.ToString()))
                {
                    sb.AppendFormat("{0,-38}{1,-20}{2}", $"Has {disktag}?", image1DiskTags.ContainsKey(disktag),
                                    image2DiskTags.ContainsKey(disktag)).AppendLine();
                }
            }

            AaruConsole.WriteLine("Comparing disk image characteristics");

            if (image1Info.HasPartitions != image2Info.HasPartitions)
            {
                imagesDiffer = true;

                if (!verbose)
                {
                    sb.AppendLine("Image partitioned status differ");
                }
            }

            if (image1Info.HasSessions != image2Info.HasSessions)
            {
                imagesDiffer = true;

                if (!verbose)
                {
                    sb.AppendLine("Image session status differ");
                }
            }

            if (image1Info.Sectors != image2Info.Sectors)
            {
                imagesDiffer = true;

                if (!verbose)
                {
                    sb.AppendLine("Image sectors differ");
                }
            }

            if (image1Info.SectorSize != image2Info.SectorSize)
            {
                imagesDiffer = true;

                if (!verbose)
                {
                    sb.AppendLine("Image sector size differ");
                }
            }

            if (image1Info.MediaType != image2Info.MediaType)
            {
                imagesDiffer = true;

                if (!verbose)
                {
                    sb.AppendLine("Disk type differ");
                }
            }

            ulong leastSectors;

            if (image1Info.Sectors < image2Info.Sectors)
            {
                imagesDiffer = true;
                leastSectors = image1Info.Sectors;

                if (!verbose)
                {
                    sb.AppendLine("Image 2 has more sectors");
                }
            }
            else if (image1Info.Sectors > image2Info.Sectors)
            {
                imagesDiffer = true;
                leastSectors = image2Info.Sectors;

                if (!verbose)
                {
                    sb.AppendLine("Image 1 has more sectors");
                }
            }
            else
            {
                leastSectors = image1Info.Sectors;
            }

            AaruConsole.WriteLine("Comparing sectors...");

            for (ulong sector = 0; sector < leastSectors; sector++)
            {
                AaruConsole.Write("\rComparing sector {0} of {1}...", sector + 1, leastSectors);

                try
                {
                    byte[] image1Sector = input1Format.ReadSector(sector);
                    byte[] image2Sector = input2Format.ReadSector(sector);
                    ArrayHelpers.CompareBytes(out bool different, out bool sameSize, image1Sector, image2Sector);

                    if (different)
                    {
                        imagesDiffer = true;
                        sb.AppendFormat("Sector {0} is different", sector).AppendLine();
                    }
                    else if (!sameSize)
                    {
                        imagesDiffer = true;

                        sb.
                        AppendFormat("Sector {0} has different sizes ({1} bytes in image 1, {2} in image 2) but are otherwise identical",
                                     sector, image1Sector.LongLength, image2Sector.LongLength).AppendLine();
                    }
                }
                #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
                catch
                {
                    // ignored
                }
                #pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body
            }

            AaruConsole.WriteLine();

            sb.AppendLine(imagesDiffer ? "Images differ" : "Images do not differ");

            AaruConsole.WriteLine(sb.ToString());

            return((int)ErrorNumber.NoError);
        }