public bool WriteSectorsTag(byte[] data, ulong sectorAddress, uint length, SectorTagType tag) { if (!IsWriting) { ErrorMessage = "Tried to write on a non-writable image"; return(false); } CommonTypes.Structs.Track track = _writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector && sectorAddress <= trk.TrackEndSector); if (track is null) { ErrorMessage = $"Can't found track containing {sectorAddress}"; return(false); } switch (tag) { case SectorTagType.CdTrackFlags: return(WriteSectorTag(data, sectorAddress, tag)); case SectorTagType.CdSectorSubchannel: { if (track.TrackSubchannelType == 0) { ErrorMessage = $"Trying to write subchannel to track {track.TrackSequence}, that does not have subchannel"; return(false); } if (data.Length % 96 != 0) { ErrorMessage = "Incorrect data size for subchannel"; return(false); } for (uint i = 0; i < length; i++) { _imageStream. Seek((long)(track.TrackFileOffset + (((i + sectorAddress) - track.TrackStartSector) * (ulong)(track.TrackRawBytesPerSector + 96))) + track.TrackRawBytesPerSector, SeekOrigin.Begin); _imageStream.Write(data, (int)(i * 96), 96); } return(true); } default: ErrorMessage = $"Unsupported tag type {tag}"; return(false); } }
public bool WriteSectorsLong(byte[] data, ulong sectorAddress, uint length) { if (!IsWriting) { ErrorMessage = "Tried to write on a non-writable image"; return(false); } CommonTypes.Structs.Track track = _writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector && sectorAddress <= trk.TrackEndSector); if (track is null) { ErrorMessage = $"Can't found track 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); } uint subchannelSize = (uint)(track.TrackSubchannelType != TrackSubchannelType.None ? 96 : 0); for (uint i = 0; i < length; i++) { _imageStream. Seek((long)(track.TrackFileOffset + (((i + sectorAddress) - track.TrackStartSector) * (ulong)(track.TrackRawBytesPerSector + subchannelSize))), SeekOrigin.Begin); _imageStream.Write(data, (int)(i * track.TrackRawBytesPerSector), track.TrackRawBytesPerSector); } return(true); }
public bool WriteSector(byte[] data, ulong sectorAddress) { if (!IsWriting) { ErrorMessage = "Tried to write on a non-writable image"; return(false); } CommonTypes.Structs.Track track = _writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector && sectorAddress <= trk.TrackEndSector); if (track is null) { ErrorMessage = $"Can't found track 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); } _imageStream. Seek((long)(track.TrackFileOffset + ((sectorAddress - track.TrackStartSector) * (ulong)track.TrackRawBytesPerSector)), SeekOrigin.Begin); _imageStream.Write(data, 0, data.Length); return(true); }
public bool Close() { if (!IsWriting) { ErrorMessage = "Image is not opened for writing"; return(false); } byte sessions = byte.MinValue; foreach (CommonTypes.Structs.Track t in _writingTracks.Where(t => t.TrackSession > byte.MinValue)) { sessions = (byte)t.TrackSession; } var header = new Header { signature = _alcoholSignature, version = new byte[] { 1, 5 }, type = MediaTypeToMediumType(_imageInfo.MediaType), sessions = sessions, structuresOffset = (uint)(_pfi == null ? 0 : 96), sessionOffset = (uint)(_pfi == null ? 96 : 4196), unknown1 = new ushort[2], unknown2 = new uint[2], unknown3 = new uint[6], unknown4 = new uint[3] }; // Alcohol sets this always, Daemon Tool expects this header.unknown1[0] = 2; _alcSessions = new Dictionary <int, Session>(); _alcTracks = new Dictionary <int, Track>(); _alcToc = new Dictionary <int, Dictionary <int, Track> >(); _writingTracks = _writingTracks.OrderBy(t => t.TrackSession).ThenBy(t => t.TrackSequence).ToList(); _alcTrackExtras = new Dictionary <int, TrackExtra>(); long currentTrackOffset = header.sessionOffset + (Marshal.SizeOf <Session>() * sessions); byte[] tmpToc = null; if (_fullToc != null) { byte[] fullTocSize = BigEndianBitConverter.GetBytes((short)_fullToc.Length); tmpToc = new byte[_fullToc.Length + 2]; Array.Copy(_fullToc, 0, tmpToc, 2, _fullToc.Length); tmpToc[0] = fullTocSize[0]; tmpToc[1] = fullTocSize[1]; } FullTOC.CDFullTOC?decodedToc = FullTOC.Decode(tmpToc); long currentExtraOffset = currentTrackOffset; int extraCount = 0; for (int i = 1; i <= sessions; i++) { if (decodedToc.HasValue) { extraCount += decodedToc.Value.TrackDescriptors.Count(t => t.SessionNumber == i); currentExtraOffset += Marshal.SizeOf <Track>() * decodedToc.Value.TrackDescriptors.Count(t => t.SessionNumber == i); } else { currentExtraOffset += Marshal.SizeOf <Track>() * 3; extraCount += 3; currentExtraOffset += Marshal.SizeOf <Track>() * _writingTracks.Count(t => t.TrackSession == i); extraCount += _writingTracks.Count(t => t.TrackSession == i); if (i < sessions) { currentExtraOffset += Marshal.SizeOf <Track>() * 2; extraCount += 2; } } } long footerOffset = currentExtraOffset + (Marshal.SizeOf <TrackExtra>() * extraCount); if (_bca != null) { header.bcaOffset = (uint)footerOffset; footerOffset += _bca.Length; } if (_isDvd) { _alcSessions.Add(1, new Session { sessionEnd = (int)((_writingTracks[0].TrackEndSector - _writingTracks[0].TrackStartSector) + 1), sessionSequence = 1, allBlocks = 1, nonTrackBlocks = 3, firstTrack = 1, lastTrack = 1, trackOffset = 4220 }); footerOffset = 4300; if (_bca != null) { footerOffset += _bca.Length; } _alcTracks.Add(1, new Track { mode = TrackMode.DVD, adrCtl = 20, point = 1, extraOffset = (uint)((_writingTracks[0].TrackEndSector - _writingTracks[0].TrackStartSector) + 1), sectorSize = 2048, files = 1, footerOffset = (uint)footerOffset, unknown = new byte[18], unknown2 = new byte[24] }); _alcToc.Add(1, _alcTracks); } else { for (int i = 1; i <= sessions; i++) { CommonTypes.Structs.Track firstTrack = _writingTracks.First(t => t.TrackSession == i); CommonTypes.Structs.Track lastTrack = _writingTracks.Last(t => t.TrackSession == i); _alcSessions.Add(i, new Session { sessionStart = (int)firstTrack.TrackStartSector - 150, sessionEnd = (int)lastTrack.TrackEndSector + 1, sessionSequence = (ushort)i, allBlocks = (byte)(decodedToc?.TrackDescriptors.Count(t => t.SessionNumber == i) ?? _writingTracks.Count(t => t.TrackSession == i) + 3), nonTrackBlocks = (byte)(decodedToc?.TrackDescriptors.Count(t => t.SessionNumber == i && t.POINT >= 0xA0 && t.POINT <= 0xAF) ?? 3), firstTrack = (ushort)firstTrack.TrackSequence, lastTrack = (ushort)lastTrack.TrackSequence, trackOffset = (uint)currentTrackOffset }); Dictionary <int, Track> thisSessionTracks = new Dictionary <int, Track>(); _trackFlags.TryGetValue((byte)firstTrack.TrackSequence, out byte firstTrackControl); _trackFlags.TryGetValue((byte)lastTrack.TrackSequence, out byte lastTrackControl); if (firstTrackControl == 0 && firstTrack.TrackType != TrackType.Audio) { firstTrackControl = (byte)CdFlags.DataTrack; } if (lastTrackControl == 0 && lastTrack.TrackType != TrackType.Audio) { lastTrackControl = (byte)CdFlags.DataTrack; } (byte minute, byte second, byte frame)leadinPmsf = LbaToMsf(lastTrack.TrackEndSector + 1); if (decodedToc?.TrackDescriptors.Any(t => t.SessionNumber == i && t.POINT >= 0xA0 && t.POINT <= 0xAF) == true) { foreach (FullTOC.TrackDataDescriptor tocTrk in decodedToc.Value.TrackDescriptors.Where(t => t.SessionNumber == i && t.POINT >= 0xA0 && t.POINT <= 0xAF)) { thisSessionTracks.Add(tocTrk.POINT, new Track { adrCtl = (byte)((tocTrk.ADR << 4) + tocTrk.CONTROL), tno = tocTrk.TNO, point = tocTrk.POINT, min = tocTrk.Min, sec = tocTrk.Sec, frame = tocTrk.Frame, zero = tocTrk.Zero, pmin = tocTrk.PMIN, psec = tocTrk.PSEC, pframe = tocTrk.PFRAME, mode = TrackMode.NoData, unknown = new byte[18], unknown2 = new byte[24], extraOffset = (uint)currentExtraOffset }); currentTrackOffset += Marshal.SizeOf <Track>(); currentExtraOffset += Marshal.SizeOf <TrackExtra>(); } } else { thisSessionTracks.Add(0xA0, new Track { adrCtl = (byte)((1 << 4) + firstTrackControl), pmin = (byte)firstTrack.TrackSequence, mode = TrackMode.NoData, point = 0xA0, unknown = new byte[18], unknown2 = new byte[24], psec = (byte)(_imageInfo.MediaType == MediaType.CDI ? 0x10 : _writingTracks.Any(t => t.TrackType == TrackType.CdMode2Form1 || t.TrackType == TrackType.CdMode2Form2 || t.TrackType == TrackType.CdMode2Formless) ? 0x20 : 0), extraOffset = (uint)currentExtraOffset }); thisSessionTracks.Add(0xA1, new Track { adrCtl = (byte)((1 << 4) + lastTrackControl), pmin = (byte)lastTrack.TrackSequence, mode = TrackMode.NoData, point = 0xA1, unknown = new byte[18], unknown2 = new byte[24], extraOffset = (uint)currentExtraOffset }); thisSessionTracks.Add(0xA2, new Track { adrCtl = (byte)((1 << 4) + firstTrackControl), zero = 0, pmin = leadinPmsf.minute, psec = leadinPmsf.second, pframe = leadinPmsf.frame, mode = TrackMode.NoData, point = 0xA2, unknown = new byte[18], unknown2 = new byte[24], extraOffset = (uint)currentExtraOffset }); currentExtraOffset += Marshal.SizeOf <TrackExtra>() * 3; currentTrackOffset += Marshal.SizeOf <Track>() * 3; } foreach (CommonTypes.Structs.Track track in _writingTracks.Where(t => t.TrackSession == i). OrderBy(t => t.TrackSequence)) { var alcTrk = new Track(); if (decodedToc?.TrackDescriptors.Any(t => t.SessionNumber == i && t.POINT == track.TrackSequence) == true) { FullTOC.TrackDataDescriptor tocTrk = decodedToc.Value.TrackDescriptors.First(t => t.SessionNumber == i && t.POINT == track.TrackSequence); alcTrk.adrCtl = (byte)((tocTrk.ADR << 4) + tocTrk.CONTROL); alcTrk.tno = tocTrk.TNO; alcTrk.point = tocTrk.POINT; alcTrk.min = tocTrk.Min; alcTrk.sec = tocTrk.Sec; alcTrk.frame = tocTrk.Frame; alcTrk.zero = tocTrk.Zero; alcTrk.pmin = tocTrk.PMIN; alcTrk.psec = tocTrk.PSEC; alcTrk.pframe = tocTrk.PFRAME; } else { (byte minute, byte second, byte frame)msf = LbaToMsf(track.TrackStartSector); _trackFlags.TryGetValue((byte)track.TrackSequence, out byte trackControl); if (trackControl == 0 && track.TrackType != TrackType.Audio) { trackControl = (byte)CdFlags.DataTrack; } alcTrk.adrCtl = (byte)((1 << 4) + trackControl); alcTrk.point = (byte)track.TrackSequence; alcTrk.zero = 0; alcTrk.pmin = msf.minute; alcTrk.psec = msf.second; alcTrk.pframe = msf.frame; } alcTrk.mode = TrackTypeToTrackMode(track.TrackType); alcTrk.subMode = track.TrackSubchannelType != TrackSubchannelType.None ? SubchannelMode.Interleaved : SubchannelMode.None; alcTrk.sectorSize = (ushort)(track.TrackRawBytesPerSector + (track.TrackSubchannelType != TrackSubchannelType.None ? 96 : 0)); alcTrk.startLba = (uint)(track.TrackStartSector + track.TrackPregap); alcTrk.startOffset = track.TrackFileOffset + (alcTrk.sectorSize * track.TrackPregap); alcTrk.files = 1; alcTrk.extraOffset = (uint)currentExtraOffset; alcTrk.footerOffset = (uint)footerOffset; if (track.TrackSequence == firstTrack.TrackSequence && track.TrackSequence > 1) { alcTrk.startLba -= 150; alcTrk.startOffset -= (ulong)(alcTrk.sectorSize * 150); } // Alcohol seems to set that for all CD tracks // Daemon Tools expect it to be like this alcTrk.unknown = new byte[] { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; alcTrk.unknown2 = new byte[24]; thisSessionTracks.Add((int)track.TrackSequence, alcTrk); currentTrackOffset += Marshal.SizeOf <Track>(); currentExtraOffset += Marshal.SizeOf <TrackExtra>(); var trkExtra = new TrackExtra { sectors = (uint)((track.TrackEndSector - track.TrackStartSector) + 1) }; if (track.TrackSequence == firstTrack.TrackSequence) { trkExtra.pregap = 150; } // When track mode changes there's a mandatory gap, Alcohol needs it else if (thisSessionTracks.TryGetValue((int)(track.TrackSequence - 1), out Track previousTrack) && _alcTrackExtras.TryGetValue((int)(track.TrackSequence - 1), out TrackExtra previousExtra) && previousTrack.mode != alcTrk.mode) { previousExtra.sectors -= 150; trkExtra.pregap = 150; _alcTrackExtras.Remove((int)(track.TrackSequence - 1)); _alcTrackExtras.Add((int)(track.TrackSequence - 1), previousExtra); } else { trkExtra.pregap = 0; } _alcTrackExtras.Add((int)track.TrackSequence, trkExtra); } if (decodedToc?.TrackDescriptors.Any(t => t.SessionNumber == i && t.POINT >= 0xB0) == true) { foreach (FullTOC.TrackDataDescriptor tocTrk in decodedToc.Value.TrackDescriptors.Where(t => t.SessionNumber == i && t.POINT >= 0xB0)) { thisSessionTracks.Add(tocTrk.POINT, new Track { adrCtl = (byte)((tocTrk.ADR << 4) + tocTrk.CONTROL), tno = tocTrk.TNO, point = tocTrk.POINT, min = tocTrk.Min, sec = tocTrk.Sec, frame = tocTrk.Frame, zero = tocTrk.Zero, pmin = tocTrk.PMIN, psec = tocTrk.PSEC, pframe = tocTrk.PFRAME, mode = TrackMode.NoData, unknown = new byte[18], unknown2 = new byte[24], extraOffset = (uint)currentExtraOffset }); currentExtraOffset += Marshal.SizeOf <TrackExtra>(); currentTrackOffset += Marshal.SizeOf <Track>(); } } else if (i < sessions) { (byte minute, byte second, byte frame)leadoutAmsf = LbaToMsf(_writingTracks.First(t => t.TrackSession == i + 1).TrackStartSector - 150); (byte minute, byte second, byte frame)leadoutPmsf = LbaToMsf(_writingTracks.OrderBy(t => t.TrackSession).ThenBy(t => t.TrackSequence).Last(). TrackStartSector); thisSessionTracks.Add(0xB0, new Track { point = 0xB0, adrCtl = 0x50, zero = 0, min = leadoutAmsf.minute, sec = leadoutAmsf.second, frame = leadoutAmsf.frame, pmin = leadoutPmsf.minute, psec = leadoutPmsf.second, pframe = leadoutPmsf.frame, unknown = new byte[18], unknown2 = new byte[24] }); thisSessionTracks.Add(0xC0, new Track { point = 0xC0, adrCtl = 0x50, min = 128, pmin = 97, psec = 25, unknown = new byte[18], unknown2 = new byte[24] }); currentTrackOffset += Marshal.SizeOf <Track>() * 2; } _alcToc.Add(i, thisSessionTracks); } } _alcFooter = new Footer { filenameOffset = (uint)(footerOffset + Marshal.SizeOf <Footer>()), widechar = 1 }; byte[] filename = Encoding.Unicode.GetBytes("*.mdf"); // Yup, Alcohol stores no filename but a wildcard. // Write header _descriptorStream.Seek(0, SeekOrigin.Begin); byte[] block = new byte[Marshal.SizeOf <Header>()]; IntPtr blockPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(Marshal.SizeOf <Header>()); System.Runtime.InteropServices.Marshal.StructureToPtr(header, blockPtr, true); System.Runtime.InteropServices.Marshal.Copy(blockPtr, block, 0, block.Length); System.Runtime.InteropServices.Marshal.FreeHGlobal(blockPtr); _descriptorStream.Write(block, 0, block.Length); // Write DVD structures if present if (header.structuresOffset != 0) { if (_dmi != null) { _descriptorStream.Seek(header.structuresOffset, SeekOrigin.Begin); switch (_dmi.Length) { case 2052: _descriptorStream.Write(_dmi, 0, 2052); break; case 2048: _descriptorStream.Write(new byte[] { 0x08, 0x02, 0x00, 0x00 }, 0, 4); _descriptorStream.Write(_dmi, 0, 2048); break; } } // TODO: Create fake PFI if none present if (_pfi != null) { _descriptorStream.Seek(header.structuresOffset + 2052, SeekOrigin.Begin); _descriptorStream.Write(_pfi, _pfi.Length - 2048, 2048); } } // Write sessions _descriptorStream.Seek(header.sessionOffset, SeekOrigin.Begin); foreach (Session session in _alcSessions.Values) { block = new byte[Marshal.SizeOf <Session>()]; blockPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(Marshal.SizeOf <Session>()); System.Runtime.InteropServices.Marshal.StructureToPtr(session, blockPtr, true); System.Runtime.InteropServices.Marshal.Copy(blockPtr, block, 0, block.Length); System.Runtime.InteropServices.Marshal.FreeHGlobal(blockPtr); _descriptorStream.Write(block, 0, block.Length); } // Write tracks foreach (KeyValuePair <int, Dictionary <int, Track> > kvp in _alcToc) { _descriptorStream.Seek(_alcSessions.First(t => t.Key == kvp.Key).Value.trackOffset, SeekOrigin.Begin); foreach (Track track in kvp.Value.Values) { Track alcoholTrack = track; // Write extra if (!_isDvd) { long position = _descriptorStream.Position; _descriptorStream.Seek(alcoholTrack.extraOffset, SeekOrigin.Begin); block = new byte[Marshal.SizeOf <TrackExtra>()]; if (_alcTrackExtras.TryGetValue(alcoholTrack.point, out TrackExtra extra)) { blockPtr = System.Runtime.InteropServices.Marshal. AllocHGlobal(Marshal.SizeOf <TrackExtra>()); System.Runtime.InteropServices.Marshal.StructureToPtr(extra, blockPtr, true); System.Runtime.InteropServices.Marshal.Copy(blockPtr, block, 0, block.Length); System.Runtime.InteropServices.Marshal.FreeHGlobal(blockPtr); } else { alcoholTrack.extraOffset = 0; } _descriptorStream.Write(block, 0, block.Length); _descriptorStream.Seek(position, SeekOrigin.Begin); } block = new byte[Marshal.SizeOf <Track>()]; blockPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(Marshal.SizeOf <Track>()); System.Runtime.InteropServices.Marshal.StructureToPtr(alcoholTrack, blockPtr, true); System.Runtime.InteropServices.Marshal.Copy(blockPtr, block, 0, block.Length); System.Runtime.InteropServices.Marshal.FreeHGlobal(blockPtr); _descriptorStream.Write(block, 0, block.Length); } } // Write BCA if (_bca != null) { _descriptorStream.Seek(header.bcaOffset, SeekOrigin.Begin); _descriptorStream.Write(_bca, 0, _bca.Length); } // Write footer _descriptorStream.Seek(footerOffset, SeekOrigin.Begin); block = new byte[Marshal.SizeOf <Footer>()]; blockPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(Marshal.SizeOf <Footer>()); System.Runtime.InteropServices.Marshal.StructureToPtr(_alcFooter, blockPtr, true); System.Runtime.InteropServices.Marshal.Copy(blockPtr, block, 0, block.Length); System.Runtime.InteropServices.Marshal.FreeHGlobal(blockPtr); _descriptorStream.Write(block, 0, block.Length); // Write filename _descriptorStream.Write(filename, 0, filename.Length); // Write filename null termination _descriptorStream.Write(new byte[] { 0, 0 }, 0, 2); _descriptorStream.Flush(); _descriptorStream.Close(); _imageStream.Flush(); _imageStream.Close(); IsWriting = false; ErrorMessage = ""; return(true); }
public bool SetTracks(List <CommonTypes.Structs.Track> tracks) { ulong currentDataOffset = 0; _writingTracks = new List <CommonTypes.Structs.Track>(); if (!_isDvd) { CommonTypes.Structs.Track[] tmpTracks = tracks.OrderBy(t => t.TrackSequence).ToArray(); for (int i = 1; i < tmpTracks.Length; i++) { CommonTypes.Structs.Track firstTrackInSession = tracks.FirstOrDefault(t => t.TrackSession == tmpTracks[i].TrackSession); if (firstTrackInSession is null) { continue; } if (tmpTracks[i].TrackSequence == firstTrackInSession.TrackSequence) { if (tmpTracks[i].TrackSequence > 1) { tmpTracks[i].TrackStartSector += 150; } continue; } tmpTracks[i - 1].TrackEndSector += tmpTracks[i].TrackPregap; tmpTracks[i].TrackPregap = 0; tmpTracks[i].TrackStartSector = tmpTracks[i - 1].TrackEndSector + 1; } tracks = tmpTracks.ToList(); } foreach (CommonTypes.Structs.Track track in tracks.OrderBy(t => t.TrackSequence)) { CommonTypes.Structs.Track newTrack = track; uint subchannelSize; switch (track.TrackSubchannelType) { case TrackSubchannelType.None: subchannelSize = 0; break; case TrackSubchannelType.Raw: case TrackSubchannelType.RawInterleaved: subchannelSize = 96; break; default: ErrorMessage = $"Unsupported subchannel type {track.TrackSubchannelType}"; return(false); } newTrack.TrackFileOffset = currentDataOffset; currentDataOffset += (ulong)(newTrack.TrackRawBytesPerSector + subchannelSize) * ((newTrack.TrackEndSector - newTrack.TrackStartSector) + 1); _writingTracks.Add(newTrack); } return(true); }
public bool WriteSectors(byte[] data, ulong sectorAddress, uint length) { if (!IsWriting) { ErrorMessage = "Tried to write on a non-writable image"; return(false); } CommonTypes.Structs.Track track = _writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector && sectorAddress <= trk.TrackEndSector); if (track is null) { ErrorMessage = $"Can't found track 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); } switch (track.TrackSubchannelType) { case TrackSubchannelType.None: _imageStream. Seek((long)(track.TrackFileOffset + ((sectorAddress - track.TrackStartSector) * (ulong)track.TrackRawBytesPerSector)), SeekOrigin.Begin); _imageStream.Write(data, 0, data.Length); ErrorMessage = ""; return(true); case TrackSubchannelType.Raw: case TrackSubchannelType.RawInterleaved: _imageStream. Seek((long)(track.TrackFileOffset + ((sectorAddress - track.TrackStartSector) * (ulong)(track.TrackRawBytesPerSector + 96))), SeekOrigin.Begin); for (uint i = 0; i < length; i++) { _imageStream.Write(data, (int)(i * track.TrackRawBytesPerSector), track.TrackRawBytesPerSector); _imageStream.Position += 96; } ErrorMessage = ""; return(true); default: ErrorMessage = "Invalid subchannel mode for this sector"; return(false); } }
public bool WriteSectorTag(byte[] data, ulong sectorAddress, SectorTagType tag) { if (!IsWriting) { ErrorMessage = "Tried to write on a non-writable image"; return(false); } CommonTypes.Structs.Track track = _writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector && sectorAddress <= trk.TrackEndSector); if (track is null) { ErrorMessage = $"Can't found track containing {sectorAddress}"; return(false); } switch (tag) { case SectorTagType.CdTrackFlags: { if (data.Length != 1) { ErrorMessage = "Incorrect data size for track flags"; return(false); } _trackFlags[(byte)sectorAddress] = data[0]; return(true); } case SectorTagType.CdSectorSubchannel: { if (track.TrackSubchannelType == 0) { ErrorMessage = $"Trying to write subchannel to track {track.TrackSequence}, that does not have subchannel"; return(false); } if (data.Length != 96) { ErrorMessage = "Incorrect data size for subchannel"; return(false); } _imageStream. Seek((long)(track.TrackFileOffset + ((sectorAddress - track.TrackStartSector) * (ulong)(track.TrackRawBytesPerSector + 96))) + track.TrackRawBytesPerSector, SeekOrigin.Begin); _imageStream.Write(data, 0, data.Length); return(true); } default: ErrorMessage = $"Unsupported tag type {tag}"; return(false); } }