Save metadata in CDRWin cuesheet.

This commit is contained in:
2020-01-09 19:03:46 +00:00
parent a87c5b24aa
commit d0dd40003e
10 changed files with 792 additions and 620 deletions

View File

@@ -41,43 +41,31 @@ namespace DiscImageChef.DiscImages
// TODO: Implement track flags // TODO: Implement track flags
public partial class CdrWin : IWritableOpticalImage, IVerifiableImage public partial class CdrWin : IWritableOpticalImage, IVerifiableImage
{ {
IFilter cdrwinFilter; IFilter _cdrwinFilter;
StreamReader cueStream; StreamReader _cueStream;
StreamWriter descriptorStream; StreamWriter _descriptorStream;
CdrWinDisc discimage; CdrWinDisc _discImage;
ImageInfo imageInfo; ImageInfo _imageInfo;
Stream imageStream; Stream _imageStream;
/// <summary>Dictionary, index is track #, value is TrackFile</summary> /// <summary>Dictionary, index is track #, value is TrackFile</summary>
Dictionary<uint, ulong> offsetmap; Dictionary<uint, ulong> _offsetMap;
bool separateTracksWriting; bool _separateTracksWriting;
Dictionary<byte, byte> trackFlags; Dictionary<byte, byte> _trackFlags;
Dictionary<byte, string> trackIsrcs; Dictionary<byte, string> _trackIsrcs;
string writingBaseName; string _writingBaseName;
Dictionary<uint, FileStream> writingStreams; Dictionary<uint, FileStream> _writingStreams;
List<Track> writingTracks; List<Track> _writingTracks;
public CdrWin() public CdrWin() => _imageInfo = new ImageInfo
{ {
imageInfo = new ImageInfo ReadableSectorTags = new List<SectorTagType>(), ReadableMediaTags = new List<MediaTagType>(),
{ HasPartitions = true, HasSessions = true, Version = null,
ReadableSectorTags = new List<SectorTagType>(), ApplicationVersion = null,
ReadableMediaTags = new List<MediaTagType>(), MediaTitle = null, Creator = null, MediaManufacturer = null,
HasPartitions = true, MediaModel = null,
HasSessions = true, MediaPartNumber = null, MediaSequence = 0, LastMediaSequence = 0,
Version = null, DriveManufacturer = null,
ApplicationVersion = null, DriveModel = null, DriveSerialNumber = null, DriveFirmwareRevision = null
MediaTitle = null, };
Creator = null,
MediaManufacturer = null,
MediaModel = null,
MediaPartNumber = null,
MediaSequence = 0,
LastMediaSequence = 0,
DriveManufacturer = null,
DriveModel = null,
DriveSerialNumber = null,
DriveFirmwareRevision = null
};
}
} }
} }

View File

@@ -137,6 +137,7 @@ namespace DiscImageChef.DiscImages
const string REGEX_SESSION = @"\bREM\s+SESSION\s+(?<number>\d+).*$"; const string REGEX_SESSION = @"\bREM\s+SESSION\s+(?<number>\d+).*$";
const string REGEX_MEDIA_TYPE = @"\bREM\s+ORIGINAL MEDIA-TYPE:\s+(?<mediatype>.+)$"; const string REGEX_MEDIA_TYPE = @"\bREM\s+ORIGINAL MEDIA-TYPE:\s+(?<mediatype>.+)$";
const string REGEX_LEAD_OUT = @"\bREM\s+LEAD-OUT\s+(?<msf>[\d]+:[\d]+:[\d]+)$"; const string REGEX_LEAD_OUT = @"\bREM\s+LEAD-OUT\s+(?<msf>[\d]+:[\d]+:[\d]+)$";
// Not checked // Not checked
const string REGEX_LBA = @"\bREM MSF:\s+(?<msf>[\d]+:[\d]+:[\d]+)\s+=\s+LBA:\s+(?<lba>[\d]+)$"; const string REGEX_LBA = @"\bREM MSF:\s+(?<msf>[\d]+:[\d]+:[\d]+)\s+=\s+LBA:\s+(?<lba>[\d]+)$";
const string REGEX_DISC_ID = @"\bDISC_ID\s+(?<diskid>[\da-f]{8})$"; const string REGEX_DISC_ID = @"\bDISC_ID\s+(?<diskid>[\da-f]{8})$";
@@ -157,6 +158,7 @@ namespace DiscImageChef.DiscImages
const string REGEX_PREGAP = @"\bPREGAP\s+(?<msf>[\d]+:[\d]+:[\d]+)$"; const string REGEX_PREGAP = @"\bPREGAP\s+(?<msf>[\d]+:[\d]+:[\d]+)$";
const string REGEX_POSTGAP = @"\bPOSTGAP\s+(?<msf>[\d]+:[\d]+:[\d]+)$"; const string REGEX_POSTGAP = @"\bPOSTGAP\s+(?<msf>[\d]+:[\d]+:[\d]+)$";
const string REGEX_FLAGS = @"\bFLAGS\s+(((?<dcp>DCP)|(?<quad>4CH)|(?<pre>PRE)|(?<scms>SCMS))\s*)+$"; const string REGEX_FLAGS = @"\bFLAGS\s+(((?<dcp>DCP)|(?<quad>4CH)|(?<pre>PRE)|(?<scms>SCMS))\s*)+$";
// Trurip extensions // Trurip extensions
const string REGEX_APPLICATION = @"\bREM\s+Ripping Tool:\s+(?<application>.+)$"; const string REGEX_APPLICATION = @"\bREM\s+Ripping Tool:\s+(?<application>.+)$";
const string REGEX_TRURIP_DISC_HASHES = @"\bREM\s+DISC\s+HASHES$"; const string REGEX_TRURIP_DISC_HASHES = @"\bREM\s+DISC\s+HASHES$";
@@ -169,5 +171,9 @@ namespace DiscImageChef.DiscImages
const string REGEX_TRURIP_TRACK_MD5 = @"\bREM\s+(Gap|Trk)\s+(?<number>\d{2}):\s+[\da-f]{32}$"; const string REGEX_TRURIP_TRACK_MD5 = @"\bREM\s+(Gap|Trk)\s+(?<number>\d{2}):\s+[\da-f]{32}$";
const string REGEX_TRURIP_TRACK_SHA1 = @"\bREM\s+(Gap|Trk)\s+(?<number>\d{2}):\s+[\da-f]{40}$"; const string REGEX_TRURIP_TRACK_SHA1 = @"\bREM\s+(Gap|Trk)\s+(?<number>\d{2}):\s+[\da-f]{40}$";
const string REGEX_TRURIP_TRACK_UNKNOWN = @"\bREM\s+(Gap|Trk)\s+(?<number>\d{2}):\s+[\da-f]{8,}$"; const string REGEX_TRURIP_TRACK_UNKNOWN = @"\bREM\s+(Gap|Trk)\s+(?<number>\d{2}):\s+[\da-f]{8,}$";
const string REGEX_DIC_MEDIA_TYPE = @"\bREM\s+METADATA DIC MEDIA-TYPE:\s+(?<mediatype>.+)$";
const string REGEX_APPLICATION_VERSION = @"\bREM\s+Ripping Tool Version:\s+(?<application>.+)$";
const string REGEX_DUMP_EXTENT =
@"\bREM\s+METADATA DUMP EXTENT:\s+(?<application>.+)\s+\|\s+(?<version>.+)\s+\|\s+(?<os>.+)\s+\|\s+(?<manufacturer>.+)\s+\|\s+(?<model>.+)\s+\|\s+(?<firmware>.+)\s+\|\s+(?<serial>.+)\s+\|\s+(?<start>\d+):(?<end>\d+)$";
} }
} }

View File

@@ -38,14 +38,14 @@ namespace DiscImageChef.DiscImages
{ {
public partial class CdrWin public partial class CdrWin
{ {
static ulong CdrWinMsftoLba(string msf) static ulong CdrWinMsfToLba(string msf)
{ {
string[] msfElements = msf.Split(':'); string[] msfElements = msf.Split(':');
ulong minute = ulong.Parse(msfElements[0]); ulong minute = ulong.Parse(msfElements[0]);
ulong second = ulong.Parse(msfElements[1]); ulong second = ulong.Parse(msfElements[1]);
ulong frame = ulong.Parse(msfElements[2]); ulong frame = ulong.Parse(msfElements[2]);
ulong sectors = minute * 60 * 75 + second * 75 + frame; ulong sectors = (minute * 60 * 75) + (second * 75) + frame;
return sectors; return sectors;
} }
@@ -144,8 +144,8 @@ namespace DiscImageChef.DiscImages
} }
} }
static (byte minute, byte second, byte frame) LbaToMsf(ulong sector) => static(byte minute, byte second, byte frame) LbaToMsf(ulong sector) =>
((byte)(sector / 75 / 60), (byte)(sector / 75 % 60), (byte)(sector % 75)); ((byte)(sector / 75 / 60), (byte)((sector / 75) % 60), (byte)(sector % 75));
static string GetTrackMode(Track track) static string GetTrackMode(Track track)
{ {
@@ -235,7 +235,7 @@ namespace DiscImageChef.DiscImages
case MediaType.HDDVDROM: return CDRWIN_DISK_TYPE_HDDVD; case MediaType.HDDVDROM: return CDRWIN_DISK_TYPE_HDDVD;
case MediaType.HDDVDRW: return CDRWIN_DISK_TYPE_HDDVDRW; case MediaType.HDDVDRW: return CDRWIN_DISK_TYPE_HDDVDRW;
case MediaType.HDDVDRWDL: return CDRWIN_DISK_TYPE_HDDVDRWDL; case MediaType.HDDVDRWDL: return CDRWIN_DISK_TYPE_HDDVDRWDL;
default: return ""; default: return"";
} }
} }
} }

View File

@@ -43,7 +43,7 @@ namespace DiscImageChef.DiscImages
// Due to .cue format, this method must parse whole file, ignoring errors (those will be thrown by OpenImage()). // Due to .cue format, this method must parse whole file, ignoring errors (those will be thrown by OpenImage()).
public bool Identify(IFilter imageFilter) public bool Identify(IFilter imageFilter)
{ {
cdrwinFilter = imageFilter; _cdrwinFilter = imageFilter;
try try
{ {
@@ -51,37 +51,45 @@ namespace DiscImageChef.DiscImages
byte[] testArray = new byte[512]; byte[] testArray = new byte[512];
imageFilter.GetDataForkStream().Read(testArray, 0, 512); imageFilter.GetDataForkStream().Read(testArray, 0, 512);
imageFilter.GetDataForkStream().Seek(0, SeekOrigin.Begin); imageFilter.GetDataForkStream().Seek(0, SeekOrigin.Begin);
// Check for unexpected control characters that shouldn't be present in a text file and can crash this plugin // Check for unexpected control characters that shouldn't be present in a text file and can crash this plugin
bool twoConsecutiveNulls = false; bool twoConsecutiveNulls = false;
for(int i = 0; i < 512; i++) for(int i = 0; i < 512; i++)
{ {
if(i >= imageFilter.GetDataForkStream().Length) break; if(i >= imageFilter.GetDataForkStream().Length)
break;
if(testArray[i] == 0) if(testArray[i] == 0)
{ {
if(twoConsecutiveNulls) return false; if(twoConsecutiveNulls)
return false;
twoConsecutiveNulls = true; twoConsecutiveNulls = true;
} }
else twoConsecutiveNulls = false; else
twoConsecutiveNulls = false;
if(testArray[i] < 0x20 && testArray[i] != 0x0A && testArray[i] != 0x0D && testArray[i] != 0x00) if(testArray[i] < 0x20 &&
testArray[i] != 0x0A &&
testArray[i] != 0x0D &&
testArray[i] != 0x00)
return false; return false;
} }
cueStream = new StreamReader(cdrwinFilter.GetDataForkStream()); _cueStream = new StreamReader(_cdrwinFilter.GetDataForkStream());
while(cueStream.Peek() >= 0) while(_cueStream.Peek() >= 0)
{ {
string line = cueStream.ReadLine(); string line = _cueStream.ReadLine();
Regex sr = new Regex(REGEX_SESSION); var sr = new Regex(REGEX_SESSION);
Regex rr = new Regex(REGEX_COMMENT); var rr = new Regex(REGEX_COMMENT);
Regex cr = new Regex(REGEX_MCN); var cr = new Regex(REGEX_MCN);
Regex fr = new Regex(REGEX_FILE); var fr = new Regex(REGEX_FILE);
Regex tr = new Regex(REGEX_CDTEXT); var tr = new Regex(REGEX_CDTEXT);
// First line must be SESSION, REM, CATALOG, FILE or CDTEXTFILE. // First line must be SESSION, REM, CATALOG, FILE or CDTEXTFILE.
Match sm = sr.Match(line ?? throw new InvalidOperationException()); Match sm = sr.Match(line ?? throw new InvalidOperationException());
Match rm = rr.Match(line); Match rm = rr.Match(line);
Match cm = cr.Match(line); Match cm = cr.Match(line);
@@ -95,9 +103,10 @@ namespace DiscImageChef.DiscImages
} }
catch(Exception ex) catch(Exception ex)
{ {
DicConsole.ErrorWriteLine("Exception trying to identify image file {0}", cdrwinFilter); DicConsole.ErrorWriteLine("Exception trying to identify image file {0}", _cdrwinFilter);
DicConsole.ErrorWriteLine("Exception: {0}", ex.Message); DicConsole.ErrorWriteLine("Exception: {0}", ex.Message);
DicConsole.ErrorWriteLine("Stack trace: {0}", ex.StackTrace); DicConsole.ErrorWriteLine("Stack trace: {0}", ex.StackTrace);
return false; return false;
} }
} }

View File

@@ -41,12 +41,13 @@ namespace DiscImageChef.DiscImages
{ {
public partial class CdrWin public partial class CdrWin
{ {
public ImageInfo Info => imageInfo; public ImageInfo Info => _imageInfo;
public string Name => "CDRWin cuesheet"; public string Name => "CDRWin cuesheet";
public Guid Id => new Guid("664568B2-15D4-4E64-8A7A-20BDA8B8386F"); public Guid Id => new Guid("664568B2-15D4-4E64-8A7A-20BDA8B8386F");
public string Format => "CDRWin CUESheet"; public string Format => "CDRWin CUESheet";
public string Author => "Natalia Portillo"; public string Author => "Natalia Portillo";
public List<Partition> Partitions { get; private set; } public List<Partition> Partitions { get; private set; }
public List<Track> Tracks public List<Track> Tracks
{ {
get get
@@ -55,36 +56,34 @@ namespace DiscImageChef.DiscImages
ulong previousStartSector = 0; ulong previousStartSector = 0;
foreach(CdrWinTrack cdrTrack in discimage.Tracks) foreach(CdrWinTrack cdrTrack in _discImage.Tracks)
{ {
Track dicTrack = new Track var dicTrack = new Track
{ {
Indexes = cdrTrack.Indexes, Indexes = cdrTrack.Indexes, TrackDescription = cdrTrack.Title,
TrackDescription = cdrTrack.Title, TrackStartSector = previousStartSector, TrackPregap = cdrTrack.Pregap,
TrackStartSector = previousStartSector, TrackSession = cdrTrack.Session, TrackSequence = cdrTrack.Sequence,
TrackPregap = cdrTrack.Pregap, TrackType = CdrWinTrackTypeToTrackType(cdrTrack.TrackType),
TrackSession = cdrTrack.Session, TrackFile = cdrTrack.TrackFile.DataFilter.GetFilename(),
TrackSequence = cdrTrack.Sequence, TrackFilter = cdrTrack.TrackFile.DataFilter,
TrackType = CdrWinTrackTypeToTrackType(cdrTrack.Tracktype), TrackFileOffset = cdrTrack.TrackFile.Offset,
TrackFile = cdrTrack.Trackfile.Datafilter.GetFilename(), TrackFileType = cdrTrack.TrackFile.FileType, TrackRawBytesPerSector = cdrTrack.Bps,
TrackFilter = cdrTrack.Trackfile.Datafilter, TrackBytesPerSector = CdrWinTrackTypeToCookedBytesPerSector(cdrTrack.TrackType)
TrackFileOffset = cdrTrack.Trackfile.Offset,
TrackFileType = cdrTrack.Trackfile.Filetype,
TrackRawBytesPerSector = cdrTrack.Bps,
TrackBytesPerSector = CdrWinTrackTypeToCookedBytesPerSector(cdrTrack.Tracktype)
}; };
dicTrack.TrackEndSector = dicTrack.TrackStartSector + cdrTrack.Sectors - 1;
dicTrack.TrackEndSector = (dicTrack.TrackStartSector + cdrTrack.Sectors) - 1;
/*if(!cdrTrack.Indexes.TryGetValue(0, out dicTrack.TrackStartSector)) /*if(!cdrTrack.Indexes.TryGetValue(0, out dicTrack.TrackStartSector))
cdrTrack.Indexes.TryGetValue(1, out dicTrack.TrackStartSector);*/ cdrTrack.Indexes.TryGetValue(1, out dicTrack.TrackStartSector);*/
if(cdrTrack.Tracktype == CDRWIN_TRACK_TYPE_CDG) if(cdrTrack.TrackType == CDRWIN_TRACK_TYPE_CDG)
{ {
dicTrack.TrackSubchannelFilter = cdrTrack.Trackfile.Datafilter; dicTrack.TrackSubchannelFilter = cdrTrack.TrackFile.DataFilter;
dicTrack.TrackSubchannelFile = cdrTrack.Trackfile.Datafilter.GetFilename(); dicTrack.TrackSubchannelFile = cdrTrack.TrackFile.DataFilter.GetFilename();
dicTrack.TrackSubchannelOffset = cdrTrack.Trackfile.Offset; dicTrack.TrackSubchannelOffset = cdrTrack.TrackFile.Offset;
dicTrack.TrackSubchannelType = TrackSubchannelType.RawInterleaved; dicTrack.TrackSubchannelType = TrackSubchannelType.RawInterleaved;
} }
else dicTrack.TrackSubchannelType = TrackSubchannelType.None; else
dicTrack.TrackSubchannelType = TrackSubchannelType.None;
tracks.Add(dicTrack); tracks.Add(dicTrack);
previousStartSector = dicTrack.TrackEndSector + 1; previousStartSector = dicTrack.TrackEndSector + 1;
@@ -93,40 +92,46 @@ namespace DiscImageChef.DiscImages
return tracks; return tracks;
} }
} }
public List<Session> Sessions => discimage.Sessions;
public List<DumpHardwareType> DumpHardware => null; public List<Session> Sessions => _discImage.Sessions;
public CICMMetadataType CicmMetadata => null; public List<DumpHardwareType> DumpHardware { get; private set; }
public IEnumerable<MediaTagType> SupportedMediaTags => new[] {MediaTagType.CD_MCN, MediaTagType.CD_TEXT}; public CICMMetadataType CicmMetadata => null;
public IEnumerable<SectorTagType> SupportedSectorTags => public IEnumerable<MediaTagType> SupportedMediaTags => new[]
new[] {
{ MediaTagType.CD_MCN, MediaTagType.CD_TEXT
SectorTagType.CdSectorEcc, SectorTagType.CdSectorEccP, SectorTagType.CdSectorEccQ, };
SectorTagType.CdSectorEdc, SectorTagType.CdSectorHeader, SectorTagType.CdSectorSubHeader, public IEnumerable<SectorTagType> SupportedSectorTags => new[]
SectorTagType.CdSectorSync, SectorTagType.CdTrackFlags, SectorTagType.CdTrackIsrc {
}; SectorTagType.CdSectorEcc, SectorTagType.CdSectorEccP, SectorTagType.CdSectorEccQ,
public IEnumerable<MediaType> SupportedMediaTypes => SectorTagType.CdSectorEdc, SectorTagType.CdSectorHeader, SectorTagType.CdSectorSubHeader,
new[] SectorTagType.CdSectorSync, SectorTagType.CdTrackFlags, SectorTagType.CdTrackIsrc
{ };
MediaType.BDR, MediaType.BDRE, MediaType.BDREXL, MediaType.BDROM, MediaType.BDRXL, MediaType.CBHD, public IEnumerable<MediaType> SupportedMediaTypes => new[]
MediaType.CD, MediaType.CDDA, MediaType.CDEG, MediaType.CDG, MediaType.CDI, MediaType.CDMIDI, {
MediaType.CDMRW, MediaType.CDPLUS, MediaType.CDR, MediaType.CDROM, MediaType.CDROMXA, MediaType.BDR, MediaType.BDRE, MediaType.BDREXL, MediaType.BDROM, MediaType.BDRXL, MediaType.CBHD,
MediaType.CDRW, MediaType.CDV, MediaType.DDCD, MediaType.DDCDR, MediaType.DDCDRW, MediaType.CD, MediaType.CDDA, MediaType.CDEG, MediaType.CDG, MediaType.CDI, MediaType.CDMIDI,
MediaType.DVDDownload, MediaType.DVDPR, MediaType.DVDPRDL, MediaType.DVDPRW, MediaType.DVDPRWDL, MediaType.CDMRW, MediaType.CDPLUS, MediaType.CDR, MediaType.CDROM, MediaType.CDROMXA, MediaType.CDRW,
MediaType.DVDR, MediaType.DVDRAM, MediaType.DVDRDL, MediaType.DVDROM, MediaType.DVDRW, MediaType.CDV, MediaType.DDCD, MediaType.DDCDR, MediaType.DDCDRW, MediaType.DVDDownload, MediaType.DVDPR,
MediaType.DVDRWDL, MediaType.EVD, MediaType.FDDVD, MediaType.DTSCD, MediaType.FVD, MediaType.HDDVDR, MediaType.DVDPRDL, MediaType.DVDPRW, MediaType.DVDPRWDL, MediaType.DVDR, MediaType.DVDRAM, MediaType.DVDRDL,
MediaType.HDDVDRAM, MediaType.HDDVDRDL, MediaType.HDDVDROM, MediaType.HDDVDRW, MediaType.HDDVDRWDL, MediaType.DVDROM, MediaType.DVDRW, MediaType.DVDRWDL, MediaType.EVD, MediaType.FDDVD, MediaType.DTSCD,
MediaType.HDVMD, MediaType.HVD, MediaType.JaguarCD, MediaType.MEGACD, MediaType.PS1CD, MediaType.FVD, MediaType.HDDVDR, MediaType.HDDVDRAM, MediaType.HDDVDRDL, MediaType.HDDVDROM,
MediaType.PS2CD, MediaType.PS2DVD, MediaType.PS3BD, MediaType.PS3DVD, MediaType.PS4BD, MediaType.HDDVDRW, MediaType.HDDVDRWDL, MediaType.HDVMD, MediaType.HVD, MediaType.JaguarCD,
MediaType.SuperCDROM2, MediaType.SVCD, MediaType.SVOD, MediaType.SATURNCD, MediaType.ThreeDO, MediaType.MEGACD, MediaType.PS1CD, MediaType.PS2CD, MediaType.PS2DVD, MediaType.PS3BD, MediaType.PS3DVD,
MediaType.UDO, MediaType.UDO2, MediaType.UDO2_WORM, MediaType.UMD, MediaType.VCD, MediaType.VCDHD, MediaType.PS4BD, MediaType.SuperCDROM2, MediaType.SVCD, MediaType.SVOD, MediaType.SATURNCD,
MediaType.NeoGeoCD, MediaType.PCFX, MediaType.CDTV, MediaType.CD32, MediaType.Nuon, MediaType.ThreeDO, MediaType.UDO, MediaType.UDO2, MediaType.UDO2_WORM, MediaType.UMD, MediaType.VCD,
MediaType.Playdia, MediaType.Pippin, MediaType.FMTOWNS, MediaType.MilCD, MediaType.VideoNow, MediaType.VCDHD, MediaType.NeoGeoCD, MediaType.PCFX, MediaType.CDTV, MediaType.CD32, MediaType.Nuon,
MediaType.VideoNowColor, MediaType.VideoNowXp MediaType.Playdia, MediaType.Pippin, MediaType.FMTOWNS, MediaType.MilCD, MediaType.VideoNow,
}; MediaType.VideoNowColor, MediaType.VideoNowXp
public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions => };
new[] {("separate", typeof(bool), "Write each track to a separate file.", (object)false)}; public IEnumerable<(string name, Type type, string description, object @default)> SupportedOptions => new[]
public IEnumerable<string> KnownExtensions => new[] {".cue"}; {
public bool IsWriting { get; private set; } ("separate", typeof(bool), "Write each track to a separate file.", (object)false)
public string ErrorMessage { get; private set; } };
public IEnumerable<string> KnownExtensions => new[]
{
".cue"
};
public bool IsWriting { get; private set; }
public string ErrorMessage { get; private set; }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -44,11 +44,11 @@ namespace DiscImageChef.DiscImages
/// <summary>Track #</summary> /// <summary>Track #</summary>
public uint Sequence; public uint Sequence;
/// <summary>Filter of file containing track</summary> /// <summary>Filter of file containing track</summary>
public IFilter Datafilter; public IFilter DataFilter;
/// <summary>Offset of track start in file</summary> /// <summary>Offset of track start in file</summary>
public ulong Offset; public ulong Offset;
/// <summary>Type of file</summary> /// <summary>Type of file</summary>
public string Filetype; public string FileType;
} }
struct CdrWinTrack struct CdrWinTrack
@@ -70,18 +70,18 @@ namespace DiscImageChef.DiscImages
/// <summary>Track ISRC</summary> /// <summary>Track ISRC</summary>
public string Isrc; public string Isrc;
/// <summary>File struct for this track</summary> /// <summary>File struct for this track</summary>
public CdrWinTrackFile Trackfile; public CdrWinTrackFile TrackFile;
/// <summary>Indexes on this track</summary> /// <summary>Indexes on this track</summary>
public Dictionary<int, ulong> Indexes; public Dictionary<int, ulong> Indexes;
/// <summary>Track pre-gap in sectors</summary> /// <summary>Track pre-gap in sectors</summary>
public ulong Pregap; public ulong Pregap;
/// <summary>Track post-gap in sectors</summary> /// <summary>Track post-gap in sectors</summary>
public ulong Postgap; public ulong Postgap;
/// <summary>Digical Copy Permitted</summary> /// <summary>Digital Copy Permitted</summary>
public bool FlagDcp; public bool FlagDcp;
/// <summary>Track is quadraphonic</summary> /// <summary>Track is quadraphonic</summary>
public bool Flag4ch; public bool Flag4ch;
/// <summary>Track has preemphasis</summary> /// <summary>Track has pre-emphasis</summary>
public bool FlagPre; public bool FlagPre;
/// <summary>Track has SCMS</summary> /// <summary>Track has SCMS</summary>
public bool FlagScms; public bool FlagScms;
@@ -90,7 +90,7 @@ namespace DiscImageChef.DiscImages
/// <summary>Sectors in track</summary> /// <summary>Sectors in track</summary>
public ulong Sectors; public ulong Sectors;
/// <summary>Track type</summary> /// <summary>Track type</summary>
public string Tracktype; public string TrackType;
/// <summary>Track session</summary> /// <summary>Track session</summary>
public ushort Session; public ushort Session;
} }
@@ -112,11 +112,11 @@ namespace DiscImageChef.DiscImages
/// <summary>Media catalog number</summary> /// <summary>Media catalog number</summary>
public string Mcn; public string Mcn;
/// <summary>Disk type</summary> /// <summary>Disk type</summary>
public MediaType Disktype; public MediaType MediaType;
/// <summary>Disk type string</summary> /// <summary>Disk type string</summary>
public string Disktypestr; public string OriginalMediaType;
/// <summary>Disk CDDB ID</summary> /// <summary>Disk CDDB ID</summary>
public string DiskId; public string DiscId;
/// <summary>Disk UPC/EAN</summary> /// <summary>Disk UPC/EAN</summary>
public string Barcode; public string Barcode;
/// <summary>Sessions</summary> /// <summary>Sessions</summary>
@@ -126,11 +126,13 @@ namespace DiscImageChef.DiscImages
/// <summary>Disk comment</summary> /// <summary>Disk comment</summary>
public string Comment; public string Comment;
/// <summary>File containing CD-Text</summary> /// <summary>File containing CD-Text</summary>
public string Cdtextfile; public string CdTextFile;
/// <summary>Has trurip extensions</summary> /// <summary>Has trurip extensions</summary>
public bool IsTrurip; public bool IsTrurip;
/// <summary>Disc image hashes</summary> /// <summary>Disc image hashes</summary>
public Dictionary<string, string> DiscHashes; public Dictionary<string, string> DiscHashes;
/// <summary>DIC media type</summary>
public string DicMediaType;
} }
} }
} }

View File

@@ -44,27 +44,28 @@ namespace DiscImageChef.DiscImages
{ {
public bool? VerifyMediaImage() public bool? VerifyMediaImage()
{ {
if(discimage.DiscHashes.Count == 0) return null; if(_discImage.DiscHashes.Count == 0)
return null;
// Read up to 1MiB at a time for verification // Read up to 1 MiB at a time for verification
const int VERIFY_SIZE = 1024 * 1024; const int verifySize = 1024 * 1024;
long readBytes; long readBytes;
byte[] verifyBytes; byte[] verifyBytes;
IFilter[] filters = discimage.Tracks.OrderBy(t => t.Sequence).Select(t => t.Trackfile.Datafilter).Distinct() IFilter[] filters = _discImage.Tracks.OrderBy(t => t.Sequence).Select(t => t.TrackFile.DataFilter).
.ToArray(); Distinct().ToArray();
if(discimage.DiscHashes.TryGetValue("sha1", out string sha1)) if(_discImage.DiscHashes.TryGetValue("sha1", out string sha1))
{ {
Sha1Context ctx = new Sha1Context(); var ctx = new Sha1Context();
foreach(IFilter filter in filters) foreach(IFilter filter in filters)
{ {
Stream stream = filter.GetDataForkStream(); Stream stream = filter.GetDataForkStream();
readBytes = 0; readBytes = 0;
verifyBytes = new byte[VERIFY_SIZE]; verifyBytes = new byte[verifySize];
while(readBytes + VERIFY_SIZE < stream.Length) while(readBytes + verifySize < stream.Length)
{ {
stream.Read(verifyBytes, 0, verifyBytes.Length); stream.Read(verifyBytes, 0, verifyBytes.Length);
ctx.Update(verifyBytes); ctx.Update(verifyBytes);
@@ -78,22 +79,22 @@ namespace DiscImageChef.DiscImages
string verifySha1 = ctx.End(); string verifySha1 = ctx.End();
DicConsole.DebugWriteLine("CDRWin plugin", "Calculated SHA1: {0}", verifySha1); DicConsole.DebugWriteLine("CDRWin plugin", "Calculated SHA1: {0}", verifySha1);
DicConsole.DebugWriteLine("CDRWin plugin", "Expected SHA1: {0}", sha1); DicConsole.DebugWriteLine("CDRWin plugin", "Expected SHA1: {0}", sha1);
return verifySha1 == sha1; return verifySha1 == sha1;
} }
if(discimage.DiscHashes.TryGetValue("md5", out string md5)) if(_discImage.DiscHashes.TryGetValue("md5", out string md5))
{ {
Md5Context ctx = new Md5Context(); var ctx = new Md5Context();
foreach(IFilter filter in filters) foreach(IFilter filter in filters)
{ {
Stream stream = filter.GetDataForkStream(); Stream stream = filter.GetDataForkStream();
readBytes = 0; readBytes = 0;
verifyBytes = new byte[VERIFY_SIZE]; verifyBytes = new byte[verifySize];
while(readBytes + VERIFY_SIZE < stream.Length) while(readBytes + verifySize < stream.Length)
{ {
stream.Read(verifyBytes, 0, verifyBytes.Length); stream.Read(verifyBytes, 0, verifyBytes.Length);
ctx.Update(verifyBytes); ctx.Update(verifyBytes);
@@ -107,22 +108,22 @@ namespace DiscImageChef.DiscImages
string verifyMd5 = ctx.End(); string verifyMd5 = ctx.End();
DicConsole.DebugWriteLine("CDRWin plugin", "Calculated MD5: {0}", verifyMd5); DicConsole.DebugWriteLine("CDRWin plugin", "Calculated MD5: {0}", verifyMd5);
DicConsole.DebugWriteLine("CDRWin plugin", "Expected MD5: {0}", md5); DicConsole.DebugWriteLine("CDRWin plugin", "Expected MD5: {0}", md5);
return verifyMd5 == md5; return verifyMd5 == md5;
} }
if(discimage.DiscHashes.TryGetValue("crc32", out string crc32)) if(_discImage.DiscHashes.TryGetValue("crc32", out string crc32))
{ {
Crc32Context ctx = new Crc32Context(); var ctx = new Crc32Context();
foreach(IFilter filter in filters) foreach(IFilter filter in filters)
{ {
Stream stream = filter.GetDataForkStream(); Stream stream = filter.GetDataForkStream();
readBytes = 0; readBytes = 0;
verifyBytes = new byte[VERIFY_SIZE]; verifyBytes = new byte[verifySize];
while(readBytes + VERIFY_SIZE < stream.Length) while(readBytes + verifySize < stream.Length)
{ {
stream.Read(verifyBytes, 0, verifyBytes.Length); stream.Read(verifyBytes, 0, verifyBytes.Length);
ctx.Update(verifyBytes); ctx.Update(verifyBytes);
@@ -136,12 +137,12 @@ namespace DiscImageChef.DiscImages
string verifyCrc = ctx.End(); string verifyCrc = ctx.End();
DicConsole.DebugWriteLine("CDRWin plugin", "Calculated CRC32: {0}", verifyCrc); DicConsole.DebugWriteLine("CDRWin plugin", "Calculated CRC32: {0}", verifyCrc);
DicConsole.DebugWriteLine("CDRWin plugin", "Expected CRC32: {0}", crc32); DicConsole.DebugWriteLine("CDRWin plugin", "Expected CRC32: {0}", crc32);
return verifyCrc == crc32; return verifyCrc == crc32;
} }
foreach(string hash in discimage.DiscHashes.Keys) foreach(string hash in _discImage.DiscHashes.Keys)
DicConsole.DebugWriteLine("CDRWin plugin", "Found unsupported hash {0}", hash); DicConsole.DebugWriteLine("CDRWin plugin", "Found unsupported hash {0}", hash);
return null; return null;
@@ -150,10 +151,11 @@ namespace DiscImageChef.DiscImages
public bool? VerifySector(ulong sectorAddress) public bool? VerifySector(ulong sectorAddress)
{ {
byte[] buffer = ReadSectorLong(sectorAddress); byte[] buffer = ReadSectorLong(sectorAddress);
return CdChecksums.CheckCdSector(buffer); return CdChecksums.CheckCdSector(buffer);
} }
public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas, public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
out List<ulong> unknownLbas) out List<ulong> unknownLbas)
{ {
byte[] buffer = ReadSectorsLong(sectorAddress, length); byte[] buffer = ReadSectorsLong(sectorAddress, length);
@@ -171,19 +173,22 @@ namespace DiscImageChef.DiscImages
{ {
case null: case null:
unknownLbas.Add((ulong)i + sectorAddress); unknownLbas.Add((ulong)i + sectorAddress);
break; break;
case false: case false:
failingLbas.Add((ulong)i + sectorAddress); failingLbas.Add((ulong)i + sectorAddress);
break; break;
} }
} }
if(unknownLbas.Count > 0) return null; if(unknownLbas.Count > 0)
return null;
return failingLbas.Count <= 0; return failingLbas.Count <= 0;
} }
public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas, public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas,
out List<ulong> unknownLbas) out List<ulong> unknownLbas)
{ {
byte[] buffer = ReadSectorsLong(sectorAddress, length, track); byte[] buffer = ReadSectorsLong(sectorAddress, length, track);
@@ -201,14 +206,17 @@ namespace DiscImageChef.DiscImages
{ {
case null: case null:
unknownLbas.Add((ulong)i + sectorAddress); unknownLbas.Add((ulong)i + sectorAddress);
break; break;
case false: case false:
failingLbas.Add((ulong)i + sectorAddress); failingLbas.Add((ulong)i + sectorAddress);
break; break;
} }
} }
if(unknownLbas.Count > 0) return null; if(unknownLbas.Count > 0)
return null;
return failingLbas.Count <= 0; return failingLbas.Count <= 0;
} }
@@ -216,6 +224,7 @@ namespace DiscImageChef.DiscImages
public bool? VerifySector(ulong sectorAddress, uint track) public bool? VerifySector(ulong sectorAddress, uint track)
{ {
byte[] buffer = ReadSectorLong(sectorAddress, track); byte[] buffer = ReadSectorLong(sectorAddress, track);
return CdChecksums.CheckCdSector(buffer); return CdChecksums.CheckCdSector(buffer);
} }
} }

View File

@@ -51,32 +51,32 @@ namespace DiscImageChef.DiscImages
{ {
if(options.TryGetValue("separate", out string tmpValue)) if(options.TryGetValue("separate", out string tmpValue))
{ {
if(!bool.TryParse(tmpValue, out separateTracksWriting)) if(!bool.TryParse(tmpValue, out _separateTracksWriting))
{ {
ErrorMessage = "Invalid value for split option"; ErrorMessage = "Invalid value for split option";
return false; return false;
} }
if(separateTracksWriting) if(_separateTracksWriting)
{ {
ErrorMessage = "Separate tracksnot yet implemented"; ErrorMessage = "Separate tracks not yet implemented";
return false; return false;
} }
} }
} }
else else
separateTracksWriting = false; _separateTracksWriting = false;
if(!SupportedMediaTypes.Contains(mediaType)) if(!SupportedMediaTypes.Contains(mediaType))
{ {
ErrorMessage = $"Unsupport media format {mediaType}"; ErrorMessage = $"Unsupported media format {mediaType}";
return false; return false;
} }
imageInfo = new ImageInfo _imageInfo = new ImageInfo
{ {
MediaType = mediaType, SectorSize = sectorSize, Sectors = sectors MediaType = mediaType, SectorSize = sectorSize, Sectors = sectors
}; };
@@ -84,8 +84,8 @@ namespace DiscImageChef.DiscImages
// TODO: Separate tracks // TODO: Separate tracks
try try
{ {
writingBaseName = Path.Combine(Path.GetDirectoryName(path), Path.GetFileNameWithoutExtension(path)); _writingBaseName = Path.Combine(Path.GetDirectoryName(path), Path.GetFileNameWithoutExtension(path));
descriptorStream = new StreamWriter(path, false, Encoding.ASCII); _descriptorStream = new StreamWriter(path, false, Encoding.ASCII);
} }
catch(IOException e) catch(IOException e)
{ {
@@ -94,13 +94,13 @@ namespace DiscImageChef.DiscImages
return false; return false;
} }
discimage = new CdrWinDisc _discImage = new CdrWinDisc
{ {
Disktype = mediaType, Sessions = new List<Session>(), Tracks = new List<CdrWinTrack>() MediaType = mediaType, Sessions = new List<Session>(), Tracks = new List<CdrWinTrack>()
}; };
trackFlags = new Dictionary<byte, byte>(); _trackFlags = new Dictionary<byte, byte>();
trackIsrcs = new Dictionary<byte, string>(); _trackIsrcs = new Dictionary<byte, string>();
IsWriting = true; IsWriting = true;
ErrorMessage = null; ErrorMessage = null;
@@ -120,15 +120,15 @@ namespace DiscImageChef.DiscImages
switch(tag) switch(tag)
{ {
case MediaTagType.CD_MCN: case MediaTagType.CD_MCN:
discimage.Mcn = Encoding.ASCII.GetString(data); _discImage.Mcn = Encoding.ASCII.GetString(data);
return true; return true;
case MediaTagType.CD_TEXT: case MediaTagType.CD_TEXT:
var cdTextStream = new FileStream(writingBaseName + "_cdtext.bin", FileMode.Create, var cdTextStream = new FileStream(_writingBaseName + "_cdtext.bin", FileMode.Create,
FileAccess.ReadWrite, FileShare.None); FileAccess.ReadWrite, FileShare.None);
cdTextStream.Write(data, 0, data.Length); cdTextStream.Write(data, 0, data.Length);
discimage.Cdtextfile = Path.GetFileName(cdTextStream.Name); _discImage.CdTextFile = Path.GetFileName(cdTextStream.Name);
cdTextStream.Close(); cdTextStream.Close();
return true; return true;
@@ -149,8 +149,8 @@ namespace DiscImageChef.DiscImages
} }
Track track = Track track =
writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector && _writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
sectorAddress <= trk.TrackEndSector); sectorAddress <= trk.TrackEndSector);
if(track.TrackSequence == 0) if(track.TrackSequence == 0)
{ {
@@ -159,7 +159,7 @@ namespace DiscImageChef.DiscImages
return false; return false;
} }
FileStream trackStream = writingStreams.FirstOrDefault(kvp => kvp.Key == track.TrackSequence).Value; FileStream trackStream = _writingStreams.FirstOrDefault(kvp => kvp.Key == track.TrackSequence).Value;
if(trackStream == null) if(trackStream == null)
{ {
@@ -201,8 +201,8 @@ namespace DiscImageChef.DiscImages
} }
Track track = Track track =
writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector && _writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
sectorAddress <= trk.TrackEndSector); sectorAddress <= trk.TrackEndSector);
if(track.TrackSequence == 0) if(track.TrackSequence == 0)
{ {
@@ -211,7 +211,7 @@ namespace DiscImageChef.DiscImages
return false; return false;
} }
FileStream trackStream = writingStreams.FirstOrDefault(kvp => kvp.Key == track.TrackSequence).Value; FileStream trackStream = _writingStreams.FirstOrDefault(kvp => kvp.Key == track.TrackSequence).Value;
if(trackStream == null) if(trackStream == null)
{ {
@@ -260,8 +260,8 @@ namespace DiscImageChef.DiscImages
} }
Track track = Track track =
writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector && _writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
sectorAddress <= trk.TrackEndSector); sectorAddress <= trk.TrackEndSector);
if(track.TrackSequence == 0) if(track.TrackSequence == 0)
{ {
@@ -270,7 +270,7 @@ namespace DiscImageChef.DiscImages
return false; return false;
} }
FileStream trackStream = writingStreams.FirstOrDefault(kvp => kvp.Key == track.TrackSequence).Value; FileStream trackStream = _writingStreams.FirstOrDefault(kvp => kvp.Key == track.TrackSequence).Value;
if(trackStream == null) if(trackStream == null)
{ {
@@ -305,8 +305,8 @@ namespace DiscImageChef.DiscImages
} }
Track track = Track track =
writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector && _writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
sectorAddress <= trk.TrackEndSector); sectorAddress <= trk.TrackEndSector);
if(track.TrackSequence == 0) if(track.TrackSequence == 0)
{ {
@@ -315,7 +315,7 @@ namespace DiscImageChef.DiscImages
return false; return false;
} }
FileStream trackStream = writingStreams.FirstOrDefault(kvp => kvp.Key == track.TrackSequence).Value; FileStream trackStream = _writingStreams.FirstOrDefault(kvp => kvp.Key == track.TrackSequence).Value;
if(trackStream == null) if(trackStream == null)
{ {
@@ -364,42 +364,42 @@ namespace DiscImageChef.DiscImages
return false; return false;
} }
if(writingTracks != null && if(_writingTracks != null &&
writingStreams != null) _writingStreams != null)
foreach(FileStream oldTrack in writingStreams.Select(t => t.Value).Distinct()) foreach(FileStream oldTrack in _writingStreams.Select(t => t.Value).Distinct())
oldTrack.Close(); oldTrack.Close();
ulong currentOffset = 0; ulong currentOffset = 0;
writingTracks = new List<Track>(); _writingTracks = new List<Track>();
foreach(Track track in tracks.OrderBy(t => t.TrackSequence)) foreach(Track track in tracks.OrderBy(t => t.TrackSequence))
{ {
Track newTrack = track; Track newTrack = track;
newTrack.TrackFile = separateTracksWriting ? writingBaseName + $"_track{track.TrackSequence:D2}.bin" newTrack.TrackFile = _separateTracksWriting ? _writingBaseName + $"_track{track.TrackSequence:D2}.bin"
: writingBaseName + ".bin"; : _writingBaseName + ".bin";
newTrack.TrackFileOffset = separateTracksWriting ? 0 : currentOffset; newTrack.TrackFileOffset = _separateTracksWriting ? 0 : currentOffset;
writingTracks.Add(newTrack); _writingTracks.Add(newTrack);
currentOffset += (ulong)newTrack.TrackRawBytesPerSector * currentOffset += (ulong)newTrack.TrackRawBytesPerSector *
((newTrack.TrackEndSector - newTrack.TrackStartSector) + 1); ((newTrack.TrackEndSector - newTrack.TrackStartSector) + 1);
} }
writingStreams = new Dictionary<uint, FileStream>(); _writingStreams = new Dictionary<uint, FileStream>();
if(separateTracksWriting) if(_separateTracksWriting)
foreach(Track track in writingTracks) foreach(Track track in _writingTracks)
writingStreams.Add(track.TrackSequence, _writingStreams.Add(track.TrackSequence,
new FileStream(track.TrackFile, FileMode.OpenOrCreate, FileAccess.ReadWrite, new FileStream(track.TrackFile, FileMode.OpenOrCreate, FileAccess.ReadWrite,
FileShare.None)); FileShare.None));
else else
{ {
var jointstream = new FileStream(writingBaseName + ".bin", FileMode.OpenOrCreate, FileAccess.ReadWrite, var jointStream = new FileStream(_writingBaseName + ".bin", FileMode.OpenOrCreate, FileAccess.ReadWrite,
FileShare.None); FileShare.None);
foreach(Track track in writingTracks) foreach(Track track in _writingTracks)
writingStreams.Add(track.TrackSequence, jointstream); _writingStreams.Add(track.TrackSequence, jointStream);
} }
return true; return true;
@@ -414,91 +414,118 @@ namespace DiscImageChef.DiscImages
return false; return false;
} }
if(separateTracksWriting) if(_separateTracksWriting)
foreach(FileStream writingStream in writingStreams.Values) foreach(FileStream writingStream in _writingStreams.Values)
{ {
writingStream.Flush(); writingStream.Flush();
writingStream.Close(); writingStream.Close();
} }
else else
{ {
writingStreams.First().Value.Flush(); _writingStreams.First().Value.Flush();
writingStreams.First().Value.Close(); _writingStreams.First().Value.Close();
} }
int currentSession = 0; int currentSession = 0;
if(!string.IsNullOrWhiteSpace(discimage.Comment)) if(!string.IsNullOrWhiteSpace(_discImage.Comment))
{ {
string[] commentLines = discimage.Comment.Split(new[] string[] commentLines = _discImage.Comment.Split(new[]
{ {
'\n' '\n'
}, StringSplitOptions.RemoveEmptyEntries); }, StringSplitOptions.RemoveEmptyEntries);
foreach(string line in commentLines) foreach(string line in commentLines)
descriptorStream.WriteLine("REM {0}", line); _descriptorStream.WriteLine("REM {0}", line);
} }
descriptorStream.WriteLine("REM ORIGINAL MEDIA-TYPE: {0}", MediaTypeToCdrwinType(imageInfo.MediaType)); _descriptorStream.WriteLine("REM ORIGINAL MEDIA-TYPE: {0}", MediaTypeToCdrwinType(_imageInfo.MediaType));
if(!string.IsNullOrEmpty(discimage.Cdtextfile)) _descriptorStream.WriteLine("REM METADATA DIC MEDIA-TYPE: {0}", _imageInfo.MediaType);
descriptorStream.WriteLine("CDTEXTFILE \"{0}\"", Path.GetFileName(discimage.Cdtextfile));
if(!string.IsNullOrEmpty(discimage.Title)) if(!string.IsNullOrEmpty(_imageInfo.Application))
descriptorStream.WriteLine("TITLE {0}", discimage.Title); {
_descriptorStream.WriteLine("REM Ripping Tool: {0}", _imageInfo.Application);
if(!string.IsNullOrEmpty(discimage.Mcn)) if(!string.IsNullOrEmpty(_imageInfo.ApplicationVersion))
descriptorStream.WriteLine("CATALOG {0}", discimage.Mcn); _descriptorStream.WriteLine("REM Ripping Tool Version: {0}", _imageInfo.ApplicationVersion);
}
if(!string.IsNullOrEmpty(discimage.Barcode)) if(DumpHardware != null)
descriptorStream.WriteLine("UPC_EAN {0}", discimage.Barcode); {
foreach(var dumpData in from dump in DumpHardware from extent in dump.Extents.OrderBy(e => e.Start)
select new
{
dump.Manufacturer, dump.Model, dump.Firmware, dump.Serial,
Application = dump.Software.Name,
ApplicationVersion = dump.Software.Version, dump.Software.OperatingSystem,
extent.Start, extent.End
})
{
_descriptorStream.
WriteLine($"REM METADATA DUMP EXTENT: {dumpData.Application} | {dumpData.ApplicationVersion} | {dumpData.OperatingSystem} | {dumpData.Manufacturer} | {dumpData.Model} | {dumpData.Firmware} | {dumpData.Serial} | {dumpData.Start}:{dumpData.End}");
}
}
if(!separateTracksWriting) if(!string.IsNullOrEmpty(_discImage.CdTextFile))
descriptorStream.WriteLine("FILE \"{0}\" BINARY", Path.GetFileName(writingStreams.First().Value.Name)); _descriptorStream.WriteLine("CDTEXTFILE \"{0}\"", Path.GetFileName(_discImage.CdTextFile));
foreach(Track track in writingTracks) if(!string.IsNullOrEmpty(_discImage.Title))
_descriptorStream.WriteLine("TITLE {0}", _discImage.Title);
if(!string.IsNullOrEmpty(_discImage.Mcn))
_descriptorStream.WriteLine("CATALOG {0}", _discImage.Mcn);
if(!string.IsNullOrEmpty(_discImage.Barcode))
_descriptorStream.WriteLine("UPC_EAN {0}", _discImage.Barcode);
if(!_separateTracksWriting)
_descriptorStream.WriteLine("FILE \"{0}\" BINARY",
Path.GetFileName(_writingStreams.First().Value.Name));
foreach(Track track in _writingTracks)
{ {
if(track.TrackSession > currentSession) if(track.TrackSession > currentSession)
descriptorStream.WriteLine("REM SESSION {0}", ++currentSession); _descriptorStream.WriteLine("REM SESSION {0}", ++currentSession);
if(separateTracksWriting) if(_separateTracksWriting)
descriptorStream.WriteLine("FILE \"{0}\" BINARY", Path.GetFileName(track.TrackFile)); _descriptorStream.WriteLine("FILE \"{0}\" BINARY", Path.GetFileName(track.TrackFile));
(byte minute, byte second, byte frame) msf = LbaToMsf(track.TrackStartSector); (byte minute, byte second, byte frame) msf = LbaToMsf(track.TrackStartSector);
descriptorStream.WriteLine(" TRACK {0:D2} {1}", track.TrackSequence, GetTrackMode(track)); _descriptorStream.WriteLine(" TRACK {0:D2} {1}", track.TrackSequence, GetTrackMode(track));
if(trackFlags.TryGetValue((byte)track.TrackSequence, out byte flagsByte)) if(_trackFlags.TryGetValue((byte)track.TrackSequence, out byte flagsByte))
if(flagsByte != 0 && if(flagsByte != 0 &&
flagsByte != (byte)CdFlags.DataTrack) flagsByte != (byte)CdFlags.DataTrack)
{ {
var flags = (CdFlags)flagsByte; var flags = (CdFlags)flagsByte;
descriptorStream.WriteLine(" FLAGS{0}{1}{2}", _descriptorStream.WriteLine(" FLAGS{0}{1}{2}",
flags.HasFlag(CdFlags.CopyPermitted) ? " DCP" : "", flags.HasFlag(CdFlags.CopyPermitted) ? " DCP" : "",
flags.HasFlag(CdFlags.FourChannel) ? " 4CH" : "", flags.HasFlag(CdFlags.FourChannel) ? " 4CH" : "",
flags.HasFlag(CdFlags.PreEmphasis) ? " PRE" : ""); flags.HasFlag(CdFlags.PreEmphasis) ? " PRE" : "");
} }
if(trackIsrcs.TryGetValue((byte)track.TrackSequence, out string isrc)) if(_trackIsrcs.TryGetValue((byte)track.TrackSequence, out string isrc))
descriptorStream.WriteLine(" ISRC {0}", isrc); _descriptorStream.WriteLine(" ISRC {0}", isrc);
if(track.TrackPregap > 0) if(track.TrackPregap > 0)
{ {
descriptorStream.WriteLine(" INDEX {0:D2} {1:D2}:{2:D2}:{3:D2}", 0, msf.minute, msf.second, _descriptorStream.WriteLine(" INDEX {0:D2} {1:D2}:{2:D2}:{3:D2}", 0, msf.minute, msf.second,
msf.frame); msf.frame);
msf = LbaToMsf(track.TrackStartSector + track.TrackPregap); msf = LbaToMsf(track.TrackStartSector + track.TrackPregap);
descriptorStream.WriteLine(" INDEX {0:D2} {1:D2}:{2:D2}:{3:D2}", 1, msf.minute, msf.second, _descriptorStream.WriteLine(" INDEX {0:D2} {1:D2}:{2:D2}:{3:D2}", 1, msf.minute, msf.second,
msf.frame); msf.frame);
} }
else else
descriptorStream.WriteLine(" INDEX {0:D2} {1:D2}:{2:D2}:{3:D2}", 1, msf.minute, msf.second, _descriptorStream.WriteLine(" INDEX {0:D2} {1:D2}:{2:D2}:{3:D2}", 1, msf.minute, msf.second,
msf.frame); msf.frame);
} }
descriptorStream.Flush(); _descriptorStream.Flush();
descriptorStream.Close(); _descriptorStream.Close();
IsWriting = false; IsWriting = false;
ErrorMessage = ""; ErrorMessage = "";
@@ -523,8 +550,8 @@ namespace DiscImageChef.DiscImages
} }
Track track = Track track =
writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector && _writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
sectorAddress <= trk.TrackEndSector); sectorAddress <= trk.TrackEndSector);
if(track.TrackSequence == 0) if(track.TrackSequence == 0)
{ {
@@ -544,14 +571,14 @@ namespace DiscImageChef.DiscImages
return false; return false;
} }
trackFlags.Add((byte)track.TrackSequence, data[0]); _trackFlags.Add((byte)track.TrackSequence, data[0]);
return true; return true;
} }
case SectorTagType.CdTrackIsrc: case SectorTagType.CdTrackIsrc:
{ {
if(data != null) if(data != null)
trackIsrcs.Add((byte)track.TrackSequence, Encoding.UTF8.GetString(data)); _trackIsrcs.Add((byte)track.TrackSequence, Encoding.UTF8.GetString(data));
return true; return true;
} }
@@ -565,15 +592,22 @@ namespace DiscImageChef.DiscImages
public bool WriteSectorsTag(byte[] data, ulong sectorAddress, uint length, SectorTagType tag) => public bool WriteSectorsTag(byte[] data, ulong sectorAddress, uint length, SectorTagType tag) =>
WriteSectorTag(data, sectorAddress, tag); WriteSectorTag(data, sectorAddress, tag);
public bool SetDumpHardware(List<DumpHardwareType> dumpHardware) => false; public bool SetDumpHardware(List<DumpHardwareType> dumpHardware)
{
DumpHardware = dumpHardware;
return true;
}
public bool SetCicmMetadata(CICMMetadataType metadata) => false; public bool SetCicmMetadata(CICMMetadataType metadata) => false;
public bool SetMetadata(ImageInfo metadata) public bool SetMetadata(ImageInfo metadata)
{ {
discimage.Barcode = metadata.MediaBarcode; _discImage.Barcode = metadata.MediaBarcode;
discimage.Comment = metadata.Comments; _discImage.Comment = metadata.Comments;
discimage.Title = metadata.MediaTitle; _discImage.Title = metadata.MediaTitle;
_imageInfo.Application = metadata.Application;
_imageInfo.ApplicationVersion = metadata.ApplicationVersion;
return true; return true;
} }

View File

@@ -186,11 +186,20 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=ATAPI/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=ATAPI/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ATIP/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=ATIP/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=BANDAI/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=BANDAI/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=BDRDL/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=BDRE/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=BDREDL/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=BDROM/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=bitsetting/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=bitsetting/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Bluray/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Bluray/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=cartstatus/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=cartstatus/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=CDDA/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=CDDA/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=CDDB/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=CDMRW/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=CDRW/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=CDRWIN/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=cdtext/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=cdtext/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=CDTEXTFILE/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=CDTV/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=CDTV/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=cdrom/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=cdrom/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=certance/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=certance/@EntryIndexedValue">True</s:Boolean>
@@ -198,12 +207,25 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=checksums/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=checksums/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=cicm/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=cicm/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Claunia/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Claunia/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=cuesheet/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=DDCD/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=DDCD/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Deinterleave/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Deinterleave/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=dicremote/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=dicremote/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Drive_0027s/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Drive_0027s/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=DVDPMRW/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=DVDPMRWDL/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=DVDPR/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=DVDPRDL/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=DVDPRW/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=DVDPRWDL/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=DVDPVR/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=dvdr/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=dvdr/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=dvdram/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=dvdram/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=DVDRDL/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=DVDROM/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=DVDRW/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=DVDRWDL/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=DVDVR/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ecsd/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=ecsd/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=eeprom/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=eeprom/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=EVPD/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=EVPD/@EntryIndexedValue">True</s:Boolean>
@@ -211,9 +233,16 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=getconfiguration/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=getconfiguration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=hddvd/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=hddvd/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=hddvdr/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=hddvdr/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=HDDVDRAM/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=HDDVDRDL/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=HDDVDROM/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=HDDVDRW/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=HDDVDRWDL/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Hldtst/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Hldtst/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=iomega/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=iomega/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=isobuster/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=isrc/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=isrc/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Isrcs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Kreon/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Kreon/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=lastrmd/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=lastrmd/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=lastsequence/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=lastsequence/@EntryIndexedValue">True</s:Boolean>
@@ -242,6 +271,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Plextor/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Plextor/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=pmin/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=pmin/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Portillo/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Portillo/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Postgap/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Powe/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Powe/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=pregap/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=pregap/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=pregaps/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=pregaps/@EntryIndexedValue">True</s:Boolean>
@@ -257,6 +287,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Reiser/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Reiser/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=remapanchor/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=remapanchor/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=reportdensitysupport/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=reportdensitysupport/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=SCMS/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=SDHCI/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=SDHCI/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Secu/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Secu/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=spamsum/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=spamsum/@EntryIndexedValue">True</s:Boolean>
@@ -264,6 +295,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=subpages/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=subpages/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=subchannel/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=subchannel/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=subchannels/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=subchannels/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Trurip/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=umounting/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=umounting/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=undecoded/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=undecoded/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Vari/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Vari/@EntryIndexedValue">True</s:Boolean>