mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
Add writing support to CDRWin cuesheet disc image.
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user