Files
Aaru/Aaru.Core/Sidecar/OpticalDisc.cs

725 lines
29 KiB
C#
Raw Normal View History

2017-08-08 13:40:32 +01:00
// /***************************************************************************
2020-02-27 12:31:25 +00:00
// Aaru Data Preservation Suite
2017-08-08 13:40:32 +01:00
// ----------------------------------------------------------------------------
//
// Filename : OpticalDisc.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
2017-08-08 13:40:32 +01:00
//
// Component : Core algorithms.
2017-08-08 13:40:32 +01:00
//
// --[ Description ] ----------------------------------------------------------
//
// Contains logic to create sidecar from an optical media dump.
2017-08-08 13:40:32 +01:00
//
// --[ License ] --------------------------------------------------------------
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
2022-02-18 10:02:53 +00:00
// Copyright © 2011-2022 Natalia Portillo
2017-08-08 13:40:32 +01:00
// ****************************************************************************/
2022-03-07 07:36:44 +00:00
namespace Aaru.Core;
2017-12-21 14:30:38 +00:00
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
2020-02-27 00:33:26 +00:00
using Aaru.CommonTypes;
using Aaru.CommonTypes.Enums;
using Aaru.CommonTypes.Interfaces;
using Aaru.CommonTypes.Metadata;
using Aaru.CommonTypes.Structs;
using Aaru.Core.Devices.Dumping;
2020-02-27 00:33:26 +00:00
using Aaru.Decoders.CD;
using Aaru.Decoders.DVD;
2017-08-08 13:40:32 +01:00
using Schemas;
2020-02-27 00:33:26 +00:00
using DMI = Aaru.Decoders.Xbox.DMI;
using MediaType = Aaru.CommonTypes.MediaType;
using Session = Aaru.CommonTypes.Structs.Session;
2017-12-21 14:30:38 +00:00
using TrackType = Schemas.TrackType;
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
public sealed partial class Sidecar
2017-08-08 13:40:32 +01:00
{
2022-03-06 13:29:38 +00:00
/// <summary>Creates a metadata sidecar for an optical disc (e.g. CD, DVD, GD, BD, XGD, GOD)</summary>
/// <param name="image">Image</param>
/// <param name="filterId">Filter uuid</param>
/// <param name="imagePath">Image path</param>
/// <param name="fi">Image file information</param>
/// <param name="plugins">Image plugins</param>
/// <param name="imgChecksums">List of image checksums</param>
/// <param name="sidecar">Metadata sidecar</param>
/// <param name="encoding">Encoding to be used for filesystem plugins</param>
void OpticalDisc(IOpticalMediaImage image, Guid filterId, string imagePath, FileInfo fi, PluginBase plugins,
List<ChecksumType> imgChecksums, ref CICMMetadataType sidecar, Encoding encoding)
2017-08-08 13:40:32 +01:00
{
2022-03-06 13:29:38 +00:00
if(_aborted)
return;
2019-04-20 19:21:00 +01:00
2022-03-06 13:29:38 +00:00
sidecar.OpticalDisc = new[]
{
new OpticalDiscType
2017-08-08 14:18:31 +01:00
{
2022-03-06 13:29:38 +00:00
Checksums = imgChecksums.ToArray(),
Image = new ImageType
2017-12-19 20:33:03 +00:00
{
2022-03-06 13:29:38 +00:00
format = image.Format,
offset = 0,
offsetSpecified = true,
Value = Path.GetFileName(imagePath)
},
Size = (ulong)fi.Length,
Sequence = new SequenceType
{
MediaTitle = image.Info.MediaTitle
2017-08-08 14:18:31 +01:00
}
2017-08-08 13:40:32 +01:00
}
2022-03-06 13:29:38 +00:00
};
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
if(image.Info.MediaSequence != 0 &&
image.Info.LastMediaSequence != 0)
{
sidecar.OpticalDisc[0].Sequence.MediaSequence = (uint)image.Info.MediaSequence;
sidecar.OpticalDisc[0].Sequence.TotalMedia = (uint)image.Info.LastMediaSequence;
}
else
{
sidecar.OpticalDisc[0].Sequence.MediaSequence = 1;
sidecar.OpticalDisc[0].Sequence.TotalMedia = 1;
}
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
MediaType dskType = image.Info.MediaType;
ErrorNumber errno;
2022-03-06 13:29:38 +00:00
UpdateStatus("Hashing media tags...");
2019-04-20 19:21:00 +01:00
2022-03-06 13:29:38 +00:00
foreach(MediaTagType tagType in image.Info.ReadableMediaTags)
{
if(_aborted)
return;
2022-03-06 13:29:38 +00:00
errno = image.ReadMediaTag(tagType, out byte[] tag);
2022-03-06 13:29:38 +00:00
if(errno != ErrorNumber.NoError)
continue;
2022-03-06 13:29:38 +00:00
Dump.AddMediaTagToSidecar(imagePath, tagType, tag, ref sidecar);
2022-03-06 13:29:38 +00:00
switch(tagType)
{
case MediaTagType.CD_ATIP:
ATIP.CDATIP atip = ATIP.Decode(tag);
2022-03-06 13:29:38 +00:00
if(atip != null)
if(atip.DDCD)
dskType = atip.DiscType ? MediaType.DDCDRW : MediaType.DDCDR;
else
dskType = atip.DiscType ? MediaType.CDRW : MediaType.CDR;
2022-03-06 13:29:38 +00:00
break;
case MediaTagType.DVD_DMI:
if(DMI.IsXbox(tag))
{
dskType = MediaType.XGD;
sidecar.OpticalDisc[0].Dimensions = new DimensionsType
2017-08-08 13:40:32 +01:00
{
2022-03-06 13:29:38 +00:00
Diameter = 120,
Thickness = 1.2
};
}
else if(DMI.IsXbox360(tag))
{
dskType = MediaType.XGD2;
2022-03-06 13:29:38 +00:00
sidecar.OpticalDisc[0].Dimensions = new DimensionsType
{
Diameter = 120,
Thickness = 1.2
};
}
2022-03-06 13:29:38 +00:00
break;
case MediaTagType.DVD_PFI:
PFI.PhysicalFormatInformation? pfi = PFI.Decode(tag, dskType);
if(pfi.HasValue)
if(dskType != MediaType.XGD &&
dskType != MediaType.XGD2 &&
dskType != MediaType.XGD3 &&
dskType != MediaType.PS2DVD &&
dskType != MediaType.PS3DVD &&
dskType != MediaType.Nuon)
{
2022-11-13 19:59:24 +00:00
dskType = pfi.Value.DiskCategory switch
{
DiskCategory.DVDPR => MediaType.DVDPR,
DiskCategory.DVDPRDL => MediaType.DVDPRDL,
DiskCategory.DVDPRW => MediaType.DVDPRW,
DiskCategory.DVDPRWDL => MediaType.DVDPRWDL,
DiskCategory.DVDR => MediaType.DVDR,
DiskCategory.DVDRAM => MediaType.DVDRAM,
DiskCategory.DVDROM => MediaType.DVDROM,
DiskCategory.DVDRW => MediaType.DVDRW,
DiskCategory.HDDVDR => MediaType.HDDVDR,
DiskCategory.HDDVDRAM => MediaType.HDDVDRAM,
DiskCategory.HDDVDROM => MediaType.HDDVDROM,
DiskCategory.HDDVDRW => MediaType.HDDVDRW,
DiskCategory.Nintendo => MediaType.GOD,
DiskCategory.UMD => MediaType.UMD,
_ => dskType
};
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
if(dskType == MediaType.DVDR &&
pfi.Value.PartVersion >= 6)
dskType = MediaType.DVDRDL;
2022-03-06 13:29:38 +00:00
if(dskType == MediaType.DVDRW &&
pfi.Value.PartVersion >= 15)
dskType = MediaType.DVDRWDL;
2022-03-06 13:29:38 +00:00
if(dskType == MediaType.GOD &&
pfi.Value.DiscSize == DVDSize.OneTwenty)
dskType = MediaType.WOD;
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
sidecar.OpticalDisc[0].Dimensions = new DimensionsType();
2022-03-06 13:29:38 +00:00
if(dskType == MediaType.UMD)
{
sidecar.OpticalDisc[0].Dimensions.Height = 64;
sidecar.OpticalDisc[0].Dimensions.HeightSpecified = true;
sidecar.OpticalDisc[0].Dimensions.Width = 63;
sidecar.OpticalDisc[0].Dimensions.WidthSpecified = true;
sidecar.OpticalDisc[0].Dimensions.Thickness = 4;
}
else
switch(pfi.Value.DiscSize)
{
2022-03-06 13:29:38 +00:00
case DVDSize.Eighty:
sidecar.OpticalDisc[0].Dimensions.Diameter = 80;
sidecar.OpticalDisc[0].Dimensions.DiameterSpecified = true;
sidecar.OpticalDisc[0].Dimensions.Thickness = 1.2;
break;
case DVDSize.OneTwenty:
sidecar.OpticalDisc[0].Dimensions.Diameter = 120;
sidecar.OpticalDisc[0].Dimensions.DiameterSpecified = true;
sidecar.OpticalDisc[0].Dimensions.Thickness = 1.2;
break;
}
2022-03-06 13:29:38 +00:00
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break;
2019-04-20 19:21:00 +01:00
}
2022-03-06 13:29:38 +00:00
}
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
try
{
List<Session> sessions = image.Sessions;
sidecar.OpticalDisc[0].Sessions = (uint)(sessions?.Count ?? 1);
}
catch
{
sidecar.OpticalDisc[0].Sessions = 1;
}
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
List<Track> tracks = image.Tracks;
List<TrackType> trksLst = null;
2022-03-06 13:29:38 +00:00
if(tracks != null)
{
sidecar.OpticalDisc[0].Tracks = new uint[1];
sidecar.OpticalDisc[0].Tracks[0] = (uint)tracks.Count;
trksLst = new List<TrackType>();
}
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
if(sidecar.OpticalDisc[0].Dimensions == null &&
image.Info.MediaType != MediaType.Unknown)
sidecar.OpticalDisc[0].Dimensions = Dimensions.DimensionsFromMediaType(image.Info.MediaType);
2022-03-06 13:29:38 +00:00
if(_aborted)
return;
2019-04-20 19:21:00 +01:00
2022-03-06 13:29:38 +00:00
InitProgress();
2018-06-22 08:08:38 +01:00
2022-03-06 13:29:38 +00:00
UpdateStatus("Checking filesystems");
List<Partition> partitions = Partitions.GetAll(image);
Partitions.AddSchemesToStats(partitions);
2022-03-06 13:29:38 +00:00
UpdateStatus("Hashing tracks...");
2022-03-06 13:29:38 +00:00
foreach(Track trk in tracks)
{
if(_aborted)
2017-08-08 13:40:32 +01:00
{
2022-03-06 13:29:38 +00:00
EndProgress();
2022-03-06 13:29:38 +00:00
return;
}
2019-04-20 19:21:00 +01:00
2022-03-06 13:29:38 +00:00
var xmlTrk = new TrackType();
2022-11-13 19:59:24 +00:00
xmlTrk.TrackType1 = trk.Type switch
{
CommonTypes.Enums.TrackType.Audio => TrackTypeTrackType.audio,
CommonTypes.Enums.TrackType.CdMode2Form2 => TrackTypeTrackType.m2f2,
CommonTypes.Enums.TrackType.CdMode2Formless => TrackTypeTrackType.mode2,
CommonTypes.Enums.TrackType.CdMode2Form1 => TrackTypeTrackType.m2f1,
CommonTypes.Enums.TrackType.CdMode1 => TrackTypeTrackType.mode1,
CommonTypes.Enums.TrackType.Data => sidecar.OpticalDisc[0].DiscType switch
{
"BD" => TrackTypeTrackType.bluray,
"DDCD" => TrackTypeTrackType.ddcd,
"DVD" => TrackTypeTrackType.dvd,
"HD DVD" => TrackTypeTrackType.hddvd,
_ => TrackTypeTrackType.mode1
},
_ => xmlTrk.TrackType1
};
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
xmlTrk.Sequence = new TrackSequenceType
{
Session = trk.Session,
TrackNumber = trk.Sequence
};
2022-03-06 13:29:38 +00:00
xmlTrk.StartSector = trk.StartSector;
xmlTrk.EndSector = trk.EndSector;
2017-08-08 13:40:32 +01:00
2022-03-17 23:54:41 +00:00
int idx0;
2022-03-06 13:29:38 +00:00
if(trk.Indexes?.TryGetValue(0, out idx0) == true &&
idx0 >= 0)
xmlTrk.StartSector = (ulong)idx0;
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
switch(sidecar.OpticalDisc[0].DiscType)
{
case "CD":
case "GD":
xmlTrk.StartMSF = LbaToMsf((long)xmlTrk.StartSector);
xmlTrk.EndMSF = LbaToMsf((long)xmlTrk.EndSector);
2022-03-06 13:29:38 +00:00
break;
case "DDCD":
xmlTrk.StartMSF = DdcdLbaToMsf((long)xmlTrk.StartSector);
xmlTrk.EndMSF = DdcdLbaToMsf((long)xmlTrk.EndSector);
2022-03-06 13:29:38 +00:00
break;
}
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
xmlTrk.Image = new ImageType
{
Value = Path.GetFileName(trk.File),
format = trk.FileType
};
2017-08-08 14:18:31 +01:00
2022-03-06 13:29:38 +00:00
if(trk.FileOffset > 0)
{
xmlTrk.Image.offset = trk.FileOffset;
xmlTrk.Image.offsetSpecified = true;
}
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
xmlTrk.Size = (xmlTrk.EndSector - xmlTrk.StartSector + 1) * (ulong)trk.RawBytesPerSector;
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
xmlTrk.BytesPerSector = (uint)trk.BytesPerSector;
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
uint sectorsToRead = 512;
ulong sectors = xmlTrk.EndSector - xmlTrk.StartSector + 1;
ulong doneSectors = 0;
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
// If there is only one track, and it's the same as the image file (e.g. ".iso" files), don't re-checksum.
if(image.Id == new Guid("12345678-AAAA-BBBB-CCCC-123456789000") &&
2022-03-06 13:29:38 +00:00
// Only if filter is none...
(filterId == new Guid("12345678-AAAA-BBBB-CCCC-123456789000") ||
2022-03-06 13:29:38 +00:00
// ...or AppleDouble
filterId == new Guid("1b2165ee-c9df-4b21-bbbb-9e5892b2df4d")))
xmlTrk.Checksums = sidecar.OpticalDisc[0].Checksums;
else
{
UpdateProgress("Track {0} of {1}", trk.Sequence, tracks.Count);
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
// For fast debugging, skip checksum
//goto skipChecksum;
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
var trkChkWorker = new Checksum();
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
InitProgress2();
2022-03-06 13:29:38 +00:00
while(doneSectors < sectors)
{
if(_aborted)
2017-08-08 13:40:32 +01:00
{
2022-03-06 13:29:38 +00:00
EndProgress();
EndProgress2();
return;
}
byte[] sector;
if(sectors - doneSectors >= sectorsToRead)
{
errno = image.ReadSectorsLong(doneSectors, sectorsToRead, xmlTrk.Sequence.TrackNumber,
out sector);
UpdateProgress2("Hashing sector {0} of {1}", (long)doneSectors,
(long)(trk.EndSector - trk.StartSector + 1));
if(errno != ErrorNumber.NoError)
2019-04-20 19:21:00 +01:00
{
2022-03-06 13:29:38 +00:00
UpdateStatus($"Error {errno} reading sector {doneSectors}");
2019-04-20 19:21:00 +01:00
EndProgress2();
2019-04-20 19:21:00 +01:00
return;
}
2022-03-06 13:29:38 +00:00
doneSectors += sectorsToRead;
}
else
{
errno = image.ReadSectorsLong(doneSectors, (uint)(sectors - doneSectors),
xmlTrk.Sequence.TrackNumber, out sector);
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
UpdateProgress2("Hashing sector {0} of {1}", (long)doneSectors,
(long)(trk.EndSector - trk.StartSector + 1));
if(errno != ErrorNumber.NoError)
2017-08-08 13:40:32 +01:00
{
2022-03-06 13:29:38 +00:00
UpdateStatus($"Error {errno} reading sector {doneSectors}");
EndProgress2();
2022-03-06 13:29:38 +00:00
return;
}
2022-03-06 13:29:38 +00:00
doneSectors += sectors - doneSectors;
}
2022-03-06 13:29:38 +00:00
trkChkWorker.Update(sector);
}
2022-03-06 13:29:38 +00:00
List<ChecksumType> trkChecksums = trkChkWorker.End();
2022-03-06 13:29:38 +00:00
xmlTrk.Checksums = trkChecksums.ToArray();
2022-03-06 13:29:38 +00:00
EndProgress2();
}
2022-03-06 13:29:38 +00:00
if(trk.SubchannelType != TrackSubchannelType.None)
{
xmlTrk.SubChannel = new SubChannelType
{
Image = new ImageType
{
Value = trk.SubchannelFile
},
2022-03-06 13:29:38 +00:00
// TODO: Packed subchannel has different size?
Size = (xmlTrk.EndSector - xmlTrk.StartSector + 1) * 96
};
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
switch(trk.SubchannelType)
{
case TrackSubchannelType.Packed:
case TrackSubchannelType.PackedInterleaved:
xmlTrk.SubChannel.Image.format = "rw";
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
break;
case TrackSubchannelType.Raw:
case TrackSubchannelType.RawInterleaved:
xmlTrk.SubChannel.Image.format = "rw_raw";
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
break;
case TrackSubchannelType.Q16:
case TrackSubchannelType.Q16Interleaved:
xmlTrk.SubChannel.Image.format = "q16";
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
break;
2017-08-08 13:40:32 +01:00
}
2022-03-06 13:29:38 +00:00
if(trk.FileOffset > 0)
2017-08-08 13:40:32 +01:00
{
2022-03-06 13:29:38 +00:00
xmlTrk.SubChannel.Image.offset = trk.SubchannelOffset;
xmlTrk.SubChannel.Image.offsetSpecified = true;
}
2022-03-06 13:29:38 +00:00
var subChkWorker = new Checksum();
2022-03-06 13:29:38 +00:00
sectors = xmlTrk.EndSector - xmlTrk.StartSector + 1;
doneSectors = 0;
2022-03-06 13:29:38 +00:00
InitProgress2();
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
while(doneSectors < sectors)
{
if(_aborted)
2017-08-08 13:40:32 +01:00
{
2022-03-06 13:29:38 +00:00
EndProgress();
EndProgress2();
return;
2017-08-08 13:40:32 +01:00
}
2022-03-06 13:29:38 +00:00
byte[] sector;
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
if(sectors - doneSectors >= sectorsToRead)
{
errno = image.ReadSectorsTag(doneSectors, sectorsToRead, xmlTrk.Sequence.TrackNumber,
SectorTagType.CdSectorSubchannel, out sector);
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
UpdateProgress2("Hashing subchannel sector {0} of {1}", (long)doneSectors,
(long)(trk.EndSector - trk.StartSector + 1));
2022-03-06 13:29:38 +00:00
if(errno != ErrorNumber.NoError)
2019-04-20 19:21:00 +01:00
{
2022-03-06 13:29:38 +00:00
UpdateStatus($"Error {errno} reading sector {doneSectors}");
2019-04-20 19:21:00 +01:00
EndProgress2();
2019-04-20 19:21:00 +01:00
return;
}
2022-03-06 13:29:38 +00:00
doneSectors += sectorsToRead;
}
else
{
errno = image.ReadSectorsTag(doneSectors, (uint)(sectors - doneSectors),
xmlTrk.Sequence.TrackNumber, SectorTagType.CdSectorSubchannel,
out sector);
2022-03-06 13:29:38 +00:00
UpdateProgress2("Hashing subchannel sector {0} of {1}", (long)doneSectors,
(long)(trk.EndSector - trk.StartSector + 1));
2022-03-06 13:29:38 +00:00
if(errno != ErrorNumber.NoError)
2017-08-08 13:40:32 +01:00
{
2022-03-06 13:29:38 +00:00
UpdateStatus($"Error {errno} reading sector {doneSectors}");
EndProgress2();
2022-03-06 13:29:38 +00:00
return;
2017-08-08 13:40:32 +01:00
}
2022-03-06 13:29:38 +00:00
doneSectors += sectors - doneSectors;
2017-08-08 13:40:32 +01:00
}
2022-03-06 13:29:38 +00:00
subChkWorker.Update(sector);
2017-08-08 13:40:32 +01:00
}
2022-03-06 13:29:38 +00:00
List<ChecksumType> subChecksums = subChkWorker.End();
2022-03-06 13:29:38 +00:00
xmlTrk.SubChannel.Checksums = subChecksums.ToArray();
2019-04-20 19:21:00 +01:00
2022-03-06 13:29:38 +00:00
EndProgress2();
}
2022-03-06 13:29:38 +00:00
// For fast debugging, skip checksum
//skipChecksum:
2022-03-07 07:36:44 +00:00
var trkPartitions = partitions.Where(p => p.Start >= trk.StartSector && p.End <= trk.EndSector).ToList();
2022-03-06 13:29:38 +00:00
xmlTrk.FileSystemInformation = new PartitionType[1];
2022-03-06 13:29:38 +00:00
if(trkPartitions.Count > 0)
{
xmlTrk.FileSystemInformation = new PartitionType[trkPartitions.Count];
2017-08-08 13:40:32 +01:00
2022-03-07 07:36:44 +00:00
for(var i = 0; i < trkPartitions.Count; i++)
2017-08-08 13:40:32 +01:00
{
2022-03-06 13:29:38 +00:00
xmlTrk.FileSystemInformation[i] = new PartitionType
2017-08-08 14:18:31 +01:00
{
2022-03-06 13:29:38 +00:00
Description = trkPartitions[i].Description,
EndSector = trkPartitions[i].End,
Name = trkPartitions[i].Name,
Sequence = (uint)trkPartitions[i].Sequence,
StartSector = trkPartitions[i].Start,
Type = trkPartitions[i].Type
2017-08-08 14:18:31 +01:00
};
List<FileSystemType> lstFs = new();
2017-08-08 13:40:32 +01:00
foreach(IFilesystem plugin in plugins.PluginsList.Values)
2017-08-08 13:40:32 +01:00
try
{
2020-07-20 21:11:32 +01:00
if(_aborted)
2019-04-20 19:21:00 +01:00
{
EndProgress();
2019-04-20 19:21:00 +01:00
return;
}
2022-03-06 13:29:38 +00:00
if(!plugin.Identify(image, trkPartitions[i]))
continue;
2022-03-06 13:29:38 +00:00
plugin.GetInformation(image, trkPartitions[i], out _, encoding);
lstFs.Add(plugin.XmlFsType);
Statistics.AddFilesystem(plugin.XmlFsType.Type);
2022-11-13 19:59:24 +00:00
dskType = plugin.XmlFsType.Type switch
{
"Opera" => MediaType.ThreeDO,
"PC Engine filesystem" => MediaType.SuperCDROM2,
"Nintendo Wii filesystem" => MediaType.WOD,
"Nintendo Gamecube filesystem" => MediaType.GOD,
_ => dskType
};
2017-08-08 13:40:32 +01:00
}
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
2017-08-08 13:40:32 +01:00
catch
#pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body
2017-08-08 13:40:32 +01:00
{
2020-02-27 23:48:41 +00:00
//AaruConsole.DebugWriteLine("Create-sidecar command", "Plugin {0} crashed", _plugin.Name);
2017-08-08 13:40:32 +01:00
}
if(lstFs.Count > 0)
2022-03-06 13:29:38 +00:00
xmlTrk.FileSystemInformation[i].FileSystems = lstFs.ToArray();
2017-08-08 13:40:32 +01:00
}
2022-03-06 13:29:38 +00:00
}
else
{
xmlTrk.FileSystemInformation[0] = new PartitionType
{
EndSector = xmlTrk.EndSector,
StartSector = xmlTrk.StartSector
};
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
List<FileSystemType> lstFs = new();
2022-03-06 13:29:38 +00:00
var xmlPart = new Partition
{
2022-03-06 13:29:38 +00:00
Start = xmlTrk.StartSector,
Length = xmlTrk.EndSector - xmlTrk.StartSector + 1,
Type = xmlTrk.TrackType1.ToString(),
Size = xmlTrk.Size,
Sequence = xmlTrk.Sequence.TrackNumber
};
2022-03-06 13:29:38 +00:00
foreach(IFilesystem plugin in plugins.PluginsList.Values)
try
{
2022-03-06 13:29:38 +00:00
if(_aborted)
{
EndProgress();
2022-03-06 13:29:38 +00:00
return;
}
if(!plugin.Identify(image, xmlPart))
continue;
plugin.GetInformation(image, xmlPart, out _, encoding);
lstFs.Add(plugin.XmlFsType);
Statistics.AddFilesystem(plugin.XmlFsType.Type);
2022-11-13 19:59:24 +00:00
dskType = plugin.XmlFsType.Type switch
{
"Opera" => MediaType.ThreeDO,
"PC Engine filesystem" => MediaType.SuperCDROM2,
"Nintendo Wii filesystem" => MediaType.WOD,
"Nintendo Gamecube filesystem" => MediaType.GOD,
_ => dskType
};
2022-03-06 13:29:38 +00:00
}
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
catch
#pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body
{
2022-03-06 13:29:38 +00:00
//AaruConsole.DebugWriteLine("Create-sidecar command", "Plugin {0} crashed", _plugin.Name);
}
2022-03-06 13:29:38 +00:00
if(lstFs.Count > 0)
xmlTrk.FileSystemInformation[0].FileSystems = lstFs.ToArray();
2017-08-08 13:40:32 +01:00
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
errno = image.ReadSectorTag(trk.Sequence, SectorTagType.CdTrackIsrc, out byte[] isrcData);
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
if(errno == ErrorNumber.NoError)
xmlTrk.ISRC = Encoding.UTF8.GetString(isrcData);
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
errno = image.ReadSectorTag(trk.Sequence, SectorTagType.CdTrackFlags, out byte[] flagsData);
if(errno == ErrorNumber.NoError)
2017-08-08 13:40:32 +01:00
{
2022-03-06 13:29:38 +00:00
var trackFlags = (CdFlags)flagsData[0];
xmlTrk.Flags = new TrackFlagsType
{
PreEmphasis = trackFlags.HasFlag(CdFlags.PreEmphasis),
CopyPermitted = trackFlags.HasFlag(CdFlags.CopyPermitted),
Data = trackFlags.HasFlag(CdFlags.DataTrack),
Quadraphonic = trackFlags.HasFlag(CdFlags.FourChannel)
};
}
2022-03-06 13:29:38 +00:00
if(trk.Indexes?.Count > 0)
xmlTrk.Indexes = trk.Indexes?.OrderBy(i => i.Key).Select(i => new TrackIndexType
{
index = i.Key,
Value = i.Value
}).ToArray();
2017-08-08 13:40:32 +01:00
2022-03-06 13:29:38 +00:00
trksLst.Add(xmlTrk);
}
EndProgress();
if(trksLst != null)
sidecar.OpticalDisc[0].Track = trksLst.ToArray();
// All XGD3 all have the same number of blocks
if(dskType == MediaType.XGD2 &&
sidecar.OpticalDisc[0].Track.Length == 1)
{
2022-03-07 07:36:44 +00:00
ulong blocks = sidecar.OpticalDisc[0].Track[0].EndSector - sidecar.OpticalDisc[0].Track[0].StartSector + 1;
2022-03-06 13:29:38 +00:00
2022-03-16 11:47:00 +00:00
if(blocks is 25063 or 4229664 or 4246304) // Wxripper unlock
2022-03-06 13:29:38 +00:00
dskType = MediaType.XGD3;
}
(string type, string subType) discType = CommonTypes.Metadata.MediaType.MediaTypeToString(dskType);
sidecar.OpticalDisc[0].DiscType = discType.type;
sidecar.OpticalDisc[0].DiscSubType = discType.subType;
Statistics.AddMedia(dskType, false);
if(image.DumpHardware != null)
sidecar.OpticalDisc[0].DumpHardwareArray = image.DumpHardware.ToArray();
else if(!string.IsNullOrEmpty(image.Info.DriveManufacturer) ||
!string.IsNullOrEmpty(image.Info.DriveModel) ||
!string.IsNullOrEmpty(image.Info.DriveFirmwareRevision) ||
!string.IsNullOrEmpty(image.Info.DriveSerialNumber))
sidecar.OpticalDisc[0].DumpHardwareArray = new[]
{
new DumpHardwareType
2017-08-08 14:18:31 +01:00
{
2022-03-06 13:29:38 +00:00
Extents = new[]
2017-08-08 14:18:31 +01:00
{
2022-03-06 13:29:38 +00:00
new ExtentType
2017-08-08 14:18:31 +01:00
{
2022-03-06 13:29:38 +00:00
Start = 0,
End = image.Info.Sectors
2020-07-20 04:34:16 +01:00
}
2022-03-06 13:29:38 +00:00
},
Manufacturer = image.Info.DriveManufacturer,
Model = image.Info.DriveModel,
Firmware = image.Info.DriveFirmwareRevision,
Serial = image.Info.DriveSerialNumber,
Software = new SoftwareType
{
Name = image.Info.Application,
Version = image.Info.ApplicationVersion
2017-08-08 14:18:31 +01:00
}
2022-03-06 13:29:38 +00:00
}
};
2017-08-08 13:40:32 +01:00
}
2017-12-19 20:33:03 +00:00
}