public bool WriteSectorsTag(byte[] data, ulong sectorAddress, uint length, SectorTagType tag) { if (!IsWriting) { ErrorMessage = "Tried to write on a non-writable image"; return(false); } Track track = Tracks.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: case SectorTagType.CdTrackIsrc: 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); } if (_subStream == null) { try { _subStream = new FileStream(_writingBaseName + ".sub", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); } catch (IOException e) { ErrorMessage = $"Could not create subchannel file, exception {e.Message}"; return(false); } } _subStream. Seek((long)(track.TrackSubchannelOffset + ((sectorAddress - track.TrackStartSector) * 96)), SeekOrigin.Begin); _subStream.Write(Subchannel.Deinterleave(data), 0, data.Length); return(true); } default: ErrorMessage = $"Unsupported tag type {tag}"; return(false); } }
// Return true if indexes have changed bool WriteSubchannelToImage(MmcSubchannel supportedSubchannel, MmcSubchannel desiredSubchannel, byte[] sub, ulong sectorAddress, uint length, SubchannelLog subLog, Dictionary <byte, string> isrcs, byte currentTrack, ref string mcn, Track[] tracks) { if (supportedSubchannel == MmcSubchannel.Q16) { sub = Subchannel.ConvertQToRaw(sub); } if (desiredSubchannel != MmcSubchannel.None) { _outputPlugin.WriteSectorsTag(sub, sectorAddress, length, SectorTagType.CdSectorSubchannel); } subLog?.WriteEntry(sub, supportedSubchannel == MmcSubchannel.Raw, (long)sectorAddress, length); byte[] deSub = Subchannel.Deinterleave(sub); // Check subchannel for (int subPos = 0; subPos < deSub.Length; subPos += 96) { byte[] q = new byte[12]; Array.Copy(deSub, subPos + 12, q, 0, 12); CRC16CCITTContext.Data(q, 10, out byte[] crc); bool crcOk = crc[0] == q[10] && crc[1] == q[11]; // ISRC if ((q[0] & 0x3) == 3) { string isrc = Subchannel.DecodeIsrc(q); if (isrc == null || isrc == "000000000000") { continue; } if (!crcOk) { continue; } if (!isrcs.ContainsKey(currentTrack)) { _dumpLog?.WriteLine($"Found new ISRC {isrc} for track {currentTrack}."); UpdateStatus?.Invoke($"Found new ISRC {isrc} for track {currentTrack}."); } else if (isrcs[currentTrack] != isrc) { _dumpLog?. WriteLine($"ISRC for track {currentTrack} changed from {isrcs[currentTrack]} to {isrc}."); UpdateStatus?. Invoke($"ISRC for track {currentTrack} changed from {isrcs[currentTrack]} to {isrc}."); } isrcs[currentTrack] = isrc; } else if ((q[0] & 0x3) == 2) { string newMcn = Subchannel.DecodeMcn(q); if (newMcn == null || newMcn == "0000000000000") { continue; } if (!crcOk) { continue; } if (mcn is null) { _dumpLog?.WriteLine($"Found new MCN {newMcn}."); UpdateStatus?.Invoke($"Found new MCN {newMcn}."); } else if (mcn != newMcn) { _dumpLog?.WriteLine($"MCN changed from {mcn} to {newMcn}."); UpdateStatus?.Invoke($"MCN changed from {mcn} to {newMcn}."); } mcn = newMcn; } else if ((q[0] & 0x3) == 1) { // TODO: Indexes // Pregap if (q[2] != 0) { continue; } if (!crcOk) { continue; } byte trackNo = (byte)(((q[1] / 16) * 10) + (q[1] & 0x0F)); for (int i = 0; i < tracks.Length; i++) { if (tracks[i].TrackSequence != trackNo || trackNo == 1) { continue; } byte pmin = (byte)(((q[3] / 16) * 10) + (q[3] & 0x0F)); byte psec = (byte)(((q[4] / 16) * 10) + (q[4] & 0x0F)); byte pframe = (byte)(((q[5] / 16) * 10) + (q[5] & 0x0F)); int qPos = (pmin * 60 * 75) + (psec * 75) + pframe; if (tracks[i].TrackPregap >= (ulong)(qPos + 1)) { continue; } tracks[i].TrackPregap = (ulong)(qPos + 1); tracks[i].TrackStartSector -= tracks[i].TrackPregap; if (i > 0) { tracks[i - 1].TrackEndSector = tracks[i].TrackStartSector - 1; } _dumpLog?.WriteLine($"Pregap for track {trackNo} set to {tracks[i].TrackPregap} sectors."); UpdateStatus?.Invoke($"Pregap for track {trackNo} set to {tracks[i].TrackPregap} sectors."); return(true); } } } return(false); }