// /*************************************************************************** // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // // Filename : ImageInfoViewModel.cs // Author(s) : Natalia Portillo // // Component : GUI view models. // // --[ Description ] ---------------------------------------------------------- // // View model and code for the opened image information panel. // // --[ License ] -------------------------------------------------------------- // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General public License for more details. // // You should have received a copy of the GNU General public License // along with this program. If not, see . // // ---------------------------------------------------------------------------- // Copyright © 2011-2025 Natalia Portillo // ****************************************************************************/ using System; using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Windows.Input; using Aaru.CommonTypes.AaruMetadata; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Structs.Devices.SCSI; using Aaru.Decoders.CD; using Aaru.Decoders.DVD; using Aaru.Decoders.SCSI; using Aaru.Decoders.Xbox; using Aaru.Gui.Models; using Aaru.Gui.ViewModels.Tabs; using Aaru.Gui.ViewModels.Windows; using Aaru.Gui.Views.Tabs; using Aaru.Gui.Views.Windows; using Aaru.Helpers; using Aaru.Localization; using Avalonia.Controls; using Avalonia.Media; using Avalonia.Media.Imaging; using Avalonia.Platform; using Avalonia.Styling; using Avalonia.Svg; using CommunityToolkit.Mvvm.Input; using Humanizer; using Sentry; using Inquiry = Aaru.CommonTypes.Structs.Devices.SCSI.Inquiry; using Session = Aaru.CommonTypes.Structs.Session; using Track = Aaru.CommonTypes.Structs.Track; namespace Aaru.Gui.ViewModels.Panels; public sealed class ImageInfoViewModel : ViewModelBase { readonly IFilter _filter; readonly IMediaImage _imageFormat; readonly string _imagePath; DecodeMediaTags _decodeMediaTags; ImageChecksum _imageChecksum; ImageConvert _imageConvert; ImageEntropy _imageEntropy; ImageSidecar _imageSidecar; ImageVerify _imageVerify; ViewSector _viewSector; public ImageInfoViewModel(string imagePath, IFilter filter, IMediaImage imageFormat, Window view) { _imagePath = imagePath; _filter = filter; _imageFormat = imageFormat; MediaTagsList = []; SectorTagsList = []; Sessions = []; Tracks = []; DumpHardwareList = []; EntropyCommand = new RelayCommand(Entropy); VerifyCommand = new RelayCommand(Verify); ChecksumCommand = new RelayCommand(Checksum); ConvertCommand = new RelayCommand(Convert); CreateSidecarCommand = new RelayCommand(CreateSidecar); ViewSectorsCommand = new RelayCommand(ViewSectors); DecodeMediaTagCommand = new RelayCommand(DecodeMediaTag); var genericHddIcon = new Bitmap(AssetLoader.Open(new Uri("avares://Aaru.Gui/Assets/Icons/oxygen/32x32/drive-harddisk.png"))); var genericOpticalIcon = new Bitmap(AssetLoader.Open(new Uri("avares://Aaru.Gui/Assets/Icons/oxygen/32x32/drive-optical.png"))); var genericFolderIcon = new Bitmap(AssetLoader.Open(new Uri("avares://Aaru.Gui/Assets/Icons/oxygen/32x32/inode-directory.png"))); // Check if we're using dark theme bool isDarkTheme = view.ActualThemeVariant == ThemeVariant.Dark; // Build the appropriate SVG path based on theme string svgPath = isDarkTheme ? $"avares://Aaru.Gui/Assets/Logos/Media/Dark/{imageFormat.Info.MediaType}.svg" : $"avares://Aaru.Gui/Assets/Logos/Media/{imageFormat.Info.MediaType}.svg"; var mediaResource = new Uri(svgPath); // Fallback to light theme version if dark version doesn't exist if(isDarkTheme && !AssetLoader.Exists(mediaResource)) mediaResource = new Uri($"avares://Aaru.Gui/Assets/Logos/Media/{imageFormat.Info.MediaType}.svg"); MediaLogo = AssetLoader.Exists(mediaResource) ? new SvgImage { Source = SvgSource.Load(AssetLoader.Open(mediaResource)) } : imageFormat.Info.MetadataMediaType == MetadataMediaType.BlockMedia ? genericHddIcon : imageFormat.Info.MetadataMediaType == MetadataMediaType.OpticalDisc ? genericOpticalIcon : genericFolderIcon; ImagePathText = string.Format(UI.Path_0, imagePath); FilterText = string.Format(UI.Filter_0, filter.Name); ImageIdentifiedText = string.Format(UI.Image_format_identified_by_0_1, imageFormat.Name, imageFormat.Id); ImageFormatText = !string.IsNullOrWhiteSpace(imageFormat.Info.Version) ? string.Format(Aaru.Localization.Core.Format_0_version_1_WithMarkup, imageFormat.Format, imageFormat.Info.Version) : string.Format(Aaru.Localization.Core.Format_0_WithMarkup, imageFormat.Format); ImageSizeText = string.Format(Aaru.Localization.Core.Image_without_headers_is_0_bytes_long, imageFormat.Info.ImageSize); SectorsText = string.Format(Aaru.Localization.Core .Contains_a_media_of_0_sectors_with_a_maximum_sector_size_of_1_bytes_etc, imageFormat.Info.Sectors, imageFormat.Info.SectorSize, ByteSize.FromBytes(imageFormat.Info.Sectors * imageFormat.Info.SectorSize).Humanize()); MediaTypeText = string.Format(Aaru.Localization.Core.Contains_a_media_of_type_0_and_XML_type_1_WithMarkup, imageFormat.Info.MediaType.Humanize(), imageFormat.Info.MetadataMediaType); HasPartitionsText = imageFormat.Info.HasPartitions ? Aaru.Localization.Core.Has_partitions : Aaru.Localization.Core.Doesnt_have_partitions; HasSessionsText = imageFormat.Info.HasSessions ? Aaru.Localization.Core.Has_sessions : Aaru.Localization.Core.Doesnt_have_sessions; if(!string.IsNullOrWhiteSpace(imageFormat.Info.Application)) { ApplicationText = !string.IsNullOrWhiteSpace(imageFormat.Info.ApplicationVersion) ? string.Format(Aaru.Localization.Core.Was_created_with_0_version_1_WithMarkup, imageFormat.Info.Application, imageFormat.Info.ApplicationVersion) : string.Format(Aaru.Localization.Core.Was_created_with_0_WithMarkup, imageFormat.Info.Application); } if(!string.IsNullOrWhiteSpace(imageFormat.Info.Creator)) CreatorText = string.Format(Aaru.Localization.Core.Created_by_0_WithMarkup, imageFormat.Info.Creator); if(imageFormat.Info.CreationTime != DateTime.MinValue) CreationTimeText = string.Format(Aaru.Localization.Core.Created_on_0, imageFormat.Info.CreationTime); if(imageFormat.Info.LastModificationTime != DateTime.MinValue) { LastModificationTimeText = string.Format(Aaru.Localization.Core.Last_modified_on_0, imageFormat.Info.LastModificationTime); } if(imageFormat.Info.MediaSequence != 0 && imageFormat.Info.LastMediaSequence != 0) { MediaSequenceText = string.Format(Aaru.Localization.Core.Media_is_number_0_on_a_set_of_1_medias, imageFormat.Info.MediaSequence, imageFormat.Info.LastMediaSequence); } if(!string.IsNullOrWhiteSpace(imageFormat.Info.MediaTitle)) { MediaTitleText = string.Format(Aaru.Localization.Core.Media_title_0_WithMarkup, imageFormat.Info.MediaTitle); } if(!string.IsNullOrWhiteSpace(imageFormat.Info.MediaManufacturer)) { MediaManufacturerText = string.Format(Aaru.Localization.Core.Media_manufacturer_0_WithMarkup, imageFormat.Info.MediaManufacturer); } if(!string.IsNullOrWhiteSpace(imageFormat.Info.MediaModel)) { MediaModelText = string.Format(Aaru.Localization.Core.Media_model_0_WithMarkup, imageFormat.Info.MediaModel); } if(!string.IsNullOrWhiteSpace(imageFormat.Info.MediaSerialNumber)) { MediaSerialNumberText = string.Format(Aaru.Localization.Core.Media_serial_number_0_WithMarkup, imageFormat.Info.MediaSerialNumber); } if(!string.IsNullOrWhiteSpace(imageFormat.Info.MediaBarcode)) { MediaBarcodeText = string.Format(Aaru.Localization.Core.Media_barcode_0_WithMarkup, imageFormat.Info.MediaBarcode); } if(!string.IsNullOrWhiteSpace(imageFormat.Info.MediaPartNumber)) { MediaPartNumberText = string.Format(Aaru.Localization.Core.Media_part_number_0_WithMarkup, imageFormat.Info.MediaPartNumber); } if(!string.IsNullOrWhiteSpace(imageFormat.Info.DriveManufacturer)) { DriveManufacturerText = string.Format(Aaru.Localization.Core.Drive_manufacturer_0_WithMarkup, imageFormat.Info.DriveManufacturer); } if(!string.IsNullOrWhiteSpace(imageFormat.Info.DriveModel)) { DriveModelText = string.Format(Aaru.Localization.Core.Drive_model_0_WithMarkup, imageFormat.Info.DriveModel); } if(!string.IsNullOrWhiteSpace(imageFormat.Info.DriveSerialNumber)) { DriveSerialNumberText = string.Format(Aaru.Localization.Core.Drive_serial_number_0_WithMarkup, imageFormat.Info.DriveSerialNumber); } if(!string.IsNullOrWhiteSpace(imageFormat.Info.DriveFirmwareRevision)) { DriveFirmwareRevisionText = string.Format(Aaru.Localization.Core.Drive_firmware_info_0_WithMarkup, imageFormat.Info.DriveFirmwareRevision); } if(imageFormat.Info.Cylinders > 0 && imageFormat.Info is { Heads: > 0, SectorsPerTrack: > 0 } && imageFormat.Info.MetadataMediaType != MetadataMediaType.OpticalDisc && imageFormat is not ITapeImage { IsTape: true }) { MediaGeometryText = string.Format(UI.Media_geometry_0_cylinders_1_heads_2_sectors_per_track, imageFormat.Info.Cylinders, imageFormat.Info.Heads, imageFormat.Info.SectorsPerTrack); } if(imageFormat.Info.ReadableMediaTags is { Count: > 0 }) { foreach(MediaTagType tag in imageFormat.Info.ReadableMediaTags.Order()) MediaTagsList.Add(tag.Humanize()); } if(imageFormat.Info.ReadableSectorTags is { Count: > 0 }) { foreach(SectorTagType tag in imageFormat.Info.ReadableSectorTags.Order()) SectorTagsList.Add(tag.Humanize()); } PeripheralDeviceTypes scsiDeviceType = PeripheralDeviceTypes.DirectAccess; byte[] scsiInquiryData = null; Inquiry? scsiInquiry = null; Modes.DecodedMode? scsiMode = null; byte[] scsiModeSense6 = null; byte[] scsiModeSense10 = null; ErrorNumber errno; if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.SCSI_INQUIRY) == true) { errno = imageFormat.ReadMediaTag(MediaTagType.SCSI_INQUIRY, out scsiInquiryData); if(errno == ErrorNumber.NoError) { scsiDeviceType = (PeripheralDeviceTypes)(scsiInquiryData[0] & 0x1F); scsiInquiry = Inquiry.Decode(scsiInquiryData); } } if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.SCSI_MODESENSE_6) == true) { errno = imageFormat.ReadMediaTag(MediaTagType.SCSI_MODESENSE_6, out scsiModeSense6); if(errno == ErrorNumber.NoError) scsiMode = Modes.DecodeMode6(scsiModeSense6, scsiDeviceType); } if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.SCSI_MODESENSE_10) == true) { errno = imageFormat.ReadMediaTag(MediaTagType.SCSI_MODESENSE_10, out scsiModeSense10); if(errno == ErrorNumber.NoError) scsiMode = Modes.DecodeMode10(scsiModeSense10, scsiDeviceType); } if(scsiInquiryData != null || scsiInquiry != null || scsiMode != null || scsiModeSense6 != null || scsiModeSense10 != null) { ScsiInfo = new ScsiInfo { DataContext = new ScsiInfoViewModel(scsiInquiryData, scsiInquiry, null, scsiMode, scsiDeviceType, scsiModeSense6, scsiModeSense10, null, view) }; } byte[] ataIdentify = null; byte[] atapiIdentify = null; errno = ErrorNumber.NoData; if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.ATA_IDENTIFY) == true) errno = imageFormat.ReadMediaTag(MediaTagType.ATA_IDENTIFY, out ataIdentify); else if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.ATAPI_IDENTIFY) == true) errno = imageFormat.ReadMediaTag(MediaTagType.ATAPI_IDENTIFY, out atapiIdentify); if(errno == ErrorNumber.NoError) { AtaInfo = new AtaInfo { DataContext = new AtaInfoViewModel(ataIdentify, atapiIdentify, null, view) }; } byte[] toc = null; TOC.CDTOC? decodedToc = null; byte[] fullToc = null; FullTOC.CDFullTOC? decodedFullToc = null; byte[] pma = null; byte[] atip = null; ATIP.CDATIP decodedAtip = null; byte[] cdtext = null; CDTextOnLeadIn.CDText? decodedCdText = null; string mediaCatalogueNumber = null; if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.CD_TOC) == true) { errno = imageFormat.ReadMediaTag(MediaTagType.CD_TOC, out toc); if(errno == ErrorNumber.NoError && toc.Length > 0) { ushort dataLen = Swapping.Swap(BitConverter.ToUInt16(toc, 0)); if(dataLen + 2 != toc.Length) { var tmp = new byte[toc.Length + 2]; Array.Copy(toc, 0, tmp, 2, toc.Length); tmp[0] = (byte)((toc.Length & 0xFF00) >> 8); tmp[1] = (byte)(toc.Length & 0xFF); toc = tmp; } decodedToc = TOC.Decode(toc); } } if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.CD_FullTOC) == true) { errno = imageFormat.ReadMediaTag(MediaTagType.CD_FullTOC, out fullToc); if(errno == ErrorNumber.NoError && fullToc.Length > 0) { ushort dataLen = Swapping.Swap(BitConverter.ToUInt16(fullToc, 0)); if(dataLen + 2 != fullToc.Length) { var tmp = new byte[fullToc.Length + 2]; Array.Copy(fullToc, 0, tmp, 2, fullToc.Length); tmp[0] = (byte)((fullToc.Length & 0xFF00) >> 8); tmp[1] = (byte)(fullToc.Length & 0xFF); fullToc = tmp; } decodedFullToc = FullTOC.Decode(fullToc); } } if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.CD_PMA) == true) { errno = imageFormat.ReadMediaTag(MediaTagType.CD_PMA, out pma); if(errno == ErrorNumber.NoError && pma.Length > 0) { ushort dataLen = Swapping.Swap(BitConverter.ToUInt16(pma, 0)); if(dataLen + 2 != pma.Length) { var tmp = new byte[pma.Length + 2]; Array.Copy(pma, 0, tmp, 2, pma.Length); tmp[0] = (byte)((pma.Length & 0xFF00) >> 8); tmp[1] = (byte)(pma.Length & 0xFF); pma = tmp; } } } if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.CD_ATIP) == true) { errno = imageFormat.ReadMediaTag(MediaTagType.CD_ATIP, out atip); if(errno == ErrorNumber.NoError) { uint dataLen = Swapping.Swap(BitConverter.ToUInt32(atip, 0)); if(dataLen + 4 != atip.Length) { var tmp = new byte[atip.Length + 4]; Array.Copy(atip, 0, tmp, 4, atip.Length); tmp[0] = (byte)((atip.Length & 0xFF000000) >> 24); tmp[1] = (byte)((atip.Length & 0xFF0000) >> 16); tmp[2] = (byte)((atip.Length & 0xFF00) >> 8); tmp[3] = (byte)(atip.Length & 0xFF); atip = tmp; } decodedAtip = ATIP.Decode(atip); } } if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.CD_TEXT) == true) { errno = imageFormat.ReadMediaTag(MediaTagType.CD_TEXT, out cdtext); if(errno == ErrorNumber.NoError) { uint dataLen = Swapping.Swap(BitConverter.ToUInt32(cdtext, 0)); if(dataLen + 4 != cdtext.Length) { var tmp = new byte[cdtext.Length + 4]; Array.Copy(cdtext, 0, tmp, 4, cdtext.Length); tmp[0] = (byte)((cdtext.Length & 0xFF000000) >> 24); tmp[1] = (byte)((cdtext.Length & 0xFF0000) >> 16); tmp[2] = (byte)((cdtext.Length & 0xFF00) >> 8); tmp[3] = (byte)(cdtext.Length & 0xFF); cdtext = tmp; } decodedCdText = CDTextOnLeadIn.Decode(cdtext); } } if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.CD_MCN) == true) { errno = imageFormat.ReadMediaTag(MediaTagType.CD_MCN, out byte[] mcn); if(errno == ErrorNumber.NoError) mediaCatalogueNumber = Encoding.UTF8.GetString(mcn); } if(toc != null || atip != null || fullToc != null || pma != null) { CompactDiscInfo = new CompactDiscInfo { DataContext = new CompactDiscInfoViewModel(toc, atip, null, null, fullToc, pma, cdtext, decodedToc, decodedAtip, null, decodedFullToc, decodedCdText, null, mediaCatalogueNumber, null, view) }; } byte[] dvdPfi = null; byte[] dvdDmi = null; byte[] dvdCmi = null; byte[] hddvdCopyrightInformation = null; byte[] dvdBca = null; PFI.PhysicalFormatInformation? decodedPfi = null; if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.DVD_PFI) == true) { errno = imageFormat.ReadMediaTag(MediaTagType.DVD_PFI, out dvdPfi); if(errno == ErrorNumber.NoError) decodedPfi = PFI.Decode(dvdPfi, imageFormat.Info.MediaType); } if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.DVD_DMI) == true) imageFormat.ReadMediaTag(MediaTagType.DVD_DMI, out dvdDmi); if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.DVD_CMI) == true) imageFormat.ReadMediaTag(MediaTagType.DVD_CMI, out dvdCmi); if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.HDDVD_CPI) == true) imageFormat.ReadMediaTag(MediaTagType.HDDVD_CPI, out hddvdCopyrightInformation); if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.DVD_BCA) == true) imageFormat.ReadMediaTag(MediaTagType.DVD_BCA, out dvdBca); if(dvdPfi != null || dvdDmi != null || dvdCmi != null || hddvdCopyrightInformation != null || dvdBca != null) { DvdInfo = new DvdInfo { DataContext = new DvdInfoViewModel(dvdPfi, dvdDmi, dvdCmi, hddvdCopyrightInformation, dvdBca, null, decodedPfi, view) }; } byte[] dvdRamDds = null; byte[] dvdRamCartridgeStatus = null; byte[] dvdRamSpareArea = null; byte[] lastBorderOutRmd = null; byte[] dvdPreRecordedInfo = null; byte[] dvdrMediaIdentifier = null; byte[] dvdrPhysicalInformation = null; byte[] hddvdrMediumStatus = null; byte[] dvdrLayerCapacity = null; byte[] dvdrDlMiddleZoneStart = null; byte[] dvdrDlJumpIntervalSize = null; byte[] dvdrDlManualLayerJumpStartLba = null; byte[] dvdPlusAdip = null; byte[] dvdPlusDcb = null; if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.DVDRAM_DDS) == true) imageFormat.ReadMediaTag(MediaTagType.DVDRAM_DDS, out dvdRamDds); if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.DVDRAM_MediumStatus) == true) imageFormat.ReadMediaTag(MediaTagType.DVDRAM_MediumStatus, out dvdRamCartridgeStatus); if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.DVDRAM_SpareArea) == true) imageFormat.ReadMediaTag(MediaTagType.DVDRAM_SpareArea, out dvdRamSpareArea); if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.DVDR_RMD) == true) imageFormat.ReadMediaTag(MediaTagType.DVDR_RMD, out lastBorderOutRmd); if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.DVDR_PreRecordedInfo) == true) imageFormat.ReadMediaTag(MediaTagType.DVDR_PreRecordedInfo, out dvdPreRecordedInfo); if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.DVDR_MediaIdentifier) == true) imageFormat.ReadMediaTag(MediaTagType.DVDR_MediaIdentifier, out dvdrMediaIdentifier); if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.DVDR_PFI) == true) imageFormat.ReadMediaTag(MediaTagType.DVDR_PFI, out dvdrPhysicalInformation); if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.HDDVD_MediumStatus) == true) imageFormat.ReadMediaTag(MediaTagType.HDDVD_MediumStatus, out hddvdrMediumStatus); if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.DVDDL_LayerCapacity) == true) imageFormat.ReadMediaTag(MediaTagType.DVDDL_LayerCapacity, out dvdrLayerCapacity); if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.DVDDL_MiddleZoneAddress) == true) imageFormat.ReadMediaTag(MediaTagType.DVDDL_MiddleZoneAddress, out dvdrDlMiddleZoneStart); if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.DVDDL_JumpIntervalSize) == true) imageFormat.ReadMediaTag(MediaTagType.DVDDL_JumpIntervalSize, out dvdrDlJumpIntervalSize); if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.DVDDL_ManualLayerJumpLBA) == true) imageFormat.ReadMediaTag(MediaTagType.DVDDL_ManualLayerJumpLBA, out dvdrDlManualLayerJumpStartLba); if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.DVD_ADIP) == true) imageFormat.ReadMediaTag(MediaTagType.DVD_ADIP, out dvdPlusAdip); if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.DCB) == true) imageFormat.ReadMediaTag(MediaTagType.DCB, out dvdPlusDcb); if(dvdRamDds != null || dvdRamCartridgeStatus != null || dvdRamSpareArea != null || lastBorderOutRmd != null || dvdPreRecordedInfo != null || dvdrMediaIdentifier != null || dvdrPhysicalInformation != null || hddvdrMediumStatus != null || dvdrLayerCapacity != null || dvdrDlMiddleZoneStart != null || dvdrDlJumpIntervalSize != null || dvdrDlManualLayerJumpStartLba != null || dvdPlusAdip != null || dvdPlusDcb != null) { DvdWritableInfo = new DvdWritableInfo { DataContext = new DvdWritableInfoViewModel(dvdRamDds, dvdRamCartridgeStatus, dvdRamSpareArea, lastBorderOutRmd, dvdPreRecordedInfo, dvdrMediaIdentifier, dvdrPhysicalInformation, hddvdrMediumStatus, null, dvdrLayerCapacity, dvdrDlMiddleZoneStart, dvdrDlJumpIntervalSize, dvdrDlManualLayerJumpStartLba, null, dvdPlusAdip, dvdPlusDcb, view) }; } byte[] blurayBurstCuttingArea = null; byte[] blurayCartridgeStatus = null; byte[] blurayDds = null; byte[] blurayDiscInformation = null; byte[] blurayPowResources = null; byte[] bluraySpareAreaInformation = null; byte[] blurayTrackResources = null; if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.BD_BCA) == true) imageFormat.ReadMediaTag(MediaTagType.BD_BCA, out blurayBurstCuttingArea); if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.BD_CartridgeStatus) == true) imageFormat.ReadMediaTag(MediaTagType.BD_CartridgeStatus, out blurayCartridgeStatus); if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.BD_DDS) == true) imageFormat.ReadMediaTag(MediaTagType.BD_DDS, out blurayDds); if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.BD_DI) == true) imageFormat.ReadMediaTag(MediaTagType.BD_DI, out blurayDiscInformation); if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.MMC_POWResourcesInformation) == true) imageFormat.ReadMediaTag(MediaTagType.MMC_POWResourcesInformation, out blurayPowResources); if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.BD_SpareArea) == true) imageFormat.ReadMediaTag(MediaTagType.BD_SpareArea, out bluraySpareAreaInformation); if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.MMC_TrackResourcesInformation) == true) imageFormat.ReadMediaTag(MediaTagType.MMC_TrackResourcesInformation, out blurayTrackResources); if(blurayDiscInformation != null || blurayBurstCuttingArea != null || blurayDds != null || blurayCartridgeStatus != null || bluraySpareAreaInformation != null || blurayPowResources != null || blurayTrackResources != null) { BlurayInfo = new BlurayInfo { DataContext = new BlurayInfoViewModel(blurayDiscInformation, blurayBurstCuttingArea, blurayDds, blurayCartridgeStatus, bluraySpareAreaInformation, blurayPowResources, blurayTrackResources, null, null, view) }; } byte[] xboxDmi = null; byte[] xboxSecuritySector = null; SS.SecuritySector? decodedXboxSecuritySector = null; if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.Xbox_DMI) == true) imageFormat.ReadMediaTag(MediaTagType.Xbox_DMI, out xboxDmi); if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.Xbox_SecuritySector) == true) { errno = imageFormat.ReadMediaTag(MediaTagType.Xbox_SecuritySector, out xboxSecuritySector); if(errno == ErrorNumber.NoError) decodedXboxSecuritySector = SS.Decode(xboxSecuritySector); } if(xboxDmi != null || xboxSecuritySector != null) { XboxInfo = new XboxInfo { DataContext = new XboxInfoViewModel(null, xboxDmi, xboxSecuritySector, decodedXboxSecuritySector, view) }; } errno = ErrorNumber.NoData; byte[] pcmciaCis = null; if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.PCMCIA_CIS) == true) errno = imageFormat.ReadMediaTag(MediaTagType.PCMCIA_CIS, out pcmciaCis); if(errno == ErrorNumber.NoError) { PcmciaInfo = new PcmciaInfo { DataContext = new PcmciaInfoViewModel(pcmciaCis, view) }; } DeviceType deviceType = DeviceType.Unknown; byte[] cid = null; byte[] csd = null; byte[] ocr = null; byte[] extendedCsd = null; byte[] scr = null; if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.SD_CID) == true) { imageFormat.ReadMediaTag(MediaTagType.SD_CID, out cid); deviceType = DeviceType.SecureDigital; } if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.SD_CSD) == true) { imageFormat.ReadMediaTag(MediaTagType.SD_CSD, out csd); deviceType = DeviceType.SecureDigital; } if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.SD_OCR) == true) { imageFormat.ReadMediaTag(MediaTagType.SD_OCR, out ocr); deviceType = DeviceType.SecureDigital; } if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.SD_SCR) == true) { imageFormat.ReadMediaTag(MediaTagType.SD_SCR, out scr); deviceType = DeviceType.SecureDigital; } if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.MMC_CID) == true) { imageFormat.ReadMediaTag(MediaTagType.MMC_CID, out cid); deviceType = DeviceType.MMC; } if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.MMC_CSD) == true) { imageFormat.ReadMediaTag(MediaTagType.MMC_CSD, out csd); deviceType = DeviceType.MMC; } if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.MMC_OCR) == true) { imageFormat.ReadMediaTag(MediaTagType.MMC_OCR, out ocr); deviceType = DeviceType.MMC; } if(imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.MMC_ExtendedCSD) == true) { imageFormat.ReadMediaTag(MediaTagType.MMC_ExtendedCSD, out extendedCsd); deviceType = DeviceType.MMC; } if(cid != null || csd != null || ocr != null || extendedCsd != null || scr != null) { SdMmcInfo = new SdMmcInfo { DataContext = new SdMmcInfoViewModel(deviceType, cid, csd, ocr, extendedCsd, scr) }; } if(imageFormat is IOpticalMediaImage opticalMediaImage) { try { if(opticalMediaImage.Sessions is { Count: > 0 }) foreach(Session session in opticalMediaImage.Sessions) Sessions.Add(session); } catch(Exception ex) { SentrySdk.CaptureException(ex); } try { if(opticalMediaImage.Tracks is { Count: > 0 }) foreach(Track track in opticalMediaImage.Tracks) Tracks.Add(track); } catch(Exception ex) { // ignored SentrySdk.CaptureException(ex); } } if(imageFormat.DumpHardware is null) return; foreach(DumpHardware dump in imageFormat.DumpHardware) { foreach(Extent extent in dump.Extents) { DumpHardwareList.Add(new DumpHardwareModel { Manufacturer = dump.Manufacturer, Model = dump.Model, Serial = dump.Serial, SoftwareName = dump.Software.Name, SoftwareVersion = dump.Software.Version, OperatingSystem = dump.Software.OperatingSystem, Start = extent.Start, End = extent.End }); } } } public ScsiInfo ScsiInfo { get; } public AtaInfo AtaInfo { get; } public CompactDiscInfo CompactDiscInfo { get; } public DvdInfo DvdInfo { get; } public DvdWritableInfo DvdWritableInfo { get; } public BlurayInfo BlurayInfo { get; } public XboxInfo XboxInfo { get; } public PcmciaInfo PcmciaInfo { get; } public SdMmcInfo SdMmcInfo { get; } public IImage MediaLogo { get; } public string ImagePathText { get; } public string FilterText { get; } public string ImageIdentifiedText { get; } public string MediaTypeText { get; set; } public string SectorsText { get; set; } public string HasPartitionsText { get; set; } public string HasSessionsText { get; set; } public string ApplicationText { get; set; } public string CreatorText { get; set; } public string CreationTimeText { get; set; } public string LastModificationTimeText { get; set; } public string MediaSequenceText { get; set; } public string MediaTitleText { get; set; } public string MediaManufacturerText { get; set; } public string MediaModelText { get; set; } public string MediaSerialNumberText { get; set; } public string MediaBarcodeText { get; set; } public string MediaPartNumberText { get; set; } public string CommentsText => _imageFormat.Info.Comments; public string DriveManufacturerText { get; set; } public string DriveModelText { get; set; } public string DriveSerialNumberText { get; set; } public string DriveFirmwareRevisionText { get; set; } public string MediaGeometryText { get; set; } public ObservableCollection MediaTagsList { get; } public ObservableCollection SectorTagsList { get; } public string ImageSizeText { get; set; } public string ImageFormatText { get; set; } public ObservableCollection Sessions { get; } public ObservableCollection Tracks { get; } public ObservableCollection DumpHardwareList { get; } public ICommand EntropyCommand { get; } public ICommand VerifyCommand { get; } public ICommand ChecksumCommand { get; } public ICommand ConvertCommand { get; } public ICommand CreateSidecarCommand { get; } public ICommand ViewSectorsCommand { get; } public ICommand DecodeMediaTagCommand { get; } public bool DriveInformationVisible => DriveManufacturerText != null || DriveModelText != null || DriveSerialNumberText != null || DriveFirmwareRevisionText != null || MediaGeometryText != null; public bool MediaInformationVisible => MediaSequenceText != null || MediaTitleText != null || MediaManufacturerText != null || MediaModelText != null || MediaSerialNumberText != null || MediaBarcodeText != null || MediaPartNumberText != null; void Entropy() { if(_imageEntropy != null) { _imageEntropy.Show(); return; } _imageEntropy = new ImageEntropy(); _imageEntropy.DataContext = new ImageEntropyViewModel(_imageFormat, _imageEntropy); _imageEntropy.Closed += (_, _) => _imageEntropy = null; _imageEntropy.Show(); } void Verify() { if(_imageVerify != null) { _imageVerify.Show(); return; } _imageVerify = new ImageVerify(); _imageVerify.DataContext = new ImageVerifyViewModel(_imageFormat, _imageVerify); _imageVerify.Closed += (_, _) => _imageVerify = null; _imageVerify.Show(); } void Checksum() { if(_imageChecksum != null) { _imageChecksum.Show(); return; } _imageChecksum = new ImageChecksum(); _imageChecksum.DataContext = new ImageChecksumViewModel(_imageFormat, _imageChecksum); _imageChecksum.Closed += (_, _) => _imageChecksum = null; _imageChecksum.Show(); } void Convert() { if(_imageConvert != null) { _imageConvert.Show(); return; } _imageConvert = new ImageConvert(); _imageConvert.DataContext = new ImageConvertViewModel(_imageFormat, _imagePath, _imageConvert); _imageConvert.Closed += (_, _) => _imageConvert = null; _imageConvert.Show(); } void CreateSidecar() { if(_imageSidecar != null) { _imageSidecar.Show(); return; } _imageSidecar = new ImageSidecar(); // TODO: Pass thru chosen default encoding _imageSidecar.DataContext = new ImageSidecarViewModel(_imageFormat, _imagePath, _filter.Id, null, _imageSidecar); _imageSidecar.Closed += (_, _) => _imageSidecar = null; _imageSidecar.Show(); } void ViewSectors() { if(_viewSector != null) { _viewSector.Show(); return; } _viewSector = new ViewSector { DataContext = new ViewSectorViewModel(_imageFormat) }; _viewSector.Closed += (_, _) => _viewSector = null; _viewSector.Show(); } void DecodeMediaTag() { if(_decodeMediaTags != null) { _decodeMediaTags.Show(); return; } _decodeMediaTags = new DecodeMediaTags { DataContext = new DecodeMediaTagsViewModel(_imageFormat) }; _decodeMediaTags.Closed += (_, _) => _decodeMediaTags = null; _decodeMediaTags.Show(); } }