using System; using System.IO; using System.Collections.Generic; namespace BizHawk.Emulation.DiscSystem.CUE { internal abstract class SS_Base : ISectorSynthJob2448 { public IBlob Blob; public long BlobOffset; public DiscMountPolicy Policy; //subQ data public SubchannelQ sq; //subP data public bool Pause; public abstract void Synth(SectorSynthJob job); protected void SynthSubchannelAsNeed(SectorSynthJob job) { //synth P if needed if ((job.Parts & ESectorSynthPart.SubchannelP) != 0) { SynthUtils.SubP(job.DestBuffer2448, job.DestOffset + 2352, Pause); } //synth Q if needed //TODO - why not already have it serialized? Into a disc resource, even. if ((job.Parts & ESectorSynthPart.SubchannelQ) != 0) { SynthUtils.SubQ_Serialize(job.DestBuffer2448, job.DestOffset + 2352 + 12, ref sq); } //clear R-W if needed if ((job.Parts & ESectorSynthPart.Subchannel_RSTUVW) != 0) { Array.Clear(job.DestBuffer2448, job.DestOffset + 2352 + 12 + 12, (12 * 6)); } //subcode has been generated deinterleaved; we may still need to interleave it if((job.Parts & ESectorSynthPart.SubcodeAny) != 0) if ((job.Parts & (ESectorSynthPart.SubcodeDeinterleave)) == 0) { SynthUtils.InterleaveSubcodeInplace(job.DestBuffer2448, job.DestOffset + 2352); } } } /// /// Represents a Mode1 2048-byte sector /// class SS_Mode1_2048 : SS_Base { public override void Synth(SectorSynthJob job) { //read the sector user data if((job.Parts & ESectorSynthPart.User2048) != 0) Blob.Read(BlobOffset, job.DestBuffer2448, job.DestOffset + 16, 2048); if ((job.Parts & ESectorSynthPart.Header16) != 0) SynthUtils.SectorHeader(job.DestBuffer2448, job.DestOffset + 0, job.LBA, 1); if ((job.Parts & ESectorSynthPart.ECMAny) != 0) SynthUtils.ECM_Mode1(job.DestBuffer2448, job.DestOffset + 0, job.LBA); SynthSubchannelAsNeed(job); } } /// /// Represents a 2352-byte sector of any sort /// class SS_2352 : SS_Base { public override void Synth(SectorSynthJob job) { //read the sector user data Blob.Read(BlobOffset, job.DestBuffer2448, job.DestOffset, 2352); //if subcode is needed, synthesize it SynthSubchannelAsNeed(job); } } /// /// Encodes a pre-gap sector /// class SS_Gap : SS_Base { public CueTrackType TrackType; public override void Synth(SectorSynthJob job) { //this isn't fully analyzed/optimized Array.Clear(job.DestBuffer2448, job.DestOffset, 2352); byte mode = 255; int form = -1; switch (TrackType) { case CueTrackType.Audio: mode = 0; break; case CueTrackType.CDI_2352: case CueTrackType.Mode1_2352: mode = 1; break; case CueTrackType.Mode2_2352: mode = 2; if (Policy.CUE_PregapMode2_As_XA_Form2) { job.DestBuffer2448[job.DestOffset + 12 + 6] = 0x20; job.DestBuffer2448[job.DestOffset + 12 + 10] = 0x20; } form = 2; //no other choice right now really break; case CueTrackType.Mode1_2048: mode = 1; Pause = true; break; case CueTrackType.Mode2_2336: default: throw new InvalidOperationException("Not supported: " + TrackType); } //audio has no sector header but the others do if (mode != 0) { if ((job.Parts & ESectorSynthPart.Header16) != 0) SynthUtils.SectorHeader(job.DestBuffer2448, job.DestOffset + 0, job.LBA, mode); } if (mode == 1) { if ((job.Parts & ESectorSynthPart.ECMAny) != 0) SynthUtils.ECM_Mode1(job.DestBuffer2448, job.DestOffset + 0, job.LBA); } if (mode == 2 && form == 2) { SynthUtils.EDC_Mode2_Form2(job.DestBuffer2448, job.DestOffset); } SynthSubchannelAsNeed(job); } } }