Add writing support to CDRWin cuesheet disc image.

This commit is contained in:
2018-01-01 20:05:49 +00:00
parent 5442d79252
commit df563dd2dd

View File

@@ -44,7 +44,7 @@ using DiscImageChef.Filters;
namespace DiscImageChef.DiscImages
{
// TODO: Implement track flags
public class CdrWin : IMediaImage
public class CdrWin : IWritableImage
{
// Type for FILE entity
/// <summary>Data as-is in little-endian</summary>
@@ -172,12 +172,16 @@ namespace DiscImageChef.DiscImages
IFilter cdrwinFilter;
StreamReader cueStream;
StreamWriter descriptorStream;
CdrWinDisc discimage;
ImageInfo imageInfo;
Stream imageStream;
/// <summary>Dictionary, index is track #, value is TrackFile</summary>
Dictionary<uint, ulong> offsetmap;
List<Partition> partitions;
bool separateTracksWriting;
string writingBaseName;
Dictionary<uint, FileStream> writingStreams;
List<Track> writingTracks;
public CdrWin()
{
@@ -210,7 +214,7 @@ namespace DiscImageChef.DiscImages
public string Format => "CDRWin CUESheet";
public List<Partition> Partitions => partitions;
public List<Partition> Partitions { get; private set; }
public List<Track> Tracks
{
@@ -240,8 +244,8 @@ namespace DiscImageChef.DiscImages
};
dicTrack.TrackEndSector = dicTrack.TrackStartSector + cdrTrack.Sectors - 1;
if(!cdrTrack.Indexes.TryGetValue(0, out dicTrack.TrackStartSector))
cdrTrack.Indexes.TryGetValue(1, out dicTrack.TrackStartSector);
/*if(!cdrTrack.Indexes.TryGetValue(0, out dicTrack.TrackStartSector))
cdrTrack.Indexes.TryGetValue(1, out dicTrack.TrackStartSector);*/
if(cdrTrack.Bps == 2448)
{
dicTrack.TrackSubchannelFilter = cdrTrack.Trackfile.Datafilter;
@@ -529,7 +533,8 @@ namespace DiscImageChef.DiscImages
// Check if file exists
if(currentfile.Datafilter == null)
if(datafile[0] == '/' || datafile[0] == '/' && datafile[1] == '.') // UNIX absolute path
if(datafile[0] == '/' || datafile[0] == '/' && datafile[1] == '.'
) // UNIX absolute path
{
Regex unixpath = new Regex("^(.+)/([^/]+)$");
Match unixpathmatch = unixpath.Match(datafile);
@@ -582,7 +587,8 @@ namespace DiscImageChef.DiscImages
}
else
{
string path = imageFilter.GetParentFolder() + Path.PathSeparator + datafile;
string path =
imageFilter.GetParentFolder() + Path.PathSeparator + datafile;
currentfile.Datafilter = filtersList.GetFilter(path);
if(currentfile.Datafilter == null)
@@ -642,7 +648,8 @@ namespace DiscImageChef.DiscImages
throw new
FeatureUnsupportedImageException($"Found INDEX {index} before INDEX 00 or INDEX 01");
if(index == 0 || index == 1 && !currenttrack.Indexes.ContainsKey(0))
if(index == 0 ||
index == 1 && !currenttrack.Indexes.ContainsKey(0))
if((int)(currenttrack.Sequence - 2) >= 0 && offset > 1)
{
cuetracks[currenttrack.Sequence - 2].Sectors = offset - currentfileoffsetsector;
@@ -736,6 +743,7 @@ namespace DiscImageChef.DiscImages
currenttrack.Trackfile = currentfile;
cuetracks[currenttrack.Sequence - 1] = currenttrack;
}
currenttrack = new CdrWinTrack
{
Indexes = new Dictionary<int, ulong>(),
@@ -837,48 +845,77 @@ namespace DiscImageChef.DiscImages
}
if(!data && !firstdata) discimage.Disktype = MediaType.CDDA;
else if(cdg) discimage.Disktype = MediaType.CDG;
else if(cdi) discimage.Disktype = MediaType.CDI;
else if(cdg)
discimage.Disktype = MediaType.CDG;
else if(cdi)
discimage.Disktype = MediaType.CDI;
else if(firstaudio && data && discimage.Sessions.Count > 1 && mode2)
discimage.Disktype = MediaType.CDPLUS;
else if(firstdata && audio || mode2) discimage.Disktype = MediaType.CDROMXA;
else if(!audio) discimage.Disktype = MediaType.CDROM;
else discimage.Disktype = MediaType.CD;
else if(firstdata && audio || mode2)
discimage.Disktype = MediaType.CDROMXA;
else if(!audio)
discimage.Disktype = MediaType.CDROM;
else
discimage.Disktype = MediaType.CD;
}
// DEBUG information
DicConsole.DebugWriteLine("CDRWin plugin", "Disc image parsing results");
DicConsole.DebugWriteLine("CDRWin plugin",
"Disc image parsing results");
DicConsole.DebugWriteLine("CDRWin plugin", "Disc CD-TEXT:");
if(discimage.Arranger == null) DicConsole.DebugWriteLine("CDRWin plugin", "\tArranger is not set.");
else DicConsole.DebugWriteLine("CDRWin plugin", "\tArranger: {0}", discimage.Arranger);
else
DicConsole.DebugWriteLine("CDRWin plugin", "\tArranger: {0}",
discimage.Arranger);
if(discimage.Composer == null) DicConsole.DebugWriteLine("CDRWin plugin", "\tComposer is not set.");
else DicConsole.DebugWriteLine("CDRWin plugin", "\tComposer: {0}", discimage.Composer);
else
DicConsole.DebugWriteLine("CDRWin plugin", "\tComposer: {0}",
discimage.Composer);
if(discimage.Genre == null) DicConsole.DebugWriteLine("CDRWin plugin", "\tGenre is not set.");
else DicConsole.DebugWriteLine("CDRWin plugin", "\tGenre: {0}", discimage.Genre);
else
DicConsole.DebugWriteLine("CDRWin plugin", "\tGenre: {0}",
discimage.Genre);
if(discimage.Performer == null) DicConsole.DebugWriteLine("CDRWin plugin", "\tPerformer is not set.");
else DicConsole.DebugWriteLine("CDRWin plugin", "\tPerformer: {0}", discimage.Performer);
else
DicConsole.DebugWriteLine("CDRWin plugin", "\tPerformer: {0}",
discimage.Performer);
if(discimage.Songwriter == null) DicConsole.DebugWriteLine("CDRWin plugin", "\tSongwriter is not set.");
else DicConsole.DebugWriteLine("CDRWin plugin", "\tSongwriter: {0}", discimage.Songwriter);
else
DicConsole.DebugWriteLine("CDRWin plugin", "\tSongwriter: {0}",
discimage.Songwriter);
if(discimage.Title == null) DicConsole.DebugWriteLine("CDRWin plugin", "\tTitle is not set.");
else DicConsole.DebugWriteLine("CDRWin plugin", "\tTitle: {0}", discimage.Title);
else
DicConsole.DebugWriteLine("CDRWin plugin", "\tTitle: {0}",
discimage.Title);
if(discimage.Cdtextfile == null)
DicConsole.DebugWriteLine("CDRWin plugin", "\tCD-TEXT binary file not set.");
else DicConsole.DebugWriteLine("CDRWin plugin", "\tCD-TEXT binary file: {0}", discimage.Cdtextfile);
DicConsole.DebugWriteLine("CDRWin plugin", "Disc information:");
if(discimage.Disktypestr == null)
DicConsole.DebugWriteLine("CDRWin plugin", "\tISOBuster disc type not set.");
else DicConsole.DebugWriteLine("CDRWin plugin", "\tISOBuster disc type: {0}", discimage.Disktypestr);
DicConsole.DebugWriteLine("CDRWin plugin", "\tGuessed disk type: {0}", discimage.Disktype);
DicConsole.DebugWriteLine("CDRWin plugin",
"\tISOBuster disc type not set.");
else
DicConsole.DebugWriteLine("CDRWin plugin", "\tISOBuster disc type: {0}",
discimage.Disktypestr);
DicConsole.DebugWriteLine("CDRWin plugin", "\tGuessed disk type: {0}",
discimage.Disktype);
if(discimage.Barcode == null) DicConsole.DebugWriteLine("CDRWin plugin", "\tBarcode not set.");
else DicConsole.DebugWriteLine("CDRWin plugin", "\tBarcode: {0}", discimage.Barcode);
else
DicConsole.DebugWriteLine("CDRWin plugin", "\tBarcode: {0}",
discimage.Barcode);
if(discimage.DiskId == null) DicConsole.DebugWriteLine("CDRWin plugin", "\tDisc ID not set.");
else DicConsole.DebugWriteLine("CDRWin plugin", "\tDisc ID: {0}", discimage.DiskId);
else
DicConsole.DebugWriteLine("CDRWin plugin", "\tDisc ID: {0}",
discimage.DiskId);
if(discimage.Mcn == null) DicConsole.DebugWriteLine("CDRWin plugin", "\tMCN not set.");
else DicConsole.DebugWriteLine("CDRWin plugin", "\tMCN: {0}", discimage.Mcn);
if(discimage.Comment == null) DicConsole.DebugWriteLine("CDRWin plugin", "\tComment not set.");
else DicConsole.DebugWriteLine("CDRWin plugin", "\tComment: \"{0}\"", discimage.Comment);
else
DicConsole.DebugWriteLine("CDRWin plugin", "\tComment: \"{0}\"",
discimage.Comment);
DicConsole.DebugWriteLine("CDRWin plugin", "Session information:");
DicConsole.DebugWriteLine("CDRWin plugin", "\tDisc contains {0} sessions", discimage.Sessions.Count);
DicConsole.DebugWriteLine("CDRWin plugin", "\tDisc contains {0} sessions",
discimage.Sessions.Count);
for(int i = 0; i < discimage.Sessions.Count; i++)
{
DicConsole.DebugWriteLine("CDRWin plugin", "\tSession {0} information:", i + 1);
@@ -908,7 +945,8 @@ namespace DiscImageChef.DiscImages
if(discimage.Tracks[i].FlagDcp)
DicConsole.DebugWriteLine("CDRWin plugin", "\t\tTrack allows digital copy");
if(discimage.Tracks[i].FlagPre)
DicConsole.DebugWriteLine("CDRWin plugin", "\t\tTrack has pre-emphasis applied");
DicConsole.DebugWriteLine("CDRWin plugin",
"\t\tTrack has pre-emphasis applied");
if(discimage.Tracks[i].FlagScms) DicConsole.DebugWriteLine("CDRWin plugin", "\t\tTrack has SCMS");
DicConsole.DebugWriteLine("CDRWin plugin",
@@ -951,7 +989,7 @@ namespace DiscImageChef.DiscImages
DicConsole.DebugWriteLine("CDRWin plugin", "Building offset map");
partitions = new List<Partition>();
Partitions = new List<Partition>();
ulong byteOffset = 0;
ulong sectorOffset = 0;
@@ -1070,16 +1108,17 @@ namespace DiscImageChef.DiscImages
}
}
partitions.Add(partition);
Partitions.Add(partition);
}
// Print offset map
DicConsole.DebugWriteLine("CDRWin plugin", "printing partition map");
foreach(Partition partition in partitions)
foreach(Partition partition in Partitions)
{
DicConsole.DebugWriteLine("CDRWin plugin", "Partition sequence: {0}", partition.Sequence);
DicConsole.DebugWriteLine("CDRWin plugin", "\tPartition name: {0}", partition.Name);
DicConsole.DebugWriteLine("CDRWin plugin", "\tPartition description: {0}", partition.Description);
DicConsole.DebugWriteLine("CDRWin plugin", "\tPartition description: {0}",
partition.Description);
DicConsole.DebugWriteLine("CDRWin plugin", "\tPartition type: {0}", partition.Type);
DicConsole.DebugWriteLine("CDRWin plugin", "\tPartition starting sector: {0}", partition.Start);
DicConsole.DebugWriteLine("CDRWin plugin", "\tPartition sectors: {0}", partition.Length);
@@ -1094,9 +1133,10 @@ namespace DiscImageChef.DiscImages
discimage.Disktype == MediaType.CDMIDI)
imageInfo.SectorSize = 2448; // CD+G subchannels ARE user data, as CD+G are useless without them
else if(discimage.Disktype != MediaType.CDROMXA && discimage.Disktype != MediaType.CDDA &&
discimage.Disktype != MediaType.CDI &&
discimage.Disktype != MediaType.CDPLUS) imageInfo.SectorSize = 2048; // Only data tracks
else imageInfo.SectorSize = 2352; // All others
discimage.Disktype != MediaType.CDI && discimage.Disktype != MediaType.CDPLUS)
imageInfo.SectorSize = 2048; // Only data tracks
else
imageInfo.SectorSize = 2352; // All others
if(discimage.Mcn != null) imageInfo.ReadableMediaTags.Add(MediaTagType.CD_MCN);
if(discimage.Cdtextfile != null) imageInfo.ReadableMediaTags.Add(MediaTagType.CD_TEXT);
@@ -1783,16 +1823,419 @@ namespace DiscImageChef.DiscImages
return null;
}
public IEnumerable<MediaTagType> SupportedMediaTags => new[] {MediaTagType.CD_MCN, MediaTagType.CD_TEXT};
public IEnumerable<SectorTagType> SupportedSectorTags =>
new[]
{
SectorTagType.CdSectorEcc, SectorTagType.CdSectorEccP, SectorTagType.CdSectorEccQ,
SectorTagType.CdSectorEdc, SectorTagType.CdSectorHeader, SectorTagType.CdSectorSubchannel,
SectorTagType.CdSectorSubHeader, SectorTagType.CdSectorSync, SectorTagType.CdTrackFlags,
SectorTagType.CdTrackIsrc
};
public IEnumerable<MediaType> SupportedMediaTypes =>
new[]
{
MediaType.BDR, MediaType.BDRE, MediaType.BDREXL, MediaType.BDROM, MediaType.BDRXL, MediaType.CBHD,
MediaType.CD, MediaType.CDDA, MediaType.CDEG, MediaType.CDG, MediaType.CDI, MediaType.CDMIDI,
MediaType.CDMRW, MediaType.CDPLUS, MediaType.CDR, MediaType.CDROM, MediaType.CDROMXA, MediaType.CDRW,
MediaType.CDV, MediaType.DDCD, MediaType.DDCDR, MediaType.DDCDRW, MediaType.DVDDownload,
MediaType.DVDPR, MediaType.DVDPRDL, MediaType.DVDPRW, MediaType.DVDPRWDL, MediaType.DVDR,
MediaType.DVDRAM, MediaType.DVDRDL, MediaType.DVDROM, MediaType.DVDRW, MediaType.DVDRWDL, MediaType.EVD,
MediaType.FDDVD, MediaType.DTSCD, MediaType.FVD, MediaType.HDDVDR, MediaType.HDDVDRAM,
MediaType.HDDVDRDL, MediaType.HDDVDROM, MediaType.HDDVDRW, MediaType.HDDVDRWDL, MediaType.HDVMD,
MediaType.HVD, MediaType.JaguarCD, MediaType.MEGACD, MediaType.PD650, MediaType.PD650_WORM,
MediaType.PS1CD, MediaType.PS2CD, MediaType.PS2DVD, MediaType.PS3BD, MediaType.PS3DVD, MediaType.PS4BD,
MediaType.SuperCDROM2, MediaType.SVCD, MediaType.SVOD, MediaType.SATURNCD, MediaType.ThreeDO,
MediaType.UDO, MediaType.UDO2, MediaType.UDO2_WORM, MediaType.UMD, MediaType.VCD, MediaType.VCDHD
};
public IEnumerable<(string name, Type type, string description)> SupportedOptions =>
new[] {("separate", typeof(bool), "Write each track to a separate file.")};
public IEnumerable<string> KnownExtensions => new[] {".cue"};
public bool IsWriting { get; private set; }
public string ErrorMessage { get; private set; }
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
uint sectorSize)
{
if(options != null)
{
if(options.TryGetValue("separate", out string tmpValue))
{
if(!bool.TryParse(tmpValue, out separateTracksWriting))
{
ErrorMessage = "Invalid value for split option";
return false;
}
if(separateTracksWriting)
{
ErrorMessage = "Separate tracksnot yet implemented";
return false;
}
}
}
else separateTracksWriting = false;
if(!SupportedMediaTypes.Contains(mediaType))
{
ErrorMessage = $"Unsupport media format {mediaType}";
return false;
}
imageInfo = new ImageInfo {MediaType = mediaType, SectorSize = sectorSize, Sectors = sectors};
// TODO: Separate tracks
try
{
writingBaseName = Path.Combine(Path.GetDirectoryName(path), Path.GetFileNameWithoutExtension(path));
descriptorStream = new StreamWriter(path, false, Encoding.ASCII);
}
catch(IOException e)
{
ErrorMessage = $"Could not create new image file, exception {e.Message}";
return false;
}
discimage = new CdrWinDisc
{
Disktype = mediaType,
Sessions = new List<Session>(),
Tracks = new List<CdrWinTrack>()
};
IsWriting = true;
ErrorMessage = null;
return true;
}
public bool WriteMediaTag(byte[] data, MediaTagType tag)
{
if(!IsWriting)
{
ErrorMessage = "Tried to write on a non-writable image";
return false;
}
switch(tag)
{
case MediaTagType.CD_MCN:
discimage.Mcn = Encoding.ASCII.GetString(data);
return true;
case MediaTagType.CD_TEXT:
FileStream cdTextStream = new FileStream(writingBaseName + "_cdtext.bin", FileMode.Create,
FileAccess.ReadWrite, FileShare.None);
cdTextStream.Write(data, 0, data.Length);
discimage.Cdtextfile = Path.GetFileName(cdTextStream.Name);
cdTextStream.Close();
return true;
default:
ErrorMessage = $"Unsupported media tag {tag}";
return false;
}
}
public bool WriteSector(byte[] data, ulong sectorAddress)
{
if(!IsWriting)
{
ErrorMessage = "Tried to write on a non-writable image";
return false;
}
Track track =
writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
sectorAddress <= trk.TrackEndSector);
if(track.TrackSequence == 0)
{
ErrorMessage = $"Can't found track containing {sectorAddress}";
return false;
}
FileStream trackStream = writingStreams.FirstOrDefault(kvp => kvp.Key == track.TrackSequence).Value;
if(trackStream == null)
{
ErrorMessage = $"Can't found file containing {sectorAddress}";
return false;
}
if(track.TrackBytesPerSector != track.TrackRawBytesPerSector)
{
ErrorMessage = "Invalid write mode for this sector";
return false;
}
if(data.Length != track.TrackRawBytesPerSector)
{
ErrorMessage = "Incorrect data size";
return false;
}
trackStream.Seek((long)(track.TrackFileOffset + (sectorAddress - track.TrackStartSector) * (ulong)track.TrackRawBytesPerSector),
SeekOrigin.Begin);
trackStream.Write(data, 0, data.Length);
return true;
}
public bool WriteSectors(byte[] data, ulong sectorAddress, uint length)
{
if(!IsWriting)
{
ErrorMessage = "Tried to write on a non-writable image";
return false;
}
Track track =
writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
sectorAddress <= trk.TrackEndSector);
if(track.TrackSequence == 0)
{
ErrorMessage = $"Can't found track containing {sectorAddress}";
return false;
}
FileStream trackStream = writingStreams.FirstOrDefault(kvp => kvp.Key == track.TrackSequence).Value;
if(trackStream == null)
{
ErrorMessage = $"Can't found file containing {sectorAddress}";
return false;
}
if(track.TrackBytesPerSector != track.TrackRawBytesPerSector)
{
ErrorMessage = "Invalid write mode for this sector";
return false;
}
if(sectorAddress + length > track.TrackEndSector + 1)
{
ErrorMessage = "Can't cross tracks";
return false;
}
if(data.Length % track.TrackRawBytesPerSector != 0)
{
ErrorMessage = "Incorrect data size";
return false;
}
trackStream.Seek((long)(track.TrackFileOffset + (sectorAddress - track.TrackStartSector) * (ulong)track.TrackRawBytesPerSector),
SeekOrigin.Begin);
trackStream.Write(data, 0, data.Length);
return true;
}
public bool WriteSectorLong(byte[] data, ulong sectorAddress)
{
if(!IsWriting)
{
ErrorMessage = "Tried to write on a non-writable image";
return false;
}
Track track =
writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
sectorAddress <= trk.TrackEndSector);
if(track.TrackSequence == 0)
{
ErrorMessage = $"Can't found track containing {sectorAddress}";
return false;
}
FileStream trackStream = writingStreams.FirstOrDefault(kvp => kvp.Key == track.TrackSequence).Value;
if(trackStream == null)
{
ErrorMessage = $"Can't found file containing {sectorAddress}";
return false;
}
if(data.Length != track.TrackRawBytesPerSector)
{
ErrorMessage = "Incorrect data size";
return false;
}
trackStream.Seek((long)(track.TrackFileOffset + (sectorAddress - track.TrackStartSector) * (ulong)track.TrackRawBytesPerSector),
SeekOrigin.Begin);
trackStream.Write(data, 0, data.Length);
return true;
}
public bool WriteSectorsLong(byte[] data, ulong sectorAddress, uint length)
{
if(!IsWriting)
{
ErrorMessage = "Tried to write on a non-writable image";
return false;
}
Track track =
writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
sectorAddress <= trk.TrackEndSector);
if(track.TrackSequence == 0)
{
ErrorMessage = $"Can't found track containing {sectorAddress}";
return false;
}
FileStream trackStream = writingStreams.FirstOrDefault(kvp => kvp.Key == track.TrackSequence).Value;
if(trackStream == null)
{
ErrorMessage = $"Can't found file containing {sectorAddress}";
return false;
}
if(sectorAddress + length > track.TrackEndSector + 1)
{
ErrorMessage = "Can't cross tracks";
return false;
}
if(data.Length % track.TrackRawBytesPerSector != 0)
{
ErrorMessage = "Incorrect data size";
return false;
}
trackStream.Seek((long)(track.TrackFileOffset + (sectorAddress - track.TrackStartSector) * (ulong)track.TrackRawBytesPerSector),
SeekOrigin.Begin);
trackStream.Write(data, 0, data.Length);
return true;
}
public bool SetTracks(List<Track> tracks)
{
if(!IsWriting)
{
ErrorMessage = "Tried to write on a non-writable image";
return false;
}
if(tracks == null || tracks.Count == 0)
{
ErrorMessage = "Invalid tracks sent";
return false;
}
ulong currentOffset = 0;
writingTracks = new List<Track>();
foreach(Track track in tracks.OrderBy(t => t.TrackSequence))
{
Track newTrack = track;
newTrack.TrackFile = separateTracksWriting
? writingBaseName + $"_track{track.TrackSequence:D2}.bin"
: writingBaseName + ".bin";
newTrack.TrackFileOffset = separateTracksWriting ? 0 : currentOffset;
writingTracks.Add(newTrack);
currentOffset += (ulong)newTrack.TrackRawBytesPerSector *
(newTrack.TrackEndSector - newTrack.TrackStartSector + 1);
}
writingStreams = new Dictionary<uint, FileStream>();
if(separateTracksWriting)
foreach(Track track in writingTracks)
writingStreams.Add(track.TrackSequence,
new FileStream(track.TrackFile, FileMode.CreateNew, FileAccess.ReadWrite,
FileShare.None));
else
{
FileStream jointstream = new FileStream(writingBaseName + ".bin", FileMode.CreateNew,
FileAccess.ReadWrite, FileShare.None);
foreach(Track track in writingTracks) writingStreams.Add(track.TrackSequence, jointstream);
}
return true;
}
public bool Close()
{
if(!IsWriting)
{
ErrorMessage = "Image is not opened for writing";
return false;
}
if(separateTracksWriting)
foreach(FileStream writingStream in writingStreams.Values)
{
writingStream.Flush();
writingStream.Close();
}
else
{
writingStreams.First().Value.Flush();
writingStreams.First().Value.Close();
}
int currentSession = 0;
if(!string.IsNullOrWhiteSpace(discimage.Comment))
{
string[] commentLines = discimage.Comment.Split(new[] {'\n'}, StringSplitOptions.RemoveEmptyEntries);
foreach(string line in commentLines) descriptorStream.WriteLine("REM {0}", line);
}
descriptorStream.WriteLine("REM ORIGINAL MEDIA-TYPE {0}", MediaTypeToCdrwinType(imageInfo.MediaType));
if(!string.IsNullOrEmpty(discimage.Cdtextfile))
descriptorStream.WriteLine("CDTEXTFILE \"{0}\"", Path.GetFileName(discimage.Cdtextfile));
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) descriptorStream.WriteLine("REM SESSION {0}", ++currentSession);
if(separateTracksWriting)
descriptorStream.WriteLine("FILE \"{0}\" BINARY", Path.GetFileName(track.TrackFile));
(byte minute, byte second, byte frame) msf = LbaToMsf(track.TrackStartSector);
descriptorStream.WriteLine(" TRACK {0:D2} {1}", track.TrackSequence, GetTrackMode(track));
descriptorStream.WriteLine(" INDEX {0:D2} {1:D2}:{2:D2}:{3:D2}", 1, msf.minute, msf.second,
msf.frame);
}
descriptorStream.Flush();
descriptorStream.Close();
IsWriting = false;
return true;
}
public bool SetMetadata(ImageInfo metadata)
{
discimage.Barcode = metadata.MediaBarcode;
discimage.Comment = metadata.Comments;
discimage.Title = metadata.MediaTitle;
return true;
}
static ulong CdrWinMsftoLba(string msf)
{
ulong minute, second, frame, sectors;
string[] msfElements = msf.Split(':');
minute = ulong.Parse(msfElements[0]);
second = ulong.Parse(msfElements[1]);
frame = ulong.Parse(msfElements[2]);
ulong minute = ulong.Parse(msfElements[0]);
ulong second = ulong.Parse(msfElements[1]);
ulong frame = ulong.Parse(msfElements[2]);
sectors = minute * 60 * 75 + second * 75 + frame;
ulong sectors = minute * 60 * 75 + second * 75 + frame;
return sectors;
}
@@ -1891,6 +2334,105 @@ namespace DiscImageChef.DiscImages
}
}
static (byte minute, byte second, byte frame) LbaToMsf(ulong sector)
{
return ((byte)(sector / 75 / 60), (byte)(sector / 75 % 60), (byte)(sector % 75));
}
static string GetTrackMode(Track track)
{
switch(track.TrackType)
{
case TrackType.Audio when track.TrackRawBytesPerSector == 2448: return CDRWIN_TRACK_TYPE_CDG;
case TrackType.Audio when track.TrackRawBytesPerSector == 2352:
return CDRWIN_TRACK_TYPE_AUDIO;
case TrackType.Data:
return CDRWIN_TRACK_TYPE_MODE1;
case TrackType.CdMode1 when track.TrackRawBytesPerSector == 2352:
return CDRWIN_TRACK_TYPE_MODE1_RAW;
case TrackType.CdMode2Formless when track.TrackRawBytesPerSector != 2352:
return CDRWIN_TRACK_TYPE_MODE2_FORMLESS;
case TrackType.CdMode2Form1 when track.TrackRawBytesPerSector != 2352:
return CDRWIN_TRACK_TYPE_MODE2_FORM1;
case TrackType.CdMode2Form2 when track.TrackRawBytesPerSector != 2352:
return CDRWIN_TRACK_TYPE_MODE2_FORM2;
case TrackType.CdMode2Formless when track.TrackRawBytesPerSector == 2352:
case TrackType.CdMode2Form1 when track.TrackRawBytesPerSector == 2352:
case TrackType.CdMode2Form2 when track.TrackRawBytesPerSector == 2352:
return CDRWIN_TRACK_TYPE_MODE2_RAW;
default: return CDRWIN_TRACK_TYPE_MODE1;
}
}
static string MediaTypeToCdrwinType(MediaType type)
{
switch(type)
{
case MediaType.BDRXL:
case MediaType.BDR: return CDRWIN_DISK_TYPE_BDR;
case MediaType.BDREXL:
case MediaType.BDRE: return CDRWIN_DISK_TYPE_BDRE;
case MediaType.BDROM:
case MediaType.CBHD:
case MediaType.PS3BD:
case MediaType.PS4BD:
case MediaType.UDO:
case MediaType.UDO2:
case MediaType.UDO2_WORM: return CDRWIN_DISK_TYPE_BD;
case MediaType.CDV:
case MediaType.DDCD:
case MediaType.DDCDR:
case MediaType.DDCDRW:
case MediaType.CDPLUS:
case MediaType.CDR:
case MediaType.CDROM:
case MediaType.CDROMXA:
case MediaType.CD:
case MediaType.CDDA:
case MediaType.CDEG:
case MediaType.CDG:
case MediaType.CDI:
case MediaType.CDMIDI:
case MediaType.DTSCD:
case MediaType.JaguarCD:
case MediaType.MEGACD:
case MediaType.PD650:
case MediaType.PD650_WORM:
case MediaType.PS1CD:
case MediaType.PS2CD:
case MediaType.SuperCDROM2:
case MediaType.SVCD:
case MediaType.SVOD:
case MediaType.SATURNCD:
case MediaType.ThreeDO:
case MediaType.VCD:
case MediaType.VCDHD: return CDRWIN_DISK_TYPE_CD;
case MediaType.CDMRW: return CDRWIN_DISK_TYPE_CDMRW;
case MediaType.CDRW: return CDRWIN_DISK_TYPE_CDRW;
case MediaType.DVDPR: return CDRWIN_DISK_TYPE_DVDPR;
case MediaType.DVDPRDL: return CDRWIN_DISK_TYPE_DVDPRDL;
case MediaType.DVDPRW: return CDRWIN_DISK_TYPE_DVDPRW;
case MediaType.DVDPRWDL: return CDRWIN_DISK_TYPE_DVDPRWDL;
case MediaType.DVDR: return CDRWIN_DISK_TYPE_DVDR;
case MediaType.DVDRAM: return CDRWIN_DISK_TYPE_DVDRAM;
case MediaType.DVDRDL: return CDRWIN_DISK_TYPE_DVDRDL;
case MediaType.DVDDownload:
case MediaType.DVDROM:
case MediaType.UMD:
case MediaType.PS2DVD:
case MediaType.PS3DVD: return CDRWIN_DISK_TYPE_DVD;
case MediaType.DVDRW: return CDRWIN_DISK_TYPE_DVDRW;
case MediaType.DVDRWDL: return CDRWIN_DISK_TYPE_DVDRWDL;
case MediaType.HDDVDR: return CDRWIN_DISK_TYPE_HDDVDR;
case MediaType.HDDVDRAM: return CDRWIN_DISK_TYPE_HDDVDRAM;
case MediaType.HDDVDRDL: return CDRWIN_DISK_TYPE_HDDVDRDL;
case MediaType.HDDVDROM: return CDRWIN_DISK_TYPE_HDDVD;
case MediaType.HDDVDRW: return CDRWIN_DISK_TYPE_HDDVDRW;
case MediaType.HDDVDRWDL: return CDRWIN_DISK_TYPE_HDDVDRWDL;
default: return "";
}
}
struct CdrWinTrackFile
{
/// <summary>Track #</summary>