mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
For DiscImageChef format, add support for tracks.
This commit is contained in:
@@ -113,6 +113,8 @@ namespace DiscImageChef.DiscImages
|
|||||||
byte shift;
|
byte shift;
|
||||||
byte[] structureBytes;
|
byte[] structureBytes;
|
||||||
IntPtr structurePointer;
|
IntPtr structurePointer;
|
||||||
|
Dictionary<byte, byte> trackFlags;
|
||||||
|
Dictionary<byte, string> trackIsrcs;
|
||||||
ulong[] userDataDdt;
|
ulong[] userDataDdt;
|
||||||
|
|
||||||
public DiscImageChef()
|
public DiscImageChef()
|
||||||
@@ -146,9 +148,9 @@ namespace DiscImageChef.DiscImages
|
|||||||
public string Name => "DiscImageChef format";
|
public string Name => "DiscImageChef format";
|
||||||
public Guid Id => new Guid("49360069-1784-4A2F-B723-0C844D610B0A");
|
public Guid Id => new Guid("49360069-1784-4A2F-B723-0C844D610B0A");
|
||||||
public string Format => "DiscImageChef";
|
public string Format => "DiscImageChef";
|
||||||
public List<Partition> Partitions { get; }
|
public List<Partition> Partitions { get; private set; }
|
||||||
public List<Track> Tracks { get; private set; }
|
public List<Track> Tracks { get; private set; }
|
||||||
public List<Session> Sessions { get; }
|
public List<Session> Sessions { get; private set; }
|
||||||
|
|
||||||
public bool Identify(IFilter imageFilter)
|
public bool Identify(IFilter imageFilter)
|
||||||
{
|
{
|
||||||
@@ -568,6 +570,59 @@ namespace DiscImageChef.DiscImages
|
|||||||
imageInfo.DriveFirmwareRevision);
|
imageInfo.DriveFirmwareRevision);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case BlockType.TracksBlock:
|
||||||
|
TracksHeader tracksHeader = new TracksHeader();
|
||||||
|
structureBytes = new byte[Marshal.SizeOf(tracksHeader)];
|
||||||
|
imageStream.Read(structureBytes, 0, structureBytes.Length);
|
||||||
|
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(tracksHeader));
|
||||||
|
Marshal.Copy(structureBytes, 0, structurePointer, Marshal.SizeOf(tracksHeader));
|
||||||
|
tracksHeader = (TracksHeader)Marshal.PtrToStructure(structurePointer, typeof(TracksHeader));
|
||||||
|
Marshal.FreeHGlobal(structurePointer);
|
||||||
|
if(tracksHeader.identifier != BlockType.TracksBlock)
|
||||||
|
{
|
||||||
|
DicConsole.DebugWriteLine("DiscImageChef format plugin",
|
||||||
|
"Incorrect identifier for tracks block at position {0}",
|
||||||
|
entry.offset);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Check CRC64
|
||||||
|
|
||||||
|
Tracks = new List<Track>();
|
||||||
|
trackFlags = new Dictionary<byte, byte>();
|
||||||
|
trackIsrcs = new Dictionary<byte, string>();
|
||||||
|
|
||||||
|
DicConsole.DebugWriteLine("DiscImageChef format plugin", "Found {0} tracks at position {0}",
|
||||||
|
tracksHeader.entries, entry.offset);
|
||||||
|
|
||||||
|
for(ushort i = 0; i < tracksHeader.entries; i++)
|
||||||
|
{
|
||||||
|
TrackEntry trackEntry = new TrackEntry();
|
||||||
|
structureBytes = new byte[Marshal.SizeOf(trackEntry)];
|
||||||
|
imageStream.Read(structureBytes, 0, structureBytes.Length);
|
||||||
|
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(trackEntry));
|
||||||
|
Marshal.Copy(structureBytes, 0, structurePointer, Marshal.SizeOf(trackEntry));
|
||||||
|
trackEntry = (TrackEntry)Marshal.PtrToStructure(structurePointer, typeof(TrackEntry));
|
||||||
|
Marshal.FreeHGlobal(structurePointer);
|
||||||
|
|
||||||
|
Tracks.Add(new Track
|
||||||
|
{
|
||||||
|
TrackSequence = trackEntry.sequence,
|
||||||
|
TrackType = trackEntry.type,
|
||||||
|
TrackStartSector = (ulong)trackEntry.start,
|
||||||
|
TrackEndSector = (ulong)trackEntry.end,
|
||||||
|
TrackPregap = (ulong)trackEntry.pregap,
|
||||||
|
TrackSession = trackEntry.session,
|
||||||
|
TrackFile = imageFilter.GetFilename(),
|
||||||
|
TrackFileType = "BINARY",
|
||||||
|
TrackFilter = imageFilter
|
||||||
|
});
|
||||||
|
|
||||||
|
trackFlags.Add(trackEntry.sequence, trackEntry.flags);
|
||||||
|
trackIsrcs.Add(trackEntry.sequence, trackEntry.isrc);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -596,6 +651,79 @@ namespace DiscImageChef.DiscImages
|
|||||||
currentCacheSize = 0;
|
currentCacheSize = 0;
|
||||||
if(!inMemoryDdt) ddtEntryCache = new Dictionary<ulong, ulong>();
|
if(!inMemoryDdt) ddtEntryCache = new Dictionary<ulong, ulong>();
|
||||||
|
|
||||||
|
if(imageInfo.XmlMediaType == XmlMediaType.OpticalDisc)
|
||||||
|
{
|
||||||
|
if(Tracks == null || Tracks.Count == 0)
|
||||||
|
{
|
||||||
|
Tracks = new List<Track>
|
||||||
|
{
|
||||||
|
new Track
|
||||||
|
{
|
||||||
|
Indexes = new Dictionary<int, ulong>(),
|
||||||
|
TrackBytesPerSector = (int)imageInfo.SectorSize,
|
||||||
|
TrackEndSector = imageInfo.Sectors - 1,
|
||||||
|
TrackFile = imageFilter.GetFilename(),
|
||||||
|
TrackFileType = "BINARY",
|
||||||
|
TrackFilter = imageFilter,
|
||||||
|
TrackRawBytesPerSector = (int)imageInfo.SectorSize,
|
||||||
|
TrackSession = 1,
|
||||||
|
TrackSequence = 1,
|
||||||
|
TrackType = TrackType.Data
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
trackFlags = new Dictionary<byte, byte> {{1, (byte)CdFlags.DataTrack}};
|
||||||
|
trackIsrcs = new Dictionary<byte, string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Sessions = new List<Session>();
|
||||||
|
for(int i = 1; i <= Tracks.Max(t => t.TrackSession); i++)
|
||||||
|
Sessions.Add(new Session
|
||||||
|
{
|
||||||
|
SessionSequence = (ushort)i,
|
||||||
|
StartTrack = Tracks.Where(t => t.TrackSession == i).Max(t => t.TrackSequence),
|
||||||
|
EndTrack = Tracks.Where(t => t.TrackSession == i).Min(t => t.TrackSequence),
|
||||||
|
StartSector = Tracks.Where(t => t.TrackSession == i).Min(t => t.TrackStartSector),
|
||||||
|
EndSector = Tracks.Where(t => t.TrackSession == i).Max(t => t.TrackEndSector)
|
||||||
|
});
|
||||||
|
|
||||||
|
ulong currentTrackOffset = 0;
|
||||||
|
Partitions = new List<Partition>();
|
||||||
|
foreach(Track track in Tracks.OrderBy(t => t.TrackStartSector))
|
||||||
|
{
|
||||||
|
Partitions.Add(new Partition
|
||||||
|
{
|
||||||
|
Sequence = track.TrackSequence,
|
||||||
|
Type = track.TrackType.ToString(),
|
||||||
|
Name = $"Track {track.TrackSequence}",
|
||||||
|
Offset = currentTrackOffset,
|
||||||
|
Start = track.TrackStartSector,
|
||||||
|
Size = (track.TrackEndSector - track.TrackStartSector + 1) *
|
||||||
|
(ulong)track.TrackBytesPerSector,
|
||||||
|
Length = track.TrackEndSector - track.TrackStartSector + 1,
|
||||||
|
Scheme = "Optical disc track"
|
||||||
|
});
|
||||||
|
currentTrackOffset += (track.TrackEndSector - track.TrackStartSector + 1) *
|
||||||
|
(ulong)track.TrackBytesPerSector;
|
||||||
|
}
|
||||||
|
|
||||||
|
Track[] tracks = Tracks.ToArray();
|
||||||
|
for(int i = 0; i < tracks.Length; i++)
|
||||||
|
{
|
||||||
|
byte[] sector = ReadSector(tracks[i].TrackStartSector);
|
||||||
|
tracks[i].TrackBytesPerSector = sector.Length;
|
||||||
|
tracks[i].TrackRawBytesPerSector = sector.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tracks = tracks.ToList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Tracks = null;
|
||||||
|
Sessions = null;
|
||||||
|
Partitions = null;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -686,12 +814,26 @@ namespace DiscImageChef.DiscImages
|
|||||||
|
|
||||||
public byte[] ReadSector(ulong sectorAddress, uint track)
|
public byte[] ReadSector(ulong sectorAddress, uint track)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
if(imageInfo.XmlMediaType != XmlMediaType.OpticalDisc)
|
||||||
|
throw new FeatureNotPresentImageException("Feature not present in image");
|
||||||
|
|
||||||
|
Track trk = Tracks.FirstOrDefault(t => t.TrackSequence == track);
|
||||||
|
if(trk.TrackSequence != track)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(track), "Track does not exist in disc image");
|
||||||
|
|
||||||
|
return ReadSector(trk.TrackStartSector + sectorAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] ReadSectorTag(ulong sectorAddress, uint track, SectorTagType tag)
|
public byte[] ReadSectorTag(ulong sectorAddress, uint track, SectorTagType tag)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
if(imageInfo.XmlMediaType != XmlMediaType.OpticalDisc)
|
||||||
|
throw new FeatureNotPresentImageException("Feature not present in image");
|
||||||
|
|
||||||
|
Track trk = Tracks.FirstOrDefault(t => t.TrackSequence == track);
|
||||||
|
if(trk.TrackSequence != track)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(track), "Track does not exist in disc image");
|
||||||
|
|
||||||
|
return ReadSectorTag(trk.TrackStartSector + sectorAddress, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] ReadSectors(ulong sectorAddress, uint length)
|
public byte[] ReadSectors(ulong sectorAddress, uint length)
|
||||||
@@ -721,12 +863,34 @@ namespace DiscImageChef.DiscImages
|
|||||||
|
|
||||||
public byte[] ReadSectors(ulong sectorAddress, uint length, uint track)
|
public byte[] ReadSectors(ulong sectorAddress, uint length, uint track)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
if(imageInfo.XmlMediaType != XmlMediaType.OpticalDisc)
|
||||||
|
throw new FeatureNotPresentImageException("Feature not present in image");
|
||||||
|
|
||||||
|
Track trk = Tracks.FirstOrDefault(t => t.TrackSequence == track);
|
||||||
|
if(trk.TrackSequence != track)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(track), "Track does not exist in disc image");
|
||||||
|
|
||||||
|
if(trk.TrackStartSector + sectorAddress + length > trk.TrackEndSector + 1)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(length),
|
||||||
|
$"Requested more sectors ({length + sectorAddress}) than present in track ({trk.TrackEndSector - trk.TrackStartSector + 1}), won't cross tracks");
|
||||||
|
|
||||||
|
return ReadSectors(trk.TrackStartSector + sectorAddress, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag)
|
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
if(imageInfo.XmlMediaType != XmlMediaType.OpticalDisc)
|
||||||
|
throw new FeatureNotPresentImageException("Feature not present in image");
|
||||||
|
|
||||||
|
Track trk = Tracks.FirstOrDefault(t => t.TrackSequence == track);
|
||||||
|
if(trk.TrackSequence != track)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(track), "Track does not exist in disc image");
|
||||||
|
|
||||||
|
if(trk.TrackStartSector + sectorAddress + length > trk.TrackEndSector + 1)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(length),
|
||||||
|
$"Requested more sectors ({length + sectorAddress}) than present in track ({trk.TrackEndSector - trk.TrackStartSector + 1}), won't cross tracks");
|
||||||
|
|
||||||
|
return ReadSectorsTag(trk.TrackStartSector + sectorAddress, length, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] ReadSectorLong(ulong sectorAddress)
|
public byte[] ReadSectorLong(ulong sectorAddress)
|
||||||
@@ -736,7 +900,14 @@ namespace DiscImageChef.DiscImages
|
|||||||
|
|
||||||
public byte[] ReadSectorLong(ulong sectorAddress, uint track)
|
public byte[] ReadSectorLong(ulong sectorAddress, uint track)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
if(imageInfo.XmlMediaType != XmlMediaType.OpticalDisc)
|
||||||
|
throw new FeatureNotPresentImageException("Feature not present in image");
|
||||||
|
|
||||||
|
Track trk = Tracks.FirstOrDefault(t => t.TrackSequence == track);
|
||||||
|
if(trk.TrackSequence != track)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(track), "Track does not exist in disc image");
|
||||||
|
|
||||||
|
return ReadSectorLong(trk.TrackStartSector + sectorAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] ReadSectorsLong(ulong sectorAddress, uint length)
|
public byte[] ReadSectorsLong(ulong sectorAddress, uint length)
|
||||||
@@ -746,7 +917,18 @@ namespace DiscImageChef.DiscImages
|
|||||||
|
|
||||||
public byte[] ReadSectorsLong(ulong sectorAddress, uint length, uint track)
|
public byte[] ReadSectorsLong(ulong sectorAddress, uint length, uint track)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
if(imageInfo.XmlMediaType != XmlMediaType.OpticalDisc)
|
||||||
|
throw new FeatureNotPresentImageException("Feature not present in image");
|
||||||
|
|
||||||
|
Track trk = Tracks.FirstOrDefault(t => t.TrackSequence == track);
|
||||||
|
if(trk.TrackSequence != track)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(track), "Track does not exist in disc image");
|
||||||
|
|
||||||
|
if(trk.TrackStartSector + sectorAddress + length > trk.TrackEndSector + 1)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(length),
|
||||||
|
$"Requested more sectors ({length + sectorAddress}) than present in track ({trk.TrackEndSector - trk.TrackStartSector + 1}), won't cross tracks");
|
||||||
|
|
||||||
|
return ReadSectorsLong(trk.TrackStartSector + sectorAddress, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Track> GetSessionTracks(Session session)
|
public List<Track> GetSessionTracks(Session session)
|
||||||
@@ -766,7 +948,14 @@ namespace DiscImageChef.DiscImages
|
|||||||
|
|
||||||
public bool? VerifySector(ulong sectorAddress, uint track)
|
public bool? VerifySector(ulong sectorAddress, uint track)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
if(imageInfo.XmlMediaType != XmlMediaType.OpticalDisc)
|
||||||
|
throw new FeatureNotPresentImageException("Feature not present in image");
|
||||||
|
|
||||||
|
Track trk = Tracks.FirstOrDefault(t => t.TrackSequence == track);
|
||||||
|
if(trk.TrackSequence != track)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(track), "Track does not exist in disc image");
|
||||||
|
|
||||||
|
return VerifySector(trk.TrackStartSector + sectorAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
|
public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
|
||||||
@@ -778,7 +967,18 @@ namespace DiscImageChef.DiscImages
|
|||||||
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)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
if(imageInfo.XmlMediaType != XmlMediaType.OpticalDisc)
|
||||||
|
throw new FeatureNotPresentImageException("Feature not present in image");
|
||||||
|
|
||||||
|
Track trk = Tracks.FirstOrDefault(t => t.TrackSequence == track);
|
||||||
|
if(trk.TrackSequence != track)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(track), "Track does not exist in disc image");
|
||||||
|
|
||||||
|
if(trk.TrackStartSector + sectorAddress + length > trk.TrackEndSector + 1)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(length),
|
||||||
|
$"Requested more sectors ({length + sectorAddress}) than present in track ({trk.TrackEndSector - trk.TrackStartSector + 1}), won't cross tracks");
|
||||||
|
|
||||||
|
return VerifySectors(trk.TrackStartSector + sectorAddress, length, out failingLbas, out unknownLbas);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool? VerifyMediaImage()
|
public bool? VerifyMediaImage()
|
||||||
@@ -837,7 +1037,13 @@ namespace DiscImageChef.DiscImages
|
|||||||
DicConsole.DebugWriteLine("DiscImageChef format plugin", "Got a shift of {0} for {1} sectors per block",
|
DicConsole.DebugWriteLine("DiscImageChef format plugin", "Got a shift of {0} for {1} sectors per block",
|
||||||
shift, oldSectorsPerBlock);
|
shift, oldSectorsPerBlock);
|
||||||
|
|
||||||
imageInfo = new ImageInfo {MediaType = mediaType, SectorSize = sectorSize, Sectors = sectors};
|
imageInfo = new ImageInfo
|
||||||
|
{
|
||||||
|
MediaType = mediaType,
|
||||||
|
SectorSize = sectorSize,
|
||||||
|
Sectors = sectors,
|
||||||
|
XmlMediaType = GetXmlMediaType(mediaType)
|
||||||
|
};
|
||||||
|
|
||||||
try { imageStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); }
|
try { imageStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); }
|
||||||
catch(IOException e)
|
catch(IOException e)
|
||||||
@@ -906,6 +1112,8 @@ namespace DiscImageChef.DiscImages
|
|||||||
mediaTags = new Dictionary<MediaTagType, byte[]>();
|
mediaTags = new Dictionary<MediaTagType, byte[]>();
|
||||||
checksumProvider = SHA256.Create();
|
checksumProvider = SHA256.Create();
|
||||||
deduplicationTable = new Dictionary<byte[], ulong>();
|
deduplicationTable = new Dictionary<byte[], ulong>();
|
||||||
|
trackIsrcs = new Dictionary<byte, string>();
|
||||||
|
trackFlags = new Dictionary<byte, byte>();
|
||||||
|
|
||||||
IsWriting = true;
|
IsWriting = true;
|
||||||
ErrorMessage = null;
|
ErrorMessage = null;
|
||||||
@@ -970,7 +1178,7 @@ namespace DiscImageChef.DiscImages
|
|||||||
dataType = DataType.UserData,
|
dataType = DataType.UserData,
|
||||||
offset = (ulong)imageStream.Position
|
offset = (ulong)imageStream.Position
|
||||||
});
|
});
|
||||||
|
|
||||||
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(currentBlockHeader));
|
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(currentBlockHeader));
|
||||||
structureBytes = new byte[Marshal.SizeOf(currentBlockHeader)];
|
structureBytes = new byte[Marshal.SizeOf(currentBlockHeader)];
|
||||||
Marshal.StructureToPtr(currentBlockHeader, structurePointer, true);
|
Marshal.StructureToPtr(currentBlockHeader, structurePointer, true);
|
||||||
@@ -1055,6 +1263,12 @@ namespace DiscImageChef.DiscImages
|
|||||||
|
|
||||||
public bool SetTracks(List<Track> tracks)
|
public bool SetTracks(List<Track> tracks)
|
||||||
{
|
{
|
||||||
|
if(imageInfo.XmlMediaType != XmlMediaType.OpticalDisc)
|
||||||
|
{
|
||||||
|
ErrorMessage = "Unsupported feature";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if(!IsWriting)
|
if(!IsWriting)
|
||||||
{
|
{
|
||||||
ErrorMessage = "Tried to write on a non-writable image";
|
ErrorMessage = "Tried to write on a non-writable image";
|
||||||
@@ -1245,6 +1459,72 @@ namespace DiscImageChef.DiscImages
|
|||||||
index.Add(idxEntry);
|
index.Add(idxEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(imageInfo.XmlMediaType == XmlMediaType.OpticalDisc && Tracks != null && Tracks.Count > 0)
|
||||||
|
{
|
||||||
|
List<TrackEntry> trackEntries = new List<TrackEntry>();
|
||||||
|
foreach(Track track in Tracks)
|
||||||
|
{
|
||||||
|
trackFlags.TryGetValue((byte)track.TrackSequence, out byte flags);
|
||||||
|
trackIsrcs.TryGetValue((byte)track.TrackSequence, out string isrc);
|
||||||
|
|
||||||
|
if((flags & (int)CdFlags.DataTrack) == 0 && track.TrackType != TrackType.Audio)
|
||||||
|
flags += (byte)CdFlags.DataTrack;
|
||||||
|
|
||||||
|
trackEntries.Add(new TrackEntry
|
||||||
|
{
|
||||||
|
sequence = (byte)track.TrackSequence,
|
||||||
|
type = track.TrackType,
|
||||||
|
start = (long)track.TrackStartSector,
|
||||||
|
end = (long)track.TrackEndSector,
|
||||||
|
pregap = (long)track.TrackPregap,
|
||||||
|
session = (byte)track.TrackSession,
|
||||||
|
isrc = isrc,
|
||||||
|
flags = flags
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(trackEntries.Count > 0)
|
||||||
|
{
|
||||||
|
blockStream = new MemoryStream();
|
||||||
|
|
||||||
|
foreach(TrackEntry entry in trackEntries)
|
||||||
|
{
|
||||||
|
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(entry));
|
||||||
|
structureBytes = new byte[Marshal.SizeOf(entry)];
|
||||||
|
Marshal.StructureToPtr(entry, structurePointer, true);
|
||||||
|
Marshal.Copy(structurePointer, structureBytes, 0, structureBytes.Length);
|
||||||
|
Marshal.FreeHGlobal(structurePointer);
|
||||||
|
blockStream.Write(structureBytes, 0, structureBytes.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
Crc64Context.Data(blockStream.ToArray(), out byte[] trksCrc);
|
||||||
|
TracksHeader trkHeader = new TracksHeader
|
||||||
|
{
|
||||||
|
identifier = BlockType.TracksBlock,
|
||||||
|
entries = (ushort)trackEntries.Count,
|
||||||
|
crc64 = BitConverter.ToUInt64(trksCrc, 0)
|
||||||
|
};
|
||||||
|
|
||||||
|
DicConsole.DebugWriteLine("DiscImageChef format plugin", "Writing tracks to position {0}",
|
||||||
|
imageStream.Position);
|
||||||
|
|
||||||
|
index.Add(new IndexEntry
|
||||||
|
{
|
||||||
|
blockType = BlockType.TracksBlock,
|
||||||
|
dataType = DataType.NoData,
|
||||||
|
offset = (ulong)imageStream.Position
|
||||||
|
});
|
||||||
|
|
||||||
|
structurePointer = Marshal.AllocHGlobal(Marshal.SizeOf(trkHeader));
|
||||||
|
structureBytes = new byte[Marshal.SizeOf(trkHeader)];
|
||||||
|
Marshal.StructureToPtr(trkHeader, structurePointer, true);
|
||||||
|
Marshal.Copy(structurePointer, structureBytes, 0, structureBytes.Length);
|
||||||
|
Marshal.FreeHGlobal(structurePointer);
|
||||||
|
imageStream.Write(structureBytes, 0, structureBytes.Length);
|
||||||
|
imageStream.Write(blockStream.ToArray(), 0, (int)blockStream.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MetadataBlock metadataBlock = new MetadataBlock();
|
MetadataBlock metadataBlock = new MetadataBlock();
|
||||||
blockStream = new MemoryStream();
|
blockStream = new MemoryStream();
|
||||||
blockStream.Write(new byte[Marshal.SizeOf(metadataBlock)], 0, Marshal.SizeOf(metadataBlock));
|
blockStream.Write(new byte[Marshal.SizeOf(metadataBlock)], 0, Marshal.SizeOf(metadataBlock));
|
||||||
@@ -1489,18 +1769,85 @@ namespace DiscImageChef.DiscImages
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Implement
|
|
||||||
public bool WriteSectorTag(byte[] data, ulong sectorAddress, SectorTagType tag)
|
public bool WriteSectorTag(byte[] data, ulong sectorAddress, SectorTagType tag)
|
||||||
{
|
{
|
||||||
ErrorMessage = "Writing sectors with tags is not yet implemented.";
|
if(!IsWriting)
|
||||||
return false;
|
{
|
||||||
|
ErrorMessage = "Tried to write on a non-writable image";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sectorAddress >= imageInfo.Sectors)
|
||||||
|
{
|
||||||
|
ErrorMessage = "Tried to write past image size";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Track track = new Track();
|
||||||
|
switch(tag)
|
||||||
|
{
|
||||||
|
case SectorTagType.CdTrackFlags:
|
||||||
|
case SectorTagType.CdTrackIsrc:
|
||||||
|
if(imageInfo.XmlMediaType != XmlMediaType.OpticalDisc)
|
||||||
|
{
|
||||||
|
ErrorMessage = "Incorrect tag for disk type";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
track = Tracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
|
||||||
|
sectorAddress <= trk.TrackEndSector);
|
||||||
|
if(track.TrackSequence == 0)
|
||||||
|
{
|
||||||
|
ErrorMessage = $"Can't found track containing {sectorAddress}";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(tag)
|
||||||
|
{
|
||||||
|
case SectorTagType.CdTrackFlags:
|
||||||
|
{
|
||||||
|
if(data.Length != 1)
|
||||||
|
{
|
||||||
|
ErrorMessage = "Incorrect data size for track flags";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
trackFlags.Add((byte)track.TrackSequence, data[0]);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case SectorTagType.CdTrackIsrc:
|
||||||
|
{
|
||||||
|
if(data != null) trackIsrcs.Add((byte)track.TrackSequence, Encoding.UTF8.GetString(data));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
default: throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Implement
|
|
||||||
public bool WriteSectorsTag(byte[] data, ulong sectorAddress, uint length, SectorTagType tag)
|
public bool WriteSectorsTag(byte[] data, ulong sectorAddress, uint length, SectorTagType tag)
|
||||||
{
|
{
|
||||||
ErrorMessage = "Writing sectors with tags is not yet implemented.";
|
if(!IsWriting)
|
||||||
return false;
|
{
|
||||||
|
ErrorMessage = "Tried to write on a non-writable image";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sectorAddress + length > imageInfo.Sectors)
|
||||||
|
{
|
||||||
|
ErrorMessage = "Tried to write past image size";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(tag)
|
||||||
|
{
|
||||||
|
case SectorTagType.CdTrackFlags:
|
||||||
|
case SectorTagType.CdTrackIsrc: return WriteSectorTag(data, sectorAddress, tag);
|
||||||
|
default: throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static XmlMediaType GetXmlMediaType(MediaType type)
|
static XmlMediaType GetXmlMediaType(MediaType type)
|
||||||
@@ -1860,7 +2207,8 @@ namespace DiscImageChef.DiscImages
|
|||||||
DeDuplicationTable = 0x48544444,
|
DeDuplicationTable = 0x48544444,
|
||||||
Index = 0x48584449,
|
Index = 0x48584449,
|
||||||
GeometryBlock = 0x4D4F4547,
|
GeometryBlock = 0x4D4F4547,
|
||||||
MetadataBlock = 0x5444545D
|
MetadataBlock = 0x5444545D,
|
||||||
|
TracksBlock = 0x534B5254
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Header, at start of file</summary>
|
/// <summary>Header, at start of file</summary>
|
||||||
@@ -1975,6 +2323,7 @@ namespace DiscImageChef.DiscImages
|
|||||||
public uint sectorsPerTrack;
|
public uint sectorsPerTrack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Metadata block, contains metadata</summary>
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
struct MetadataBlock
|
struct MetadataBlock
|
||||||
{
|
{
|
||||||
@@ -2035,5 +2384,30 @@ namespace DiscImageChef.DiscImages
|
|||||||
/// <summary>Length in bytes of the null-terminated UTF-16LE creator string</summary>
|
/// <summary>Length in bytes of the null-terminated UTF-16LE creator string</summary>
|
||||||
public uint driveFirmwareRevisionLength;
|
public uint driveFirmwareRevisionLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
struct TracksHeader
|
||||||
|
{
|
||||||
|
/// <summary>Identifier, <see cref="BlockType.TracksBlock" /></summary>
|
||||||
|
public BlockType identifier;
|
||||||
|
/// <summary>How many entries follow this header</summary>
|
||||||
|
public ushort entries;
|
||||||
|
/// <summary>CRC64-ECMA of the block</summary>
|
||||||
|
public ulong crc64;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
|
||||||
|
struct TrackEntry
|
||||||
|
{
|
||||||
|
public byte sequence;
|
||||||
|
public TrackType type;
|
||||||
|
public long start;
|
||||||
|
public long end;
|
||||||
|
public long pregap;
|
||||||
|
public byte session;
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 13)]
|
||||||
|
public string isrc;
|
||||||
|
public byte flags;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -37,20 +37,20 @@ namespace DiscImageChef.DiscImages
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Track (as partitioning element) types.
|
/// Track (as partitioning element) types.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum TrackType
|
public enum TrackType : byte
|
||||||
{
|
{
|
||||||
/// <summary>Audio track</summary>
|
/// <summary>Audio track</summary>
|
||||||
Audio,
|
Audio = 0,
|
||||||
/// <summary>Data track (not any of the below defined ones)</summary>
|
/// <summary>Data track (not any of the below defined ones)</summary>
|
||||||
Data,
|
Data = 1,
|
||||||
/// <summary>Data track, compact disc mode 1</summary>
|
/// <summary>Data track, compact disc mode 1</summary>
|
||||||
CdMode1,
|
CdMode1 = 2,
|
||||||
/// <summary>Data track, compact disc mode 2, formless</summary>
|
/// <summary>Data track, compact disc mode 2, formless</summary>
|
||||||
CdMode2Formless,
|
CdMode2Formless = 3,
|
||||||
/// <summary>Data track, compact disc mode 2, form 1</summary>
|
/// <summary>Data track, compact disc mode 2, form 1</summary>
|
||||||
CdMode2Form1,
|
CdMode2Form1 = 4,
|
||||||
/// <summary>Data track, compact disc mode 2, form 2</summary>
|
/// <summary>Data track, compact disc mode 2, form 2</summary>
|
||||||
CdMode2Form2
|
CdMode2Form2 = 5
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user