Files
osrepodbmgr/osrepodbmgr.Core/Workers/DiscImageChef.cs

1123 lines
66 KiB
C#

//
// Author:
// Natalia Portillo claunia@claunia.com
//
// Copyright (c) 2017, © Claunia.com
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in
// the documentation and/or other materials provided with the distribution.
// * Neither the name of the [ORGANIZATION] nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
using System;
using System.Collections.Generic;
using System.IO;
using DiscImageChef.CommonTypes;
using DiscImageChef.Decoders.PCMCIA;
using DiscImageChef.Filesystems;
using DiscImageChef.Filters;
using DiscImageChef.DiscImages;
using DiscImageChef.Partitions;
using Schemas;
namespace osrepodbmgr.Core
{
public static partial class Workers
{
public static void AddMedia()
{
if(string.IsNullOrWhiteSpace(Context.selectedFile))
{
if(Failed != null)
Failed("There is no file set");
return;
}
string filesPath;
if(!string.IsNullOrEmpty(Context.tmpFolder) && Directory.Exists(Context.tmpFolder))
filesPath = Context.tmpFolder;
else
filesPath = Context.path;
string selectedFile = Path.Combine(filesPath, Context.selectedFile);
if(!File.Exists(selectedFile))
{
if(Failed != null)
Failed("Selected file does not exist");
return;
}
CICMMetadataType sidecar = new CICMMetadataType();
PluginBase plugins = new PluginBase();
IMediaImage _imageFormat;
long maxProgress = 4;
long currentProgress = 0;
FiltersList filtersList = new FiltersList();
if(UpdateProgress != null)
UpdateProgress(null, "Detecting image filter", 1, maxProgress);
IFilter inputFilter = filtersList.GetFilter(selectedFile);
if(inputFilter == null)
{
if(Failed != null)
Failed("Cannot open specified file.");
return;
}
try
{
#if DEBUG
stopwatch.Restart();
#endif
if(UpdateProgress != null)
UpdateProgress(null, "Detecting image format", 2, maxProgress);
_imageFormat = ImageFormat.Detect(inputFilter);
#if DEBUG
stopwatch.Stop();
Console.WriteLine("Core.AddMedia(): Took {0} seconds to detect image format", stopwatch.Elapsed.TotalSeconds);
#endif
if(_imageFormat == null)
{
if(Failed != null)
Failed("Image format not identified, not proceeding with analysis.");
return;
}
try
{
if(!_imageFormat.Open(inputFilter))
{
if(Failed != null)
Failed("Unable to open image format\n" +
"No error given");
return;
}
}
catch(Exception ex)
{
if(Failed != null)
Failed(string.Format("Unable to open image format\n" +
"Error: {0}", ex.Message));
#if DEBUG
Console.WriteLine("Exception {0}\n{1}", ex.Message, ex.InnerException);
#endif
return;
}
FileInfo fi = new FileInfo(selectedFile);
FileStream fs = new FileStream(selectedFile, FileMode.Open, FileAccess.Read);
Checksum imgChkWorker = new Checksum();
if(UpdateProgress != null)
UpdateProgress(null, "Hashing image file", 3, maxProgress);
#if DEBUG
stopwatch.Restart();
#endif
byte[] data;
long position = 0;
while(position < (fi.Length - 524288))
{
data = new byte[524288];
fs.Read(data, 0, 524288);
if(UpdateProgress2 != null)
UpdateProgress2(null, string.Format("{0} of {1} bytes", position, fi.Length), position, fi.Length);
imgChkWorker.Update(data);
position += 524288;
}
data = new byte[fi.Length - position];
fs.Read(data, 0, (int)(fi.Length - position));
if(UpdateProgress2 != null)
UpdateProgress2(null, string.Format("{0} of {1} bytes", position, fi.Length), position, fi.Length);
imgChkWorker.Update(data);
fs.Close();
#if DEBUG
stopwatch.Stop();
Console.WriteLine("Core.AddMedia(): Took {0} seconds to hash image file", stopwatch.Elapsed.TotalSeconds);
#endif
List<ChecksumType> imgChecksums = imgChkWorker.End();
if(UpdateProgress2 != null)
UpdateProgress2(null, null, 0, 0);
switch(_imageFormat.Info.XmlMediaType)
{
case XmlMediaType.OpticalDisc:
{
maxProgress = 4 + _imageFormat.Info.ReadableMediaTags.Count + _imageFormat.Tracks.Count;
if(UpdateProgress != null)
UpdateProgress(null, "Hashing image file", 3, maxProgress);
sidecar.OpticalDisc = new OpticalDiscType[1];
sidecar.OpticalDisc[0] = new OpticalDiscType();
sidecar.OpticalDisc[0].Checksums = imgChecksums.ToArray();
sidecar.OpticalDisc[0].Image = new ImageType();
sidecar.OpticalDisc[0].Image.format = _imageFormat.Format;
sidecar.OpticalDisc[0].Image.offset = 0;
sidecar.OpticalDisc[0].Image.offsetSpecified = true;
sidecar.OpticalDisc[0].Image.Value = Path.GetFileName(selectedFile);
sidecar.OpticalDisc[0].Size = fi.Length;
sidecar.OpticalDisc[0].Sequence = new SequenceType();
if(_imageFormat.Info.MediaSequence != 0 && _imageFormat.Info.LastMediaSequence != 0)
{
sidecar.OpticalDisc[0].Sequence.MediaSequence = _imageFormat.Info.MediaSequence;
sidecar.OpticalDisc[0].Sequence.TotalMedia = _imageFormat.Info.LastMediaSequence;
}
else
{
sidecar.OpticalDisc[0].Sequence.MediaSequence = 1;
sidecar.OpticalDisc[0].Sequence.TotalMedia = 1;
}
sidecar.OpticalDisc[0].Sequence.MediaTitle = _imageFormat.Info.MediaTitle;
MediaType dskType = _imageFormat.Info.MediaType;
currentProgress = 3;
#if DEBUG
stopwatch.Restart();
#endif
foreach(MediaTagType tagType in _imageFormat.Info.ReadableMediaTags)
{
currentProgress++;
if(UpdateProgress != null)
UpdateProgress(null, string.Format("Hashing file containing {0}", tagType), currentProgress, maxProgress);
switch(tagType)
{
case MediaTagType.CD_ATIP:
sidecar.OpticalDisc[0].ATIP = new DumpType();
sidecar.OpticalDisc[0].ATIP.Checksums = Checksum.GetChecksums(_imageFormat.ReadDiskTag(MediaTagType.CD_ATIP)).ToArray();
sidecar.OpticalDisc[0].ATIP.Size = _imageFormat.ReadDiskTag(MediaTagType.CD_ATIP).Length;
DiscImageChef.Decoders.CD.ATIP.CDATIP? atip = DiscImageChef.Decoders.CD.ATIP.Decode(_imageFormat.ReadDiskTag(MediaTagType.CD_ATIP));
if(atip.HasValue)
{
if(atip.Value.DDCD)
dskType = atip.Value.DiscType ? MediaType.DDCDRW : MediaType.DDCDR;
else
dskType = atip.Value.DiscType ? MediaType.CDRW : MediaType.CDR;
}
break;
case MediaTagType.DVD_BCA:
sidecar.OpticalDisc[0].BCA = new DumpType();
sidecar.OpticalDisc[0].BCA.Checksums = Checksum.GetChecksums(_imageFormat.ReadDiskTag(MediaTagType.DVD_BCA)).ToArray();
sidecar.OpticalDisc[0].BCA.Size = _imageFormat.ReadDiskTag(MediaTagType.DVD_BCA).Length;
break;
case MediaTagType.BD_BCA:
sidecar.OpticalDisc[0].BCA = new DumpType();
sidecar.OpticalDisc[0].BCA.Checksums = Checksum.GetChecksums(_imageFormat.ReadDiskTag(MediaTagType.BD_BCA)).ToArray();
sidecar.OpticalDisc[0].BCA.Size = _imageFormat.ReadDiskTag(MediaTagType.BD_BCA).Length;
break;
case MediaTagType.DVD_CMI:
sidecar.OpticalDisc[0].CMI = new DumpType();
DiscImageChef.Decoders.DVD.CSS_CPRM.LeadInCopyright? cmi = DiscImageChef.Decoders.DVD.CSS_CPRM.DecodeLeadInCopyright(_imageFormat.ReadDiskTag(MediaTagType.DVD_CMI));
if(cmi.HasValue)
{
switch(cmi.Value.CopyrightType)
{
case DiscImageChef.Decoders.DVD.CopyrightType.AACS:
sidecar.OpticalDisc[0].CopyProtection = "AACS";
break;
case DiscImageChef.Decoders.DVD.CopyrightType.CSS:
sidecar.OpticalDisc[0].CopyProtection = "CSS";
break;
case DiscImageChef.Decoders.DVD.CopyrightType.CPRM:
sidecar.OpticalDisc[0].CopyProtection = "CPRM";
break;
}
}
sidecar.OpticalDisc[0].CMI.Checksums = Checksum.GetChecksums(_imageFormat.ReadDiskTag(MediaTagType.DVD_CMI)).ToArray();
sidecar.OpticalDisc[0].CMI.Size = _imageFormat.ReadDiskTag(MediaTagType.DVD_CMI).Length;
break;
case MediaTagType.DVD_DMI:
sidecar.OpticalDisc[0].DMI = new DumpType();
sidecar.OpticalDisc[0].DMI.Checksums = Checksum.GetChecksums(_imageFormat.ReadDiskTag(MediaTagType.DVD_DMI)).ToArray();
sidecar.OpticalDisc[0].DMI.Size = _imageFormat.ReadDiskTag(MediaTagType.DVD_DMI).Length;
if(DiscImageChef.Decoders.Xbox.DMI.IsXbox(_imageFormat.ReadDiskTag(MediaTagType.DVD_DMI)))
{
dskType = MediaType.XGD;
sidecar.OpticalDisc[0].Dimensions = new DimensionsType();
sidecar.OpticalDisc[0].Dimensions.Diameter = 120;
}
else if(DiscImageChef.Decoders.Xbox.DMI.IsXbox360(_imageFormat.ReadDiskTag(MediaTagType.DVD_DMI)))
{
dskType = MediaType.XGD2;
sidecar.OpticalDisc[0].Dimensions = new DimensionsType();
sidecar.OpticalDisc[0].Dimensions.Diameter = 120;
}
break;
case MediaTagType.DVD_PFI:
sidecar.OpticalDisc[0].PFI = new DumpType();
sidecar.OpticalDisc[0].PFI.Checksums = Checksum.GetChecksums(_imageFormat.ReadDiskTag(MediaTagType.DVD_PFI)).ToArray();
sidecar.OpticalDisc[0].PFI.Size = _imageFormat.ReadDiskTag(MediaTagType.DVD_PFI).Length;
DiscImageChef.Decoders.DVD.PFI.PhysicalFormatInformation? pfi = DiscImageChef.Decoders.DVD.PFI.Decode(_imageFormat.ReadDiskTag(MediaTagType.DVD_PFI));
if(pfi.HasValue)
{
if(dskType != MediaType.XGD &&
dskType != MediaType.XGD2 &&
dskType != MediaType.XGD3)
{
switch(pfi.Value.DiskCategory)
{
case DiscImageChef.Decoders.DVD.DiskCategory.DVDPR:
dskType = MediaType.DVDPR;
break;
case DiscImageChef.Decoders.DVD.DiskCategory.DVDPRDL:
dskType = MediaType.DVDPRDL;
break;
case DiscImageChef.Decoders.DVD.DiskCategory.DVDPRW:
dskType = MediaType.DVDPRW;
break;
case DiscImageChef.Decoders.DVD.DiskCategory.DVDPRWDL:
dskType = MediaType.DVDPRWDL;
break;
case DiscImageChef.Decoders.DVD.DiskCategory.DVDR:
dskType = MediaType.DVDR;
break;
case DiscImageChef.Decoders.DVD.DiskCategory.DVDRAM:
dskType = MediaType.DVDRAM;
break;
case DiscImageChef.Decoders.DVD.DiskCategory.DVDROM:
dskType = MediaType.DVDROM;
break;
case DiscImageChef.Decoders.DVD.DiskCategory.DVDRW:
dskType = MediaType.DVDRW;
break;
case DiscImageChef.Decoders.DVD.DiskCategory.HDDVDR:
dskType = MediaType.HDDVDR;
break;
case DiscImageChef.Decoders.DVD.DiskCategory.HDDVDRAM:
dskType = MediaType.HDDVDRAM;
break;
case DiscImageChef.Decoders.DVD.DiskCategory.HDDVDROM:
dskType = MediaType.HDDVDROM;
break;
case DiscImageChef.Decoders.DVD.DiskCategory.HDDVDRW:
dskType = MediaType.HDDVDRW;
break;
case DiscImageChef.Decoders.DVD.DiskCategory.Nintendo:
dskType = MediaType.GOD;
break;
case DiscImageChef.Decoders.DVD.DiskCategory.UMD:
dskType = MediaType.UMD;
break;
}
if(dskType == MediaType.DVDR && pfi.Value.PartVersion == 6)
dskType = MediaType.DVDRDL;
if(dskType == MediaType.DVDRW && pfi.Value.PartVersion == 3)
dskType = MediaType.DVDRWDL;
if(dskType == MediaType.GOD && pfi.Value.DiscSize == DiscImageChef.Decoders.DVD.DVDSize.OneTwenty)
dskType = MediaType.WOD;
sidecar.OpticalDisc[0].Dimensions = new DimensionsType();
if(dskType == MediaType.UMD)
sidecar.OpticalDisc[0].Dimensions.Diameter = 60;
else if(pfi.Value.DiscSize == DiscImageChef.Decoders.DVD.DVDSize.Eighty)
sidecar.OpticalDisc[0].Dimensions.Diameter = 80;
else if(pfi.Value.DiscSize == DiscImageChef.Decoders.DVD.DVDSize.OneTwenty)
sidecar.OpticalDisc[0].Dimensions.Diameter = 120;
}
}
break;
case MediaTagType.CD_PMA:
sidecar.OpticalDisc[0].PMA = new DumpType();
sidecar.OpticalDisc[0].PMA.Checksums = Checksum.GetChecksums(_imageFormat.ReadDiskTag(MediaTagType.CD_PMA)).ToArray();
sidecar.OpticalDisc[0].PMA.Size = _imageFormat.ReadDiskTag(MediaTagType.CD_PMA).Length;
break;
}
}
#if DEBUG
stopwatch.Stop();
Console.WriteLine("Core.AddMedia(): Took {0} seconds to hash media tags", stopwatch.Elapsed.TotalSeconds);
#endif
try
{
List<Session> sessions = _imageFormat.Sessions;
sidecar.OpticalDisc[0].Sessions = sessions != null ? sessions.Count : 1;
}
catch
{
sidecar.OpticalDisc[0].Sessions = 1;
}
List<Track> tracks = _imageFormat.Tracks;
List<Schemas.TrackType> trksLst = null;
if(tracks != null)
{
sidecar.OpticalDisc[0].Tracks = new int[1];
sidecar.OpticalDisc[0].Tracks[0] = tracks.Count;
trksLst = new List<Schemas.TrackType>();
}
foreach(Track trk in tracks)
{
currentProgress++;
Schemas.TrackType xmlTrk = new Schemas.TrackType();
switch(trk.TrackType)
{
case DiscImageChef.DiscImages.TrackType.Audio:
xmlTrk.TrackType1 = TrackTypeTrackType.audio;
break;
case DiscImageChef.DiscImages.TrackType.CdMode2Form2:
xmlTrk.TrackType1 = TrackTypeTrackType.m2f2;
break;
case DiscImageChef.DiscImages.TrackType.CdMode2Formless:
xmlTrk.TrackType1 = TrackTypeTrackType.mode2;
break;
case DiscImageChef.DiscImages.TrackType.CdMode2Form1:
xmlTrk.TrackType1 = TrackTypeTrackType.m2f1;
break;
case DiscImageChef.DiscImages.TrackType.CdMode1:
xmlTrk.TrackType1 = TrackTypeTrackType.mode1;
break;
case DiscImageChef.DiscImages.TrackType.Data:
switch(sidecar.OpticalDisc[0].DiscType)
{
case "BD":
xmlTrk.TrackType1 = TrackTypeTrackType.bluray;
break;
case "DDCD":
xmlTrk.TrackType1 = TrackTypeTrackType.ddcd;
break;
case "DVD":
xmlTrk.TrackType1 = TrackTypeTrackType.dvd;
break;
case "HD DVD":
xmlTrk.TrackType1 = TrackTypeTrackType.hddvd;
break;
default:
xmlTrk.TrackType1 = TrackTypeTrackType.mode1;
break;
}
break;
}
xmlTrk.Sequence = new TrackSequenceType();
xmlTrk.Sequence.Session = trk.TrackSession;
xmlTrk.Sequence.TrackNumber = (int)trk.TrackSequence;
xmlTrk.StartSector = (long)trk.TrackStartSector;
xmlTrk.EndSector = (long)trk.TrackEndSector;
if(trk.Indexes != null && trk.Indexes.ContainsKey(0))
{
ulong idx0;
if(trk.Indexes.TryGetValue(0, out idx0))
xmlTrk.StartSector = (long)idx0;
}
if(sidecar.OpticalDisc[0].DiscType == "CD" ||
sidecar.OpticalDisc[0].DiscType == "GD")
{
xmlTrk.StartMSF = LbaToMsf(xmlTrk.StartSector);
xmlTrk.EndMSF = LbaToMsf(xmlTrk.EndSector);
}
else if(sidecar.OpticalDisc[0].DiscType == "DDCD")
{
xmlTrk.StartMSF = DdcdLbaToMsf(xmlTrk.StartSector);
xmlTrk.EndMSF = DdcdLbaToMsf(xmlTrk.EndSector);
}
xmlTrk.Image = new ImageType();
xmlTrk.Image.Value = Path.GetFileName(trk.TrackFile);
if(trk.TrackFileOffset > 0)
{
xmlTrk.Image.offset = (long)trk.TrackFileOffset;
xmlTrk.Image.offsetSpecified = true;
}
xmlTrk.Image.format = trk.TrackFileType;
xmlTrk.Size = (xmlTrk.EndSector - xmlTrk.StartSector + 1) * trk.TrackRawBytesPerSector;
xmlTrk.BytesPerSector = trk.TrackBytesPerSector;
uint sectorsToRead = 512;
ulong sectors = (ulong)(xmlTrk.EndSector - xmlTrk.StartSector + 1);
ulong doneSectors = 0;
// If there is only one track, and it's the same as the image file (e.g. ".iso" files), don't re-checksum.
if(_imageFormat.Id == new Guid("12345678-AAAA-BBBB-CCCC-123456789000"))
{
xmlTrk.Checksums = sidecar.OpticalDisc[0].Checksums;
}
else
{
if(UpdateProgress != null)
UpdateProgress(null, string.Format("Hashing track {0}", trk.TrackSequence), currentProgress, maxProgress);
Checksum trkChkWorker = new Checksum();
#if DEBUG
stopwatch.Restart();
#endif
while(doneSectors < sectors)
{
byte[] sector;
if((sectors - doneSectors) >= sectorsToRead)
{
sector = _imageFormat.ReadSectorsLong(doneSectors, sectorsToRead, (uint)xmlTrk.Sequence.TrackNumber);
if(UpdateProgress2 != null)
UpdateProgress2(null, string.Format("Sector {0} of {1}", doneSectors, sectors), (long)doneSectors, (long)sectors);
doneSectors += sectorsToRead;
}
else
{
sector = _imageFormat.ReadSectorsLong(doneSectors, (uint)(sectors - doneSectors), (uint)xmlTrk.Sequence.TrackNumber);
if(UpdateProgress2 != null)
UpdateProgress2(null, string.Format("Sector {0} of {1}", doneSectors, sectors), (long)doneSectors, (long)sectors);
doneSectors += (sectors - doneSectors);
}
trkChkWorker.Update(sector);
}
List<ChecksumType> trkChecksums = trkChkWorker.End();
#if DEBUG
stopwatch.Stop();
Console.WriteLine("Core.AddMedia(): Took {0} seconds to hash track {1}", stopwatch.Elapsed.TotalSeconds, trk.TrackSequence);
#endif
xmlTrk.Checksums = trkChecksums.ToArray();
}
if(UpdateProgress2 != null)
UpdateProgress2(null, null, 0, 0);
if(trk.TrackSubchannelType != TrackSubchannelType.None)
{
if(UpdateProgress != null)
UpdateProgress(null, string.Format("Hashing subchannel of track {0}", trk.TrackSequence), currentProgress, maxProgress);
xmlTrk.SubChannel = new SubChannelType();
xmlTrk.SubChannel.Image = new ImageType();
switch(trk.TrackSubchannelType)
{
case TrackSubchannelType.Packed:
case TrackSubchannelType.PackedInterleaved:
xmlTrk.SubChannel.Image.format = "rw";
break;
case TrackSubchannelType.Raw:
case TrackSubchannelType.RawInterleaved:
xmlTrk.SubChannel.Image.format = "rw_raw";
break;
case TrackSubchannelType.Q16:
case TrackSubchannelType.Q16Interleaved:
xmlTrk.SubChannel.Image.format = "q16";
break;
}
if(trk.TrackFileOffset > 0)
{
xmlTrk.SubChannel.Image.offset = (long)trk.TrackSubchannelOffset;
xmlTrk.SubChannel.Image.offsetSpecified = true;
}
xmlTrk.SubChannel.Image.Value = trk.TrackSubchannelFile;
// TODO: Packed subchannel has different size?
xmlTrk.SubChannel.Size = (xmlTrk.EndSector - xmlTrk.StartSector + 1) * 96;
Checksum subChkWorker = new Checksum();
sectors = (ulong)(xmlTrk.EndSector - xmlTrk.StartSector + 1);
doneSectors = 0;
#if DEBUG
stopwatch.Restart();
#endif
while(doneSectors < sectors)
{
byte[] sector;
if((sectors - doneSectors) >= sectorsToRead)
{
sector = _imageFormat.ReadSectorsTag(doneSectors, sectorsToRead, (uint)xmlTrk.Sequence.TrackNumber, SectorTagType.CdSectorSubchannel);
if(UpdateProgress2 != null)
UpdateProgress2(null, string.Format("Sector {0} of {1}", doneSectors, sectors), position, fi.Length);
doneSectors += sectorsToRead;
}
else
{
sector = _imageFormat.ReadSectorsTag(doneSectors, (uint)(sectors - doneSectors), (uint)xmlTrk.Sequence.TrackNumber, SectorTagType.CdSectorSubchannel);
if(UpdateProgress2 != null)
UpdateProgress2(null, string.Format("Sector {0} of {1}", doneSectors, sectors), position, fi.Length);
doneSectors += (sectors - doneSectors);
}
subChkWorker.Update(sector);
}
List<ChecksumType> subChecksums = subChkWorker.End();
xmlTrk.SubChannel.Checksums = subChecksums.ToArray();
#if DEBUG
stopwatch.Stop();
Console.WriteLine("Core.AddMedia(): Took {0} seconds to hash subchannel of track {1}", stopwatch.Elapsed.TotalSeconds, trk.TrackSequence);
#endif
if(UpdateProgress2 != null)
UpdateProgress2(null, null, 0, 0);
}
if(UpdateProgress != null)
UpdateProgress(null, "Checking filesystems", maxProgress - 1, maxProgress);
#if DEBUG
stopwatch.Restart();
#endif
List<Partition> partitions = new List<Partition>();
foreach(IPartition _partplugin in plugins.PartPluginsList.Values)
{
List<Partition> _partitions;
if(_partplugin.GetInformation(_imageFormat, out _partitions, 0)) // TODO: Subpartitions
partitions.AddRange(_partitions);
}
xmlTrk.FileSystemInformation = new PartitionType[1];
if(partitions.Count > 0)
{
xmlTrk.FileSystemInformation = new PartitionType[partitions.Count];
for(int i = 0; i < partitions.Count; i++)
{
xmlTrk.FileSystemInformation[i] = new PartitionType();
xmlTrk.FileSystemInformation[i].Description = partitions[i].Description;
xmlTrk.FileSystemInformation[i].EndSector = (int)(partitions[i].End);
xmlTrk.FileSystemInformation[i].Name = partitions[i].Name;
xmlTrk.FileSystemInformation[i].Sequence = (int)partitions[i].Sequence;
xmlTrk.FileSystemInformation[i].StartSector = (int)partitions[i].Start;
xmlTrk.FileSystemInformation[i].Type = partitions[i].Type;
List<FileSystemType> lstFs = new List<FileSystemType>();
foreach(IFilesystem _plugin in plugins.PluginsList.Values)
{
try
{
if(_plugin.Identify(_imageFormat, partitions[i]))
{
string foo;
_plugin.GetInformation(_imageFormat, partitions[i], out foo, null);
lstFs.Add(_plugin.XmlFsType);
if(_plugin.XmlFsType.Type == "Opera")
dskType = MediaType.ThreeDO;
if(_plugin.XmlFsType.Type == "PC Engine filesystem")
dskType = MediaType.SuperCDROM2;
if(_plugin.XmlFsType.Type == "Nintendo Wii filesystem")
dskType = MediaType.WOD;
if(_plugin.XmlFsType.Type == "Nintendo Gamecube filesystem")
dskType = MediaType.GOD;
}
}
#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
{
//DicConsole.DebugWriteLine("Create-sidecar command", "Plugin {0} crashed", _plugin.Name);
}
}
if(lstFs.Count > 0)
xmlTrk.FileSystemInformation[i].FileSystems = lstFs.ToArray();
}
}
else
{
xmlTrk.FileSystemInformation[0] = new PartitionType();
xmlTrk.FileSystemInformation[0].EndSector = (int)xmlTrk.EndSector;
xmlTrk.FileSystemInformation[0].StartSector = (int)xmlTrk.StartSector;
Partition xmlPart = new Partition
{
Start = (ulong)xmlTrk.StartSector,
Length = (ulong)((xmlTrk.EndSector - xmlTrk.StartSector) + 1)
};
List<FileSystemType> lstFs = new List<FileSystemType>();
foreach(IFilesystem _plugin in plugins.PluginsList.Values)
{
try
{
if(_plugin.Identify(_imageFormat, xmlPart))
{
string foo;
_plugin.GetInformation(_imageFormat, xmlPart, out foo, null);
lstFs.Add(_plugin.XmlFsType);
if(_plugin.XmlFsType.Type == "Opera")
dskType = MediaType.ThreeDO;
if(_plugin.XmlFsType.Type == "PC Engine filesystem")
dskType = MediaType.SuperCDROM2;
if(_plugin.XmlFsType.Type == "Nintendo Wii filesystem")
dskType = MediaType.WOD;
if(_plugin.XmlFsType.Type == "Nintendo Gamecube filesystem")
dskType = MediaType.GOD;
}
}
#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
{
//DicConsole.DebugWriteLine("Create-sidecar command", "Plugin {0} crashed", _plugin.Name);
}
}
if(lstFs.Count > 0)
xmlTrk.FileSystemInformation[0].FileSystems = lstFs.ToArray();
}
#if DEBUG
stopwatch.Stop();
Console.WriteLine("Core.AddMedia(): Took {0} seconds to check all filesystems on track {1}", stopwatch.Elapsed.TotalSeconds, trk.TrackSequence);
#endif
trksLst.Add(xmlTrk);
}
if(UpdateProgress != null)
UpdateProgress(null, "Finishing", maxProgress, maxProgress);
if(trksLst != null)
sidecar.OpticalDisc[0].Track = trksLst.ToArray();
string dscType, dscSubType;
DiscImageChef.Metadata.MediaType.MediaTypeToString(dskType, out dscType, out dscSubType);
sidecar.OpticalDisc[0].DiscType = dscType;
sidecar.OpticalDisc[0].DiscSubType = dscSubType;
if(!string.IsNullOrEmpty(_imageFormat.Info.DriveManufacturer) ||
!string.IsNullOrEmpty(_imageFormat.Info.DriveModel) ||
!string.IsNullOrEmpty(_imageFormat.Info.DriveFirmwareRevision) ||
!string.IsNullOrEmpty(_imageFormat.Info.DriveSerialNumber))
{
sidecar.OpticalDisc[0].DumpHardwareArray = new DumpHardwareType[1];
sidecar.OpticalDisc[0].DumpHardwareArray[0].Extents = new ExtentType[0];
sidecar.OpticalDisc[0].DumpHardwareArray[0].Extents[0].Start = 0;
sidecar.OpticalDisc[0].DumpHardwareArray[0].Extents[0].End = _imageFormat.Info.Sectors;
sidecar.OpticalDisc[0].DumpHardwareArray[0].Manufacturer = _imageFormat.Info.DriveManufacturer;
sidecar.OpticalDisc[0].DumpHardwareArray[0].Model = _imageFormat.Info.DriveModel;
sidecar.OpticalDisc[0].DumpHardwareArray[0].Firmware = _imageFormat.Info.DriveFirmwareRevision;
sidecar.OpticalDisc[0].DumpHardwareArray[0].Serial = _imageFormat.Info.DriveSerialNumber;
sidecar.OpticalDisc[0].DumpHardwareArray[0].Software = new SoftwareType();
sidecar.OpticalDisc[0].DumpHardwareArray[0].Software.Name = _imageFormat.Info.Application;
sidecar.OpticalDisc[0].DumpHardwareArray[0].Software.Version = _imageFormat.Info.ApplicationVersion;
}
Context.workingDisc = sidecar.OpticalDisc[0];
if(Finished != null)
Finished();
return;
}
case XmlMediaType.BlockMedia:
{
maxProgress = 3 + _imageFormat.Info.ReadableMediaTags.Count;
if(UpdateProgress != null)
UpdateProgress(null, "Hashing image file", 3, maxProgress);
sidecar.BlockMedia = new BlockMediaType[1];
sidecar.BlockMedia[0] = new BlockMediaType();
sidecar.BlockMedia[0].Checksums = imgChecksums.ToArray();
sidecar.BlockMedia[0].Image = new ImageType();
sidecar.BlockMedia[0].Image.format = _imageFormat.Format;
sidecar.BlockMedia[0].Image.offset = 0;
sidecar.BlockMedia[0].Image.offsetSpecified = true;
sidecar.BlockMedia[0].Image.Value = Path.GetFileName(selectedFile);
sidecar.BlockMedia[0].Size = fi.Length;
sidecar.BlockMedia[0].Sequence = new SequenceType();
if(_imageFormat.Info.MediaSequence != 0 && _imageFormat.Info.LastMediaSequence != 0)
{
sidecar.BlockMedia[0].Sequence.MediaSequence = _imageFormat.Info.MediaSequence;
sidecar.BlockMedia[0].Sequence.TotalMedia = _imageFormat.Info.LastMediaSequence;
}
else
{
sidecar.BlockMedia[0].Sequence.MediaSequence = 1;
sidecar.BlockMedia[0].Sequence.TotalMedia = 1;
}
sidecar.BlockMedia[0].Sequence.MediaTitle = _imageFormat.Info.MediaTitle;
currentProgress = 3;
#if DEBUG
stopwatch.Restart();
#endif
foreach(MediaTagType tagType in _imageFormat.Info.ReadableMediaTags)
{
currentProgress++;
if(UpdateProgress != null)
UpdateProgress(null, string.Format("Hashing file containing {0}", tagType), currentProgress, maxProgress);
switch(tagType)
{
case MediaTagType.ATAPI_IDENTIFY:
sidecar.BlockMedia[0].ATA = new ATAType();
sidecar.BlockMedia[0].ATA.Identify = new DumpType();
sidecar.BlockMedia[0].ATA.Identify.Checksums = Checksum.GetChecksums(_imageFormat.ReadDiskTag(MediaTagType.ATAPI_IDENTIFY)).ToArray();
sidecar.BlockMedia[0].ATA.Identify.Size = _imageFormat.ReadDiskTag(MediaTagType.ATAPI_IDENTIFY).Length;
break;
case MediaTagType.ATA_IDENTIFY:
sidecar.BlockMedia[0].ATA = new ATAType();
sidecar.BlockMedia[0].ATA.Identify = new DumpType();
sidecar.BlockMedia[0].ATA.Identify.Checksums = Checksum.GetChecksums(_imageFormat.ReadDiskTag(MediaTagType.ATA_IDENTIFY)).ToArray();
sidecar.BlockMedia[0].ATA.Identify.Size = _imageFormat.ReadDiskTag(MediaTagType.ATA_IDENTIFY).Length;
break;
case MediaTagType.PCMCIA_CIS:
byte[] cis = _imageFormat.ReadDiskTag(MediaTagType.PCMCIA_CIS);
sidecar.BlockMedia[0].PCMCIA = new PCMCIAType();
sidecar.BlockMedia[0].PCMCIA.CIS = new DumpType();
sidecar.BlockMedia[0].PCMCIA.CIS.Checksums = Checksum.GetChecksums(cis).ToArray();
sidecar.BlockMedia[0].PCMCIA.CIS.Size = cis.Length;
DiscImageChef.Decoders.PCMCIA.Tuple[] tuples = CIS.GetTuples(cis);
if(tuples != null)
{
foreach(DiscImageChef.Decoders.PCMCIA.Tuple tuple in tuples)
{
if(tuple.Code == TupleCodes.CISTPL_MANFID)
{
ManufacturerIdentificationTuple manfid = CIS.DecodeManufacturerIdentificationTuple(tuple);
if(manfid != null)
{
sidecar.BlockMedia[0].PCMCIA.ManufacturerCode = manfid.ManufacturerID;
sidecar.BlockMedia[0].PCMCIA.CardCode = manfid.CardID;
sidecar.BlockMedia[0].PCMCIA.ManufacturerCodeSpecified = true;
sidecar.BlockMedia[0].PCMCIA.CardCodeSpecified = true;
}
}
else if(tuple.Code == TupleCodes.CISTPL_VERS_1)
{
Level1VersionTuple vers = CIS.DecodeLevel1VersionTuple(tuple);
if(vers != null)
{
sidecar.BlockMedia[0].PCMCIA.Manufacturer = vers.Manufacturer;
sidecar.BlockMedia[0].PCMCIA.ProductName = vers.Product;
sidecar.BlockMedia[0].PCMCIA.Compliance = string.Format("{0}.{1}", vers.MajorVersion, vers.MinorVersion);
sidecar.BlockMedia[0].PCMCIA.AdditionalInformation = vers.AdditionalInformation;
}
}
}
}
break;
case MediaTagType.SCSI_INQUIRY:
sidecar.BlockMedia[0].SCSI = new SCSIType();
sidecar.BlockMedia[0].SCSI.Inquiry = new DumpType();
sidecar.BlockMedia[0].SCSI.Inquiry.Checksums = Checksum.GetChecksums(_imageFormat.ReadDiskTag(MediaTagType.SCSI_INQUIRY)).ToArray();
sidecar.BlockMedia[0].SCSI.Inquiry.Size = _imageFormat.ReadDiskTag(MediaTagType.SCSI_INQUIRY).Length;
break;
case MediaTagType.SD_CID:
if(sidecar.BlockMedia[0].SecureDigital == null)
sidecar.BlockMedia[0].SecureDigital = new SecureDigitalType();
sidecar.BlockMedia[0].SecureDigital.CID = new DumpType();
sidecar.BlockMedia[0].SecureDigital.CID.Checksums = Checksum.GetChecksums(_imageFormat.ReadDiskTag(MediaTagType.SD_CID)).ToArray();
sidecar.BlockMedia[0].SecureDigital.CID.Size = _imageFormat.ReadDiskTag(MediaTagType.SD_CID).Length;
break;
case MediaTagType.SD_CSD:
if(sidecar.BlockMedia[0].SecureDigital == null)
sidecar.BlockMedia[0].SecureDigital = new SecureDigitalType();
sidecar.BlockMedia[0].SecureDigital.CSD = new DumpType();
sidecar.BlockMedia[0].SecureDigital.CSD.Checksums = Checksum.GetChecksums(_imageFormat.ReadDiskTag(MediaTagType.SD_CSD)).ToArray();
sidecar.BlockMedia[0].SecureDigital.CSD.Size = _imageFormat.ReadDiskTag(MediaTagType.SD_CSD).Length;
break;
case MediaTagType.MMC_ExtendedCSD:
if(sidecar.BlockMedia[0].SecureDigital == null)
sidecar.BlockMedia[0].SecureDigital = new SecureDigitalType();
sidecar.BlockMedia[0].MultiMediaCard.ExtendedCSD = new DumpType();
sidecar.BlockMedia[0].MultiMediaCard.ExtendedCSD.Checksums = Checksum.GetChecksums(_imageFormat.ReadDiskTag(MediaTagType.MMC_ExtendedCSD)).ToArray();
sidecar.BlockMedia[0].MultiMediaCard.ExtendedCSD.Size = _imageFormat.ReadDiskTag(MediaTagType.MMC_ExtendedCSD).Length;
break;
}
}
#if DEBUG
stopwatch.Stop();
Console.WriteLine("Core.AddMedia(): Took {0} seconds to hash media tags", stopwatch.Elapsed.TotalSeconds);
#endif
// If there is only one track, and it's the same as the image file (e.g. ".iso" files), don't re-checksum.
if(_imageFormat.Id == new System.Guid("12345678-AAAA-BBBB-CCCC-123456789000"))
{
sidecar.BlockMedia[0].ContentChecksums = sidecar.BlockMedia[0].Checksums;
}
else
{
Checksum contentChkWorker = new Checksum();
uint sectorsToRead = 512;
ulong sectors = _imageFormat.Info.Sectors;
ulong doneSectors = 0;
if(UpdateProgress != null)
UpdateProgress(null, "Hashing media contents", currentProgress, maxProgress);
Checksum cntChkWorker = new Checksum();
#if DEBUG
stopwatch.Restart();
#endif
while(doneSectors < sectors)
{
byte[] sector;
if((sectors - doneSectors) >= sectorsToRead)
{
sector = _imageFormat.ReadSectors(doneSectors, sectorsToRead);
if(UpdateProgress2 != null)
UpdateProgress2(null, string.Format("Sector {0} of {1}", doneSectors, sectors), (long)doneSectors, (long)sectors);
doneSectors += sectorsToRead;
}
else
{
sector = _imageFormat.ReadSectors(doneSectors, (uint)(sectors - doneSectors));
if(UpdateProgress2 != null)
UpdateProgress2(null, string.Format("Sector {0} of {1}", doneSectors, sectors), (long)doneSectors, (long)sectors);
doneSectors += (sectors - doneSectors);
}
cntChkWorker.Update(sector);
}
List<ChecksumType> cntChecksums = cntChkWorker.End();
#if DEBUG
stopwatch.Stop();
Console.WriteLine("Core.AddMedia(): Took {0} seconds to hash media contents", stopwatch.Elapsed.TotalSeconds);
#endif
sidecar.BlockMedia[0].ContentChecksums = cntChecksums.ToArray();
}
string dskType, dskSubType;
DiscImageChef.Metadata.MediaType.MediaTypeToString(_imageFormat.Info.MediaType, out dskType, out dskSubType);
sidecar.BlockMedia[0].DiskType = dskType;
sidecar.BlockMedia[0].DiskSubType = dskSubType;
sidecar.BlockMedia[0].Dimensions = DiscImageChef.Metadata.Dimensions.DimensionsFromMediaType(_imageFormat.Info.MediaType);
sidecar.BlockMedia[0].LogicalBlocks = (long)_imageFormat.Info.Sectors;
sidecar.BlockMedia[0].LogicalBlockSize = (int)_imageFormat.Info.SectorSize;
// TODO: Detect it
sidecar.BlockMedia[0].PhysicalBlockSize = (int)_imageFormat.Info.SectorSize;
if(UpdateProgress != null)
UpdateProgress(null, "Checking filesystems", maxProgress - 1, maxProgress);
#if DEBUG
stopwatch.Restart();
#endif
List<Partition> partitions = new List<Partition>();
foreach(IPartition _partplugin in plugins.PartPluginsList.Values)
{
List<Partition> _partitions;
if(_partplugin.GetInformation(_imageFormat, out _partitions, 0))
{
partitions = _partitions;
break;
}
}
sidecar.BlockMedia[0].FileSystemInformation = new PartitionType[1];
if(partitions.Count > 0)
{
sidecar.BlockMedia[0].FileSystemInformation = new PartitionType[partitions.Count];
for(int i = 0; i < partitions.Count; i++)
{
sidecar.BlockMedia[0].FileSystemInformation[i] = new PartitionType();
sidecar.BlockMedia[0].FileSystemInformation[i].Description = partitions[i].Description;
sidecar.BlockMedia[0].FileSystemInformation[i].EndSector = (int)(partitions[i].End);
sidecar.BlockMedia[0].FileSystemInformation[i].Name = partitions[i].Name;
sidecar.BlockMedia[0].FileSystemInformation[i].Sequence = (int)partitions[i].Sequence;
sidecar.BlockMedia[0].FileSystemInformation[i].StartSector = (int)partitions[i].Start;
sidecar.BlockMedia[0].FileSystemInformation[i].Type = partitions[i].Type;
List<FileSystemType> lstFs = new List<FileSystemType>();
foreach(IFilesystem _plugin in plugins.PluginsList.Values)
{
try
{
if(_plugin.Identify(_imageFormat, partitions[i]))
{
string foo;
_plugin.GetInformation(_imageFormat, partitions[i], out foo, null);
lstFs.Add(_plugin.XmlFsType);
}
}
#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
{
//DicConsole.DebugWriteLine("Create-sidecar command", "Plugin {0} crashed", _plugin.Name);
}
}
if(lstFs.Count > 0)
sidecar.BlockMedia[0].FileSystemInformation[i].FileSystems = lstFs.ToArray();
}
}
else
{
sidecar.BlockMedia[0].FileSystemInformation[0] = new PartitionType();
sidecar.BlockMedia[0].FileSystemInformation[0].StartSector = 0;
sidecar.BlockMedia[0].FileSystemInformation[0].EndSector = (int)(_imageFormat.Info.Sectors - 1);
Partition wholePart = new Partition
{
Start = 0,
Length = _imageFormat.Info.Sectors
};
List<FileSystemType> lstFs = new List<FileSystemType>();
foreach(IFilesystem _plugin in plugins.PluginsList.Values)
{
try
{
if(_plugin.Identify(_imageFormat, wholePart))
{
string foo;
_plugin.GetInformation(_imageFormat, wholePart, out foo, null);
lstFs.Add(_plugin.XmlFsType);
}
}
#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
{
//DicConsole.DebugWriteLine("Create-sidecar command", "Plugin {0} crashed", _plugin.Name);
}
}
if(lstFs.Count > 0)
sidecar.BlockMedia[0].FileSystemInformation[0].FileSystems = lstFs.ToArray();
}
#if DEBUG
stopwatch.Stop();
Console.WriteLine("Core.AddMedia(): Took {0} seconds to check all filesystems", stopwatch.Elapsed.TotalSeconds);
#endif
// TODO: Implement support for getting CHS
if(UpdateProgress != null)
UpdateProgress(null, "Finishing", maxProgress, maxProgress);
Context.workingDisk = sidecar.BlockMedia[0];
if(Finished != null)
Finished();
return;
}
case XmlMediaType.LinearMedia:
{
if(Failed != null)
Failed("Linear media not yet supported.");
return;
}
case XmlMediaType.AudioMedia:
{
if(Failed != null)
Failed("Audio media not yet supported.");
return;
}
}
if(Failed != null)
Failed("Should've not arrived here.");
return;
}
catch(Exception ex)
{
if(Failed != null)
Failed(string.Format("Error reading file: {0}\n{1}", ex.Message, ex.StackTrace));
#if DEBUG
Console.WriteLine("Exception {0}\n{1}", ex.Message, ex.InnerException);
#endif
}
}
static string LbaToMsf(long lba)
{
long m, s, f;
if(lba >= -150)
{
m = (lba + 150) / (75 * 60);
lba -= m * (75 * 60);
s = (lba + 150) / 75;
lba -= s * 75;
f = lba + 150;
}
else
{
m = (lba + 450150) / (75 * 60);
lba -= m * (75 * 60);
s = (lba + 450150) / 75;
lba -= s * 75;
f = lba + 450150;
}
return string.Format("{0}:{1:D2}:{2:D2}", m, s, f);
}
static string DdcdLbaToMsf(long lba)
{
long h, m, s, f;
if(lba >= -150)
{
h = (lba + 150) / (75 * 60 * 60);
lba -= h * (75 * 60 * 60);
m = (lba + 150) / (75 * 60);
lba -= m * (75 * 60);
s = (lba + 150) / 75;
lba -= s * 75;
f = lba + 150;
}
else
{
h = (lba + 450150 * 2) / (75 * 60 * 60);
lba -= h * (75 * 60 * 60);
m = (lba + 450150 * 2) / (75 * 60);
lba -= m * (75 * 60);
s = (lba + 450150 * 2) / 75;
lba -= s * 75;
f = lba + 450150 * 2;
}
return string.Format("{3}:{0:D2}:{1:D2}:{2:D2}", m, s, f, h);
}
}
}