Files
Aaru/Aaru.Images/AaruFormat/Helpers.cs

532 lines
36 KiB
C#

// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : Helpers.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Disk image plugins.
//
// --[ Description ] ----------------------------------------------------------
//
// Contains helpers for Aaru Format disk images.
//
// --[ License ] --------------------------------------------------------------
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2025 Natalia Portillo
// ****************************************************************************/
using System;
using Aaru.CommonTypes;
using Aaru.CommonTypes.Enums;
using Aaru.CommonTypes.Structs.Devices.ATA;
using Aaru.CommonTypes.Structs.Devices.SCSI;
using Aaru.Decoders.SecureDigital;
using Aaru.Helpers;
namespace Aaru.Images;
public sealed partial class AaruFormat
{
/// <summary>Checks for media tags that may contain metadata and sets it up if not already set</summary>
void SetMetadataFromTags()
{
// Search for SecureDigital CID
if(_mediaTags.TryGetValue(MediaTagType.SD_CID, out byte[] sdCid))
{
CID decoded = Decoders.SecureDigital.Decoders.DecodeCID(sdCid);
if(string.IsNullOrWhiteSpace(_imageInfo.DriveManufacturer))
_imageInfo.DriveManufacturer = VendorString.Prettify(decoded.Manufacturer);
if(string.IsNullOrWhiteSpace(_imageInfo.DriveModel)) _imageInfo.DriveModel = decoded.ProductName;
if(string.IsNullOrWhiteSpace(_imageInfo.DriveFirmwareRevision))
{
_imageInfo.DriveFirmwareRevision =
$"{(decoded.ProductRevision & 0xF0) >> 4:X2}.{decoded.ProductRevision & 0x0F:X2}";
}
if(string.IsNullOrWhiteSpace(_imageInfo.DriveSerialNumber))
_imageInfo.DriveSerialNumber = $"{decoded.ProductSerialNumber}";
}
// Search for MultiMediaCard CID
if(_mediaTags.TryGetValue(MediaTagType.MMC_CID, out byte[] mmcCid))
{
Decoders.MMC.CID decoded = Decoders.MMC.Decoders.DecodeCID(mmcCid);
if(string.IsNullOrWhiteSpace(_imageInfo.DriveManufacturer))
_imageInfo.DriveManufacturer = Decoders.MMC.VendorString.Prettify(decoded.Manufacturer);
if(string.IsNullOrWhiteSpace(_imageInfo.DriveModel)) _imageInfo.DriveModel = decoded.ProductName;
if(string.IsNullOrWhiteSpace(_imageInfo.DriveFirmwareRevision))
{
_imageInfo.DriveFirmwareRevision =
$"{(decoded.ProductRevision & 0xF0) >> 4:X2}.{decoded.ProductRevision & 0x0F:X2}";
}
if(string.IsNullOrWhiteSpace(_imageInfo.DriveSerialNumber))
_imageInfo.DriveSerialNumber = $"{decoded.ProductSerialNumber}";
}
// Search for SCSI INQUIRY
if(_mediaTags.TryGetValue(MediaTagType.SCSI_INQUIRY, out byte[] scsiInquiry))
{
Inquiry? nullableInquiry = Inquiry.Decode(scsiInquiry);
if(nullableInquiry.HasValue)
{
Inquiry inquiry = nullableInquiry.Value;
if(string.IsNullOrWhiteSpace(_imageInfo.DriveManufacturer))
_imageInfo.DriveManufacturer = StringHandlers.CToString(inquiry.VendorIdentification)?.Trim();
if(string.IsNullOrWhiteSpace(_imageInfo.DriveModel))
_imageInfo.DriveModel = StringHandlers.CToString(inquiry.ProductIdentification)?.Trim();
if(string.IsNullOrWhiteSpace(_imageInfo.DriveFirmwareRevision))
_imageInfo.DriveFirmwareRevision = StringHandlers.CToString(inquiry.ProductRevisionLevel)?.Trim();
}
}
// Search for ATA or ATAPI IDENTIFY
if(!_mediaTags.TryGetValue(MediaTagType.ATA_IDENTIFY, out byte[] ataIdentify) &&
!_mediaTags.TryGetValue(MediaTagType.ATAPI_IDENTIFY, out ataIdentify))
return;
Identify.IdentifyDevice? nullableIdentify = CommonTypes.Structs.Devices.ATA.Identify.Decode(ataIdentify);
if(!nullableIdentify.HasValue) return;
Identify.IdentifyDevice identify = nullableIdentify.Value;
string[] separated = identify.Model.Split(' ');
if(separated.Length == 1)
{
if(string.IsNullOrWhiteSpace(_imageInfo.DriveModel))
_imageInfo.DriveModel = separated[0];
else
{
if(string.IsNullOrWhiteSpace(_imageInfo.DriveManufacturer)) _imageInfo.DriveManufacturer = separated[0];
if(string.IsNullOrWhiteSpace(_imageInfo.DriveModel)) _imageInfo.DriveModel = separated[^1];
}
}
if(string.IsNullOrWhiteSpace(_imageInfo.DriveFirmwareRevision))
_imageInfo.DriveFirmwareRevision = identify.FirmwareRevision;
if(string.IsNullOrWhiteSpace(_imageInfo.DriveSerialNumber))
_imageInfo.DriveSerialNumber = identify.SerialNumber;
}
// Get the Aaru Metadata media type from Aaru media type
static MetadataMediaType GetMetadataMediaType(MediaType type)
{
return type switch
{
MediaType.CD
or MediaType.CDDA
or MediaType.CDG
or MediaType.CDEG
or MediaType.CDI
or MediaType.CDIREADY
or MediaType.CDROM
or MediaType.CDROMXA
or MediaType.CDPLUS
or MediaType.CDMO
or MediaType.CDR
or MediaType.CDRW
or MediaType.CDMRW
or MediaType.VCD
or MediaType.SVCD
or MediaType.PCD
or MediaType.SACD
or MediaType.DDCD
or MediaType.DDCDR
or MediaType.DDCDRW
or MediaType.DTSCD
or MediaType.CDMIDI
or MediaType.CDV
or MediaType.DVDROM
or MediaType.DVDR
or MediaType.DVDRW
or MediaType.DVDPR
or MediaType.DVDPRW
or MediaType.DVDPRWDL
or MediaType.DVDRDL
or MediaType.DVDPRDL
or MediaType.DVDRAM
or MediaType.DVDRWDL
or MediaType.DVDDownload
or MediaType.HDDVDROM
or MediaType.HDDVDRAM
or MediaType.HDDVDR
or MediaType.HDDVDRW
or MediaType.HDDVDRDL
or MediaType.HDDVDRWDL
or MediaType.BDROM
or MediaType.UHDBD
or MediaType.BDR
or MediaType.BDRE
or MediaType.BDRXL
or MediaType.BDREXL
or MediaType.EVD
or MediaType.FVD
or MediaType.HVD
or MediaType.CBHD
or MediaType.HDVMD
or MediaType.VCDHD
or MediaType.SVOD
or MediaType.FDDVD
or MediaType.LD
or MediaType.LDROM
or MediaType.CRVdisc
or MediaType.LDROM2
or MediaType.LVROM
or MediaType.MegaLD
or MediaType.PS1CD
or MediaType.PS2CD
or MediaType.PS2DVD
or MediaType.PS3DVD
or MediaType.PS3BD
or MediaType.PS4BD
or MediaType.PS5BD
or MediaType.UMD
or MediaType.XGD
or MediaType.XGD2
or MediaType.XGD3
or MediaType.XGD4
or MediaType.MEGACD
or MediaType.SATURNCD
or MediaType.GDROM
or MediaType.GDR
or MediaType.SuperCDROM2
or MediaType.JaguarCD
or MediaType.ThreeDO
or MediaType.PCFX
or MediaType.NeoGeoCD
or MediaType.GOD
or MediaType.WOD
or MediaType.WUOD
or MediaType.CDTV
or MediaType.CD32
or MediaType.Nuon
or MediaType.Playdia
or MediaType.Pippin
or MediaType.FMTOWNS
or MediaType.MilCD
or MediaType.VideoNow
or MediaType.VideoNowColor
or MediaType.VideoNowXp
or MediaType.CVD => MetadataMediaType.OpticalDisc,
_ => MetadataMediaType.BlockMedia
};
}
// Gets a DDT entry
ulong GetDdtEntry(ulong sectorAddress)
{
if(_inMemoryDdt) return _userDataDdt[sectorAddress];
if(_ddtEntryCache.TryGetValue(sectorAddress, out ulong entry)) return entry;
long oldPosition = _imageStream.Position;
_imageStream.Position = _outMemoryDdtPosition + Marshal.SizeOf<DdtHeader>();
_imageStream.Position += (long)(sectorAddress * sizeof(ulong));
var temp = new byte[sizeof(ulong)];
_imageStream.EnsureRead(temp, 0, sizeof(ulong));
_imageStream.Position = oldPosition;
entry = BitConverter.ToUInt64(temp, 0);
if(_ddtEntryCache.Count >= MAX_DDT_ENTRY_CACHE) _ddtEntryCache.Clear();
_ddtEntryCache.Add(sectorAddress, entry);
return entry;
}
// Sets a DDT entry
void SetDdtEntry(ulong sectorAddress, ulong pointer)
{
if(_inMemoryDdt)
{
if(IsTape)
_tapeDdt[sectorAddress] = pointer;
else
_userDataDdt[sectorAddress] = pointer;
return;
}
long oldPosition = _imageStream.Position;
_imageStream.Position = _outMemoryDdtPosition + Marshal.SizeOf<DdtHeader>();
_imageStream.Position += (long)(sectorAddress * sizeof(ulong));
_imageStream.Write(BitConverter.GetBytes(pointer), 0, sizeof(ulong));
_imageStream.Position = oldPosition;
}
// Converts between image data type and Aaru media tag type
static MediaTagType GetMediaTagTypeForDataType(DataType type) => type switch
{
DataType.CompactDiscPartialToc => MediaTagType
.CD_TOC,
DataType.CompactDiscSessionInfo => MediaTagType
.CD_SessionInfo,
DataType.CompactDiscToc => MediaTagType
.CD_FullTOC,
DataType.CompactDiscPma => MediaTagType.CD_PMA,
DataType.CompactDiscAtip => MediaTagType
.CD_ATIP,
DataType.CompactDiscLeadInCdText =>
MediaTagType.CD_TEXT,
DataType.DvdPfi => MediaTagType.DVD_PFI,
DataType.DvdLeadInCmi => MediaTagType.DVD_CMI,
DataType.DvdDiscKey =>
MediaTagType.DVD_DiscKey,
DataType.DvdBca => MediaTagType.DVD_BCA,
DataType.DvdDmi => MediaTagType.DVD_DMI,
DataType.DvdMediaIdentifier => MediaTagType
.DVD_MediaIdentifier,
DataType.DvdMediaKeyBlock => MediaTagType
.DVD_MKB,
DataType.DvdRamDds => MediaTagType.DVDRAM_DDS,
DataType.DvdRamMediumStatus => MediaTagType
.DVDRAM_MediumStatus,
DataType.DvdRamSpareArea => MediaTagType
.DVDRAM_SpareArea,
DataType.DvdRRmd => MediaTagType.DVDR_RMD,
DataType.DvdRPrerecordedInfo => MediaTagType
.DVDR_PreRecordedInfo,
DataType.DvdRMediaIdentifier => MediaTagType
.DVDR_MediaIdentifier,
DataType.DvdRPfi => MediaTagType.DVDR_PFI,
DataType.DvdAdip => MediaTagType.DVD_ADIP,
DataType.HdDvdCpi => MediaTagType.HDDVD_CPI,
DataType.HdDvdMediumStatus => MediaTagType
.HDDVD_MediumStatus,
DataType.DvdDlLayerCapacity => MediaTagType
.DVDDL_LayerCapacity,
DataType.DvdDlMiddleZoneAddress => MediaTagType
.DVDDL_MiddleZoneAddress,
DataType.DvdDlJumpIntervalSize => MediaTagType
.DVDDL_JumpIntervalSize,
DataType.DvdDlManualLayerJumpLba =>
MediaTagType.DVDDL_ManualLayerJumpLBA,
DataType.BlurayDi => MediaTagType.BD_DI,
DataType.BlurayBca => MediaTagType.BD_BCA,
DataType.BlurayDds => MediaTagType.BD_DDS,
DataType.BlurayCartridgeStatus => MediaTagType
.BD_CartridgeStatus,
DataType.BluraySpareArea => MediaTagType
.BD_SpareArea,
DataType.AacsVolumeIdentifier => MediaTagType
.AACS_VolumeIdentifier,
DataType.AacsSerialNumber => MediaTagType
.AACS_SerialNumber,
DataType.AacsMediaIdentifier => MediaTagType
.AACS_MediaIdentifier,
DataType.AacsMediaKeyBlock => MediaTagType
.AACS_MKB,
DataType.AacsDataKeys => MediaTagType
.AACS_DataKeys,
DataType.AacsLbaExtents => MediaTagType
.AACS_LBAExtents,
DataType.CprmMediaKeyBlock => MediaTagType
.AACS_CPRM_MKB,
DataType.HybridRecognizedLayers => MediaTagType
.Hybrid_RecognizedLayers,
DataType.ScsiMmcWriteProtection => MediaTagType
.MMC_WriteProtection,
DataType.ScsiMmcDiscInformation => MediaTagType
.MMC_DiscInformation,
DataType.ScsiMmcTrackResourcesInformation =>
MediaTagType.MMC_TrackResourcesInformation,
DataType.ScsiMmcPowResourcesInformation =>
MediaTagType.MMC_POWResourcesInformation,
DataType.ScsiInquiry => MediaTagType
.SCSI_INQUIRY,
DataType.ScsiModePage2A => MediaTagType
.SCSI_MODEPAGE_2A,
DataType.AtaIdentify => MediaTagType
.ATA_IDENTIFY,
DataType.AtapiIdentify => MediaTagType
.ATAPI_IDENTIFY,
DataType.PcmciaCis => MediaTagType.PCMCIA_CIS,
DataType.SecureDigitalCid => MediaTagType
.SD_CID,
DataType.SecureDigitalCsd => MediaTagType
.SD_CSD,
DataType.SecureDigitalScr => MediaTagType
.SD_SCR,
DataType.SecureDigitalOcr => MediaTagType
.SD_OCR,
DataType.MultiMediaCardCid => MediaTagType
.MMC_CID,
DataType.MultiMediaCardCsd => MediaTagType
.MMC_CSD,
DataType.MultiMediaCardOcr => MediaTagType
.MMC_OCR,
DataType.MultiMediaCardExtendedCsd =>
MediaTagType.MMC_ExtendedCSD,
DataType.XboxSecuritySector => MediaTagType
.Xbox_SecuritySector,
DataType.FloppyLeadOut => MediaTagType
.Floppy_LeadOut,
DataType.DvdDiscControlBlock => MediaTagType
.DCB,
DataType.CompactDiscFirstTrackPregap =>
MediaTagType.CD_FirstTrackPregap,
DataType.CompactDiscLeadOut => MediaTagType
.CD_LeadOut,
DataType.ScsiModeSense6 => MediaTagType
.SCSI_MODESENSE_6,
DataType.ScsiModeSense10 => MediaTagType
.SCSI_MODESENSE_10,
DataType.UsbDescriptors => MediaTagType
.USB_Descriptors,
DataType.XboxDmi => MediaTagType.Xbox_DMI,
DataType.XboxPfi => MediaTagType.Xbox_PFI,
DataType.CompactDiscMediaCatalogueNumber =>
MediaTagType.CD_MCN,
DataType.CompactDiscLeadIn => MediaTagType
.CD_LeadIn,
DataType.DvdDiscKeyDecrypted => MediaTagType
.DVD_DiscKey_Decrypted,
_ => throw new ArgumentOutOfRangeException()
};
// Converts between Aaru media tag type and image data type
static DataType GetDataTypeForMediaTag(MediaTagType tag) => tag switch
{
MediaTagType.CD_TOC => DataType
.CompactDiscPartialToc,
MediaTagType.CD_SessionInfo => DataType
.CompactDiscSessionInfo,
MediaTagType.CD_FullTOC => DataType.CompactDiscToc,
MediaTagType.CD_PMA => DataType.CompactDiscPma,
MediaTagType.CD_ATIP => DataType.CompactDiscAtip,
MediaTagType.CD_TEXT => DataType
.CompactDiscLeadInCdText,
MediaTagType.DVD_PFI => DataType.DvdPfi,
MediaTagType.DVD_CMI => DataType.DvdLeadInCmi,
MediaTagType.DVD_DiscKey => DataType.DvdDiscKey,
MediaTagType.DVD_BCA => DataType.DvdBca,
MediaTagType.DVD_DMI => DataType.DvdDmi,
MediaTagType.DVD_MediaIdentifier => DataType
.DvdMediaIdentifier,
MediaTagType.DVD_MKB => DataType.DvdMediaKeyBlock,
MediaTagType.DVDRAM_DDS => DataType.DvdRamDds,
MediaTagType.DVDRAM_MediumStatus => DataType
.DvdRamMediumStatus,
MediaTagType.DVDRAM_SpareArea => DataType
.DvdRamSpareArea,
MediaTagType.DVDR_RMD => DataType.DvdRRmd,
MediaTagType.DVDR_PreRecordedInfo => DataType
.DvdRPrerecordedInfo,
MediaTagType.DVDR_MediaIdentifier => DataType
.DvdRMediaIdentifier,
MediaTagType.DVDR_PFI => DataType.DvdRPfi,
MediaTagType.DVD_ADIP => DataType.DvdAdip,
MediaTagType.HDDVD_CPI => DataType.HdDvdCpi,
MediaTagType.HDDVD_MediumStatus => DataType
.HdDvdMediumStatus,
MediaTagType.DVDDL_LayerCapacity => DataType
.DvdDlLayerCapacity,
MediaTagType.DVDDL_MiddleZoneAddress => DataType
.DvdDlMiddleZoneAddress,
MediaTagType.DVDDL_JumpIntervalSize => DataType
.DvdDlJumpIntervalSize,
MediaTagType.DVDDL_ManualLayerJumpLBA => DataType
.DvdDlManualLayerJumpLba,
MediaTagType.BD_DI => DataType.BlurayDi,
MediaTagType.BD_BCA => DataType.BlurayBca,
MediaTagType.BD_DDS => DataType.BlurayDds,
MediaTagType.BD_CartridgeStatus => DataType
.BlurayCartridgeStatus,
MediaTagType.BD_SpareArea => DataType
.BluraySpareArea,
MediaTagType.AACS_VolumeIdentifier => DataType
.AacsVolumeIdentifier,
MediaTagType.AACS_SerialNumber => DataType
.AacsSerialNumber,
MediaTagType.AACS_MediaIdentifier => DataType
.AacsMediaIdentifier,
MediaTagType.AACS_MKB => DataType.AacsMediaKeyBlock,
MediaTagType.AACS_DataKeys => DataType.AacsDataKeys,
MediaTagType.AACS_LBAExtents => DataType
.AacsLbaExtents,
MediaTagType.AACS_CPRM_MKB => DataType
.CprmMediaKeyBlock,
MediaTagType.Hybrid_RecognizedLayers => DataType
.HybridRecognizedLayers,
MediaTagType.MMC_WriteProtection => DataType
.ScsiMmcWriteProtection,
MediaTagType.MMC_DiscInformation => DataType
.ScsiMmcDiscInformation,
MediaTagType.MMC_TrackResourcesInformation =>
DataType.ScsiMmcTrackResourcesInformation,
MediaTagType.MMC_POWResourcesInformation => DataType
.ScsiMmcPowResourcesInformation,
MediaTagType.SCSI_INQUIRY => DataType.ScsiInquiry,
MediaTagType.SCSI_MODEPAGE_2A => DataType
.ScsiModePage2A,
MediaTagType.ATA_IDENTIFY => DataType.AtaIdentify,
MediaTagType.ATAPI_IDENTIFY => DataType
.AtapiIdentify,
MediaTagType.PCMCIA_CIS => DataType.PcmciaCis,
MediaTagType.SD_CID => DataType.SecureDigitalCid,
MediaTagType.SD_CSD => DataType.SecureDigitalCsd,
MediaTagType.SD_SCR => DataType.SecureDigitalScr,
MediaTagType.SD_OCR => DataType.SecureDigitalOcr,
MediaTagType.MMC_CID => DataType.MultiMediaCardCid,
MediaTagType.MMC_CSD => DataType.MultiMediaCardCsd,
MediaTagType.MMC_OCR => DataType.MultiMediaCardOcr,
MediaTagType.MMC_ExtendedCSD => DataType
.MultiMediaCardExtendedCsd,
MediaTagType.Xbox_SecuritySector => DataType
.XboxSecuritySector,
MediaTagType.Floppy_LeadOut => DataType
.FloppyLeadOut,
MediaTagType.DCB => DataType.DvdDiscControlBlock,
MediaTagType.CD_FirstTrackPregap => DataType
.CompactDiscFirstTrackPregap,
MediaTagType.CD_LeadOut => DataType
.CompactDiscLeadOut,
MediaTagType.SCSI_MODESENSE_6 => DataType
.ScsiModeSense6,
MediaTagType.SCSI_MODESENSE_10 => DataType
.ScsiModeSense10,
MediaTagType.USB_Descriptors => DataType
.UsbDescriptors,
MediaTagType.Xbox_DMI => DataType.XboxDmi,
MediaTagType.Xbox_PFI => DataType.XboxPfi,
MediaTagType.CD_MCN => DataType
.CompactDiscMediaCatalogueNumber,
MediaTagType.CD_LeadIn =>
DataType.CompactDiscLeadIn,
MediaTagType.DVD_DiscKey_Decrypted => DataType
.DvdDiscKeyDecrypted,
_ => throw new
ArgumentOutOfRangeException(nameof(tag),
tag,
null)
};
}