示例#1
0
		public DiscStream(Disc disc, EDiscStreamView view, int from_lba)
		{
			SectorSize = 2048;
			Disc = disc;
			NumSectors = disc.Session1.LeadoutLBA;
			dsr = new DiscSectorReader(disc);

			//following the provided view
			switch (view)
			{
				case EDiscStreamView.DiscStreamView_Mode1_2048:
					dsr.Policy.UserData2048Mode = DiscSectorReaderPolicy.EUserData2048Mode.AssumeMode1;
					break;
				case EDiscStreamView.DiscStreamView_Mode2_Form1_2048:
					dsr.Policy.UserData2048Mode = DiscSectorReaderPolicy.EUserData2048Mode.AssumeMode2_Form1;
					break;
				default:
					throw new NotSupportedException("Unsupported EDiscStreamView");
			}


			currPosition = from_lba * SectorSize;
			cachedSector = -1;
			cachedSectorBuffer = new byte[SectorSize];
		}
示例#2
0
		public Yabause(CoreComm CoreComm, DiscSystem.Disc CD, object SyncSettings)
		{
			byte[] bios = CoreComm.CoreFileProvider.GetFirmware("SAT", "J", true, "Saturn BIOS is required.");
			CoreComm.RomStatusDetails = string.Format("Disk partial hash:{0}", CD.GetHash());
			this.CoreComm = CoreComm;
			this.CD = CD;

			this.SyncSettings = (SaturnSyncSettings)SyncSettings ?? new SaturnSyncSettings();

			if (this.SyncSettings.UseGL && glContext == null)
			{
				glContext = CoreComm.RequestGLContext();
			}


			ResetCounters();

			ActivateGL();
			Init(bios);

			InputCallbackH = new LibYabause.InputCallback(() => CoreComm.InputCallback.Call());
			LibYabause.libyabause_setinputcallback(InputCallbackH);
			CoreComm.UsesDriveLed = true;

			DeactivateGL();
		}
示例#3
0
		public DiscIdentifier(Disc disc)
		{
			this.disc = disc;
			dsr = new DiscSectorReader(disc);
			
			//the first check for mode 0 should be sufficient for blocking attempts to read audio sectors, so dont do this
			//dsr.Policy.ThrowExceptions2048 = false;
		}
示例#4
0
		void _Open_LBA_2048(Disc disc)
		{
			SectorSize = 2048;
			Disc = disc;
			NumSectors = disc.LBACount;

			currPosition = 0;
			cachedSector = -1;
			cachedSectorBuffer = new byte[SectorSize];
		}
示例#5
0
		void BindDisc(DiscRecord discRecord)
		{
			Disc disc = discRecord.Disc;
			boundDiscRecord = discRecord;

			DiscStructure toc = disc.ReadStructure();
			boundDisc = disc;
			lblSessions.Text = toc.Sessions.Count.ToString();
			lblTracks.Text = toc.Sessions.Sum((ses) => ses.Tracks.Count).ToString();
			lblSectors.Text = string.Format("{0} ({1})", toc.LengthInSectors, toc.FriendlyLength.Value);
			lblSize.Text = string.Format("{0:0.00} MB", toc.BinarySize / 1024.0 / 1024.0);
			btnExportCue.Enabled = true;
			UpdateCue();
		}
示例#6
0
        public DiscStream(Disc disc, EDiscStreamView view, int from_lba)
        {
            if (view != EDiscStreamView.DiscStreamView_Mode1_2048)
                throw new NotSupportedException("disc streams of not mode 1 are currently unsupported");

            SectorSize = 2048;
            Disc = disc;
            NumSectors = disc.Session1.LeadoutLBA;
            dsr = new DiscSectorReader(disc);

            //following the provided view
            dsr.Policy.UserData2048Mode = DiscSectorReaderPolicy.EUserData2048Mode.AssumeMode1;

            currPosition = from_lba * SectorSize;
            cachedSector = -1;
            cachedSectorBuffer = new byte[SectorSize];
        }
示例#7
0
        /// <summary>
        /// applies an SBI file to the disc
        /// </summary>
        public void Run(Disc disc, SBI.SubQPatchData sbi, bool asMednafen)
        {
            //TODO - could implement as a blob, to avoid allocating so many byte buffers

            //save this, it's small, and we'll want it for disc processing a/b checks
            disc.Memos["sbi"] = sbi;

            DiscSectorReader dsr = new DiscSectorReader(disc);

            int n = sbi.ABAs.Count;
            int b = 0;
            for (int i = 0; i < n; i++)
            {
                int lba = sbi.ABAs[i] - 150;

                //create a synthesizer which can return the patched data
                var ss_patchq = new SS_PatchQ() { Original = disc.Sectors[lba + 150] };
                byte[] subQbuf = ss_patchq.Buffer_SubQ;

                //read the old subcode
                dsr.ReadLBA_SubQ(lba, subQbuf, 0);

                //insert patch
                disc.Sectors[lba + 150] = ss_patchq;

                //apply SBI patch
                for (int j = 0; j < 12; j++)
                {
                    short patch = sbi.subq[b++];
                    if (patch == -1) continue;
                    else subQbuf[j] = (byte)patch;
                }

                //Apply mednafen hacks
                //The reasoning here is that we know we expect these sectors to have a wrong checksum. therefore, generate a checksum, and make it wrong
                //However, this seems senseless to me. The whole point of the SBI data is that it stores the patches needed to generate an acceptable subQ, right?
                if (asMednafen)
                {
                    SynthUtils.SubQ_SynthChecksum(subQbuf, 0);
                    subQbuf[10] ^= 0xFF;
                    subQbuf[11] ^= 0xFF;
                }
            }
        }
示例#8
0
		public static void Extract(Disc disc, string path, string filebase)
		{
			var dsr = new DiscSectorReader(disc);

			bool confirmed = false;
			var tracks = disc.Session1.Tracks;
			foreach (var track in tracks)
			{
				if (!track.IsAudio)
					continue;

				int trackLength = track.NextTrack.LBA - track.LBA;
				var waveData = new byte[trackLength * 2352];
				int startLba = track.LBA;
				for (int sector = 0; sector < trackLength; sector++)
					dsr.ReadLBA_2352(startLba + sector, waveData, sector * 2352);

				string mp3Path = string.Format("{0} - Track {1:D2}.mp3", Path.Combine(path, filebase), track.Number);
				if (File.Exists(mp3Path))
				{
					if (!confirmed)
					{
						var dr = MessageBox.Show("This file already exists. Do you want extraction to proceed overwriting files, or cancel the entire operation immediately?", "File already exists", MessageBoxButtons.OKCancel);
						if (dr == DialogResult.Cancel) return;
						confirmed = true;
					}
					File.Delete(mp3Path);
				}

				string tempfile = Path.GetTempFileName();

				try
				{
					File.WriteAllBytes(tempfile, waveData);
					var ffmpeg = new FFMpeg();
					ffmpeg.Run("-f", "s16le", "-ar", "44100", "-ac", "2", "-i", tempfile, "-f", "mp3", "-ab", "192k", mp3Path);
				}
				finally
				{
					File.Delete(tempfile);
				}
			}
		}
示例#9
0
 public CDAudio(Disc disc, int maxVolume = short.MaxValue)
 {
     Disc = disc;
     MaxVolume = maxVolume;
 }
示例#10
0
 public static DiscStream Open_LBA_2048(Disc disc)
 {
     var ret = new DiscStream();
     ret._Open_LBA_2048(disc);
     return ret;
 }
示例#11
0
 public DiscSectorReader(Disc disc)
 {
     this.disc = disc;
 }
示例#12
0
 /// <summary>
 /// THIS HASNT BEEN TESTED IN A LONG TIME. DOES IT WORK?
 /// </summary>
 public static Disc FromIsoPath(string isoPath)
 {
     var ret = new Disc();
     ret.FromIsoPathInternal(isoPath);
     ret.Structure.Synthesize_TOCPointsFromSessions();
     ret.Synthesize_SubcodeFromStructure();
     return ret;
 }
示例#13
0
 public DiscIdentifier(Disc disc)
 {
     this.disc = disc;
     dsr = new DiscSectorReader(disc);
 }
示例#14
0
		void RunMednaDisc()
		{
			var disc = new Disc();
			OUT_Disc = disc;

			//create a MednaDisc and give it to the disc for ownership
			var md = new MednaDisc(IN_FromPath);
			disc.DisposableResources.Add(md);

			//"length of disc" for bizhawk's purposes (NOT a robust concept!) is determined by beginning of leadout track
			var m_leadoutTrack = md.TOCTracks[100];
			int nSectors = (int)m_leadoutTrack.lba;

			//make synth param memos
			disc.SynthParams.MednaDisc = md;

			//this is the sole sector synthesizer we'll need
			var synth = new SS_MednaDisc();
			OUT_Disc.SynthProvider = new SimpleSectorSynthProvider() { SS = synth };

			//ADR (q-Mode) is necessarily 0x01 for a RawTOCEntry
			const int kADR = 1;
			const int kUnknownControl = 0;

			//mednafen delivers us what is essentially but not exactly (or completely) a TOCRaw.
			//we need to synth RawTOCEntries from this and then turn it into a proper TOCRaw
			//when coming from mednafen, there are 101 entries.
			//entry[0] is placeholder junk, not to be used
			//entry[100] is the leadout track (A0)
			//A1 and A2 are in the form of FirstRecordedTrackNumber and LastRecordedTrackNumber
			for (int i = 1; i < 101; i++)
			{
				var m_te = md.TOCTracks[i];

				//dont add invalid (absent) items
				if (!m_te.Valid)
					continue;

				var m_ts = new Timestamp((int)m_te.lba + 150); //these are supposed to be absolute timestamps

				var q = new SubchannelQ
				{
					q_status = SubchannelQ.ComputeStatus(kADR, (EControlQ)m_te.control), 
					q_tno = BCD2.FromDecimal(0), //unknown with mednadisc
					q_index = BCD2.FromDecimal(i),
					min = BCD2.FromDecimal(0), //unknown with mednadisc
					sec = BCD2.FromDecimal(0), //unknown with mednadisc
					frame = BCD2.FromDecimal(0), //unknown with mednadisc
					zero = 0, //unknown with mednadisc
					ap_min = BCD2.FromDecimal(m_ts.MIN),
					ap_sec = BCD2.FromDecimal(m_ts.SEC),
					ap_frame = BCD2.FromDecimal(m_ts.FRAC),
					q_crc = 0 //meaningless
				};

				//a special fixup: mednafen's entry 100 is the lead-out track, so change it into the A2 raw toc entry
				if (i == 100)
				{
					q.q_index.BCDValue = 0xA2;
				}

				disc.RawTOCEntries.Add(new RawTOCEntry { QData = q });
			}

			//synth A0 and A1 entries (indicating first and last recorded tracks and also session type)
			var qA0 = new SubchannelQ
			{
				q_status = SubchannelQ.ComputeStatus(kADR, kUnknownControl),
				q_tno = BCD2.FromDecimal(0), //unknown with mednadisc
				q_index = BCD2.FromBCD(0xA0),
				min = BCD2.FromDecimal(0), //unknown with mednadisc
				sec = BCD2.FromDecimal(0), //unknown with mednadisc
				frame = BCD2.FromDecimal(0), //unknown with mednadisc
				zero = 0, //unknown with mednadisc
				ap_min = BCD2.FromDecimal(md.TOC.first_track),
				ap_sec = BCD2.FromDecimal(md.TOC.disc_type),
				ap_frame = BCD2.FromDecimal(0),
				q_crc = 0, //meaningless
			};
			disc.RawTOCEntries.Add(new RawTOCEntry { QData = qA0 });
			var qA1 = new SubchannelQ
			{
				q_status = SubchannelQ.ComputeStatus(kADR, kUnknownControl),
				q_tno = BCD2.FromDecimal(0), //unknown with mednadisc
				q_index = BCD2.FromBCD(0xA1),
				min = BCD2.FromDecimal(0), //unknown with mednadisc
				sec = BCD2.FromDecimal(0), //unknown with mednadisc
				frame = BCD2.FromDecimal(0), //unknown with mednadisc
				zero = 0, //unknown with mednadisc
				ap_min = BCD2.FromDecimal(md.TOC.last_track),
				ap_sec = BCD2.FromDecimal(0),
				ap_frame = BCD2.FromDecimal(0),
				q_crc = 0, //meaningless
			};
			disc.RawTOCEntries.Add(new RawTOCEntry { QData = qA1 });

		}
示例#15
0
		public ScsiCDBus(PCEngine pce, Disc disc)
		{
			this.pce = pce;
			this.disc = disc;
		}
示例#16
0
 public DiscHasher(Disc disc)
 {
     this.disc = disc;
 }
示例#17
0
 public CDAudio(Disc disc, int maxVolume = short.MaxValue)
 {
     Disc      = disc;
     MaxVolume = maxVolume;
 }
示例#18
0
        /// <exception cref="MDSParseException">no file found at <paramref name="mdsPath"/> or BLOB error</exception>
        public Disc LoadMDSToDisc(string mdsPath, DiscMountPolicy IN_DiscMountPolicy)
        {
            var loadResults = LoadMDSPath(mdsPath);

            if (!loadResults.Valid)
            {
                throw loadResults.FailureException;
            }

            Disc disc = new Disc();

            // load all blobs
            Dictionary <int, IBlob> BlobIndex = MountBlobs(loadResults.ParsedMDSFile, disc);

            var mdsf = loadResults.ParsedMDSFile;

            //generate DiscTOCRaw items from the ones specified in the MDS file
            disc.RawTOCEntries = new List <RawTOCEntry>();
            foreach (var entry in mdsf.TOCEntries)
            {
                disc.RawTOCEntries.Add(EmitRawTOCEntry(entry));
            }

            //analyze the RAWTocEntries to figure out what type of track track 1 is
            var tocSynth = new Synthesize_DiscTOC_From_RawTOCEntries_Job()
            {
                Entries = disc.RawTOCEntries
            };

            tocSynth.Run();

            // now build the sectors
            int currBlobIndex = 0;

            foreach (var session in mdsf.ParsedSession)
            {
                for (int i = session.StartTrack; i <= session.EndTrack; i++)
                {
                    int relMSF = -1;

                    var track = mdsf.TOCEntries.FirstOrDefault(t => t.Point == i);
                    if (track == null)
                    {
                        break;
                    }

                    // ignore the info entries
                    if (track.Point == 0xA0 ||
                        track.Point == 0xA1 ||
                        track.Point == 0xA2)
                    {
                        continue;
                    }

                    // get the blob(s) for this track
                    // it's probably a safe assumption that there will be only one blob per track, but I'm still not 100% sure on this
                    var tr = mdsf.TOCEntries.FirstOrDefault(a => a.Point == i) ?? throw new MDSParseException("BLOB Error!");

#if true
                    if (tr.ImageFileNamePaths.Count == 0)
                    {
                        throw new MDSParseException("BLOB Error!");
                    }
#else // this is the worst use of lists and LINQ I've seen in this god-forsaken codebase, I hope for all our sakes that it's not a workaround for some race condition --yoshi
                    List <string> blobstrings = new List <string>();
                    foreach (var t in tr.ImageFileNamePaths)
                    {
                        if (!blobstrings.Contains(t))
                        {
                            blobstrings.Add(t);
                        }
                    }

                    var tBlobs = (from a in tr.ImageFileNamePaths
                                  select a).ToList();

                    if (tBlobs.Count < 1)
                    {
                        throw new MDSParseException("BLOB Error!");
                    }

                    // is the currBlob valid for this track, or do we need to increment?
                    string bString = tBlobs.First();
#endif

                    IBlob mdfBlob = null;

                    // check for track pregap and create if necessary
                    // this is specified in the track extras block
                    if (track.ExtraBlock.Pregap > 0)
                    {
                        CUE.CueTrackType pregapTrackType = CUE.CueTrackType.Audio;
                        if (tocSynth.Result.TOCItems[1].IsData)
                        {
                            if (tocSynth.Result.Session1Format == SessionFormat.Type20_CDXA)
                            {
                                pregapTrackType = CUE.CueTrackType.Mode2_2352;
                            }
                            else if (tocSynth.Result.Session1Format == SessionFormat.Type10_CDI)
                            {
                                pregapTrackType = CUE.CueTrackType.CDI_2352;
                            }
                            else if (tocSynth.Result.Session1Format == SessionFormat.Type00_CDROM_CDDA)
                            {
                                pregapTrackType = CUE.CueTrackType.Mode1_2352;
                            }
                        }
                        for (int pre = 0; pre < track.ExtraBlock.Pregap; pre++)
                        {
                            relMSF++;

                            var ss_gap = new CUE.SS_Gap()
                            {
                                Policy    = IN_DiscMountPolicy,
                                TrackType = pregapTrackType
                            };
                            disc._Sectors.Add(ss_gap);

                            int qRelMSF = pre - Convert.ToInt32(track.ExtraBlock.Pregap);

                            //tweak relMSF due to ambiguity/contradiction in yellowbook docs
                            if (!IN_DiscMountPolicy.CUE_PregapContradictionModeA)
                            {
                                qRelMSF++;
                            }

                            //setup subQ
                            byte ADR = 1;                             //absent some kind of policy for how to set it, this is a safe assumption:
                            ss_gap.sq.SetStatus(ADR, tocSynth.Result.TOCItems[1].Control);
                            ss_gap.sq.q_tno        = BCD2.FromDecimal(1);
                            ss_gap.sq.q_index      = BCD2.FromDecimal(0);
                            ss_gap.sq.AP_Timestamp = pre;
                            ss_gap.sq.Timestamp    = qRelMSF;

                            //setup subP
                            ss_gap.Pause = true;
                        }
                        // pregap processing completed
                    }



                    // create track sectors
                    long currBlobOffset = track.TrackOffset;
                    for (long sector = session.StartSector; sector <= session.EndSector; sector++)
                    {
                        CUE.SS_Base sBase = null;

                        // get the current blob from the BlobIndex
                        Disc.Blob_RawFile currBlob = (Disc.Blob_RawFile)BlobIndex[currBlobIndex];
                        long currBlobLength        = currBlob.Length;
                        long currBlobPosition      = sector;
                        if (currBlobPosition == currBlobLength)
                        {
                            currBlobIndex++;
                        }
                        mdfBlob = disc.DisposableResources[currBlobIndex] as Disc.Blob_RawFile;

                        //int userSector = 2048;
                        switch (track.SectorSize)
                        {
                        case 2448:
                            sBase = new CUE.SS_2352()
                            {
                                Policy = IN_DiscMountPolicy
                            };
                            //userSector = 2352;
                            break;

                        case 2048:
                        default:
                            sBase = new CUE.SS_Mode1_2048()
                            {
                                Policy = IN_DiscMountPolicy
                            };
                            //userSector = 2048;
                            break;

                            //throw new Exception($"Not supported: Sector Size {track.SectorSize}");
                        }

                        // configure blob
                        sBase.Blob       = mdfBlob;
                        sBase.BlobOffset = currBlobOffset;

                        currBlobOffset += track.SectorSize;                         // userSector;

                        // add subchannel data
                        relMSF++;
                        BCD2 tno, ino;

                        //this should actually be zero. im not sure if this is stored as BCD2 or not
                        tno = BCD2.FromDecimal(track.TrackNo);

                        //these are special values.. I think, taken from this:
                        //http://www.staff.uni-mainz.de/tacke/scsi/SCSI2-14.html
                        //the CCD will contain Points as decimal values except for these specially converted decimal values which should stay as BCD.
                        //Why couldn't they all be BCD? I don't know. I guess because BCD is inconvenient, but only A0 and friends have special meaning. It's confusing.
                        ino = BCD2.FromDecimal(track.Point);
                        if (track.Point == 0xA0)
                        {
                            ino.BCDValue = 0xA0;
                        }
                        else if (track.Point == 0xA1)
                        {
                            ino.BCDValue = 0xA1;
                        }
                        else if (track.Point == 0xA2)
                        {
                            ino.BCDValue = 0xA2;
                        }

                        // get ADR & Control from ADR_Control byte
                        byte adrc    = Convert.ToByte(track.ADR_Control);
                        var  Control = adrc & 0x0F;
                        var  ADR     = adrc >> 4;

                        var q = new SubchannelQ
                        {
                            q_status     = SubchannelQ.ComputeStatus(ADR, (EControlQ)(Control & 0xF)),
                            q_tno        = BCD2.FromDecimal(track.Point),
                            q_index      = ino,
                            AP_Timestamp = disc._Sectors.Count,
                            Timestamp    = relMSF - Convert.ToInt32(track.ExtraBlock.Pregap)
                        };

                        sBase.sq = q;

                        disc._Sectors.Add(sBase);
                    }
                }
            }

            return(disc);
        }
示例#19
0
        /// <exception cref="CCDParseException">file <paramref name="ccdPath"/> not found, nonexistent IMG file, nonexistent SUB file, IMG or SUB file not multiple of <c>2352 B</c>, or IMG and SUB files differ in length</exception>
        public Disc LoadCCDToDisc(string ccdPath, DiscMountPolicy IN_DiscMountPolicy)
        {
            var loadResults = LoadCCDPath(ccdPath);

            if (!loadResults.Valid)
            {
                throw loadResults.FailureException;
            }

            Disc disc = new Disc();

            IBlob imgBlob = null, subBlob = null;
            long  imgLen = -1, subLen;

            //mount the IMG file
            //first check for a .ecm in place of the img
            var imgPath = loadResults.ImgPath;

            if (!File.Exists(imgPath))
            {
                var ecmPath = Path.ChangeExtension(imgPath, ".img.ecm");
                if (File.Exists(ecmPath))
                {
                    if (Disc.Blob_ECM.IsECM(ecmPath))
                    {
                        var ecm = new Disc.Blob_ECM();
                        ecm.Load(ecmPath);
                        imgBlob = ecm;
                        imgLen  = ecm.Length;
                    }
                }
            }
            if (imgBlob == null)
            {
                if (!File.Exists(loadResults.ImgPath))
                {
                    throw new CCDParseException("Malformed CCD format: nonexistent IMG file!");
                }
                var imgFile = new Disc.Blob_RawFile()
                {
                    PhysicalPath = loadResults.ImgPath
                };
                imgLen  = imgFile.Length;
                imgBlob = imgFile;
            }
            disc.DisposableResources.Add(imgBlob);

            //mount the SUB file
            if (!File.Exists(loadResults.SubPath))
            {
                throw new CCDParseException("Malformed CCD format: nonexistent SUB file!");
            }
            var subFile = new Disc.Blob_RawFile()
            {
                PhysicalPath = loadResults.SubPath
            };

            subBlob = subFile;
            disc.DisposableResources.Add(subBlob);
            subLen = subFile.Length;

            //quick integrity check of file sizes
            if (imgLen % 2352 != 0)
            {
                throw new CCDParseException("Malformed CCD format: IMG file length not multiple of 2352");
            }
            int NumImgSectors = (int)(imgLen / 2352);

            if (subLen != NumImgSectors * 96)
            {
                throw new CCDParseException("Malformed CCD format: SUB file length not matching IMG");
            }

            var ccdf = loadResults.ParsedCCDFile;

            //the only instance of a sector synthesizer we'll need
            SS_CCD synth = new SS_CCD();

            //generate DiscTOCRaw items from the ones specified in the CCD file
            //TODO - range validate these (too many truncations to byte)
            disc.RawTOCEntries = new List <RawTOCEntry>();
            foreach (var entry in ccdf.TOCEntries)
            {
                BCD2 tno, ino;

                //this should actually be zero. im not sure if this is stored as BCD2 or not
                tno = BCD2.FromDecimal(entry.TrackNo);

                //these are special values.. I think, taken from this:
                //http://www.staff.uni-mainz.de/tacke/scsi/SCSI2-14.html
                //the CCD will contain Points as decimal values except for these specially converted decimal values which should stay as BCD.
                //Why couldn't they all be BCD? I don't know. I guess because BCD is inconvenient, but only A0 and friends have special meaning. It's confusing.
                ino = BCD2.FromDecimal(entry.Point);
                if (entry.Point == 0xA0)
                {
                    ino.BCDValue = 0xA0;
                }
                else if (entry.Point == 0xA1)
                {
                    ino.BCDValue = 0xA1;
                }
                else if (entry.Point == 0xA2)
                {
                    ino.BCDValue = 0xA2;
                }

                var q = new SubchannelQ
                {
                    q_status = SubchannelQ.ComputeStatus(entry.ADR, (EControlQ)(entry.Control & 0xF)),
                    q_tno    = tno,
                    q_index  = ino,
                    min      = BCD2.FromDecimal(entry.AMin),
                    sec      = BCD2.FromDecimal(entry.ASec),
                    frame    = BCD2.FromDecimal(entry.AFrame),
                    zero     = (byte)entry.Zero,
                    ap_min   = BCD2.FromDecimal(entry.PMin),
                    ap_sec   = BCD2.FromDecimal(entry.PSec),
                    ap_frame = BCD2.FromDecimal(entry.PFrame),
                    q_crc    = 0,                  //meaningless
                };

                disc.RawTOCEntries.Add(new RawTOCEntry {
                    QData = q
                });
            }

            //analyze the RAWTocEntries to figure out what type of track track 1 is
            var tocSynth = new Synthesize_DiscTOC_From_RawTOCEntries_Job()
            {
                Entries = disc.RawTOCEntries
            };

            tocSynth.Run();

            //Add sectors for the mandatory track 1 pregap, which isn't stored in the CCD file
            //We reuse some CUE code for this.
            //If we load other formats later we might should abstract this even further (to a synthesizer job)
            //It can't really be abstracted from cue files though due to the necessity of merging this with other track 1 pregaps
            CUE.CueTrackType pregapTrackType = CUE.CueTrackType.Audio;
            if (tocSynth.Result.TOCItems[1].IsData)
            {
                if (tocSynth.Result.Session1Format == SessionFormat.Type20_CDXA)
                {
                    pregapTrackType = CUE.CueTrackType.Mode2_2352;
                }
                else if (tocSynth.Result.Session1Format == SessionFormat.Type10_CDI)
                {
                    pregapTrackType = CUE.CueTrackType.CDI_2352;
                }
                else if (tocSynth.Result.Session1Format == SessionFormat.Type00_CDROM_CDDA)
                {
                    pregapTrackType = CUE.CueTrackType.Mode1_2352;
                }
            }
            for (int i = 0; i < 150; i++)
            {
                var ss_gap = new CUE.SS_Gap()
                {
                    Policy    = IN_DiscMountPolicy,
                    TrackType = pregapTrackType
                };
                disc._Sectors.Add(ss_gap);

                int qRelMSF = i - 150;

                //tweak relMSF due to ambiguity/contradiction in yellowbook docs
                if (!IN_DiscMountPolicy.CUE_PregapContradictionModeA)
                {
                    qRelMSF++;
                }

                //setup subQ
                byte ADR = 1;                 //absent some kind of policy for how to set it, this is a safe assumption:
                ss_gap.sq.SetStatus(ADR, tocSynth.Result.TOCItems[1].Control);
                ss_gap.sq.q_tno        = BCD2.FromDecimal(1);
                ss_gap.sq.q_index      = BCD2.FromDecimal(0);
                ss_gap.sq.AP_Timestamp = i;
                ss_gap.sq.Timestamp    = qRelMSF;

                //setup subP
                ss_gap.Pause = true;
            }

            //build the sectors:
            //set up as many sectors as we have img/sub for, even if the TOC doesnt reference them
            //(the TOC is unreliable, and the Track records are redundant)
            for (int i = 0; i < NumImgSectors; i++)
            {
                disc._Sectors.Add(synth);
            }

            return(disc);
        }
示例#20
0
        public static void Dump(Disc disc, string path)
        {
            using (var sw = new StreamWriter(path))
            {
                //NOTE: IsoBuster requires the A0,A1,A2 RawTocEntries to be first or else it can't do anything with the tracks
                //if we ever get them in a different order, we'll have to re-order them here

                sw.WriteLine("[CloneCD]");
                sw.WriteLine("Version=3");
                sw.WriteLine();
                sw.WriteLine("[Disc]");
                sw.WriteLine("TocEntries={0}", disc.RawTOCEntries.Count);
                sw.WriteLine("Sessions=1");
                sw.WriteLine("DataTracksScrambled=0");
                sw.WriteLine("CDTextLength=0");                 //not supported anyway
                sw.WriteLine();
                sw.WriteLine("[Session 1]");
                sw.WriteLine("PreGapMode=2");
                sw.WriteLine("PreGapSubC=1");
                sw.WriteLine();
                for (int i = 0; i < disc.RawTOCEntries.Count; i++)
                {
                    var entry = disc.RawTOCEntries[i];

                    //ehhh something's wrong with how I track these
                    int point = entry.QData.q_index.DecimalValue;
                    if (point == 100)
                    {
                        point = 0xA0;
                    }
                    if (point == 101)
                    {
                        point = 0xA1;
                    }
                    if (point == 102)
                    {
                        point = 0xA2;
                    }

                    sw.WriteLine("[Entry {0}]", i);
                    sw.WriteLine("Session=1");
                    sw.WriteLine("Point=0x{0:x2}", point);
                    sw.WriteLine("ADR=0x{0:x2}", entry.QData.ADR);
                    sw.WriteLine("Control=0x{0:x2}", (int)entry.QData.CONTROL);
                    sw.WriteLine("TrackNo={0}", entry.QData.q_tno.DecimalValue);
                    sw.WriteLine("AMin={0}", entry.QData.min.DecimalValue);
                    sw.WriteLine("ASec={0}", entry.QData.sec.DecimalValue);
                    sw.WriteLine("AFrame={0}", entry.QData.frame.DecimalValue);
                    sw.WriteLine("ALBA={0}", entry.QData.Timestamp - 150);                     //remember to adapt the absolute MSF to an LBA (this field is redundant...)
                    sw.WriteLine("Zero={0}", entry.QData.zero);
                    sw.WriteLine("PMin={0}", entry.QData.ap_min.DecimalValue);
                    sw.WriteLine("PSec={0}", entry.QData.ap_sec.DecimalValue);
                    sw.WriteLine("PFrame={0}", entry.QData.ap_frame.DecimalValue);
                    sw.WriteLine("PLBA={0}", entry.QData.AP_Timestamp - 150);                     //remember to adapt the absolute MSF to an LBA (this field is redundant...)
                    sw.WriteLine();
                }

                //this is nonsense, really. the whole CCD track list shouldn't be needed.
                //but in order to make a high quality CCD which can be inspected by various other tools, we need it
                //now, regarding the indexes.. theyre truly useless. having indexes written out with the tracks is bad news.
                //index information is only truly stored in subQ
                for (int tnum = 1; tnum <= disc.Session1.LastInformationTrack.Number; tnum++)
                {
                    var track = disc.Session1.Tracks[tnum];
                    sw.WriteLine("[TRACK {0}]", track.Number);
                    sw.WriteLine("MODE={0}", track.Mode);
                    //indexes are BS, dont write them. but we certainly need an index 1
                    sw.WriteLine("INDEX 1={0}", track.LBA);
                    sw.WriteLine();
                }
            }

            //TODO - actually re-add
            //dump the img and sub
            //TODO - acquire disk size first
            string           imgPath = Path.ChangeExtension(path, ".img");
            string           subPath = Path.ChangeExtension(path, ".sub");
            var              buf2448 = new byte[2448];
            DiscSectorReader dsr     = new DiscSectorReader(disc);

            using (var imgFile = File.OpenWrite(imgPath))
                using (var subFile = File.OpenWrite(subPath))
                {
                    int nLBA = disc.Session1.LeadoutLBA;
                    for (int lba = 0; lba < nLBA; lba++)
                    {
                        dsr.ReadLBA_2448(lba, buf2448, 0);
                        imgFile.Write(buf2448, 0, 2352);
                        subFile.Write(buf2448, 2352, 96);
                    }
                }
        }
示例#21
0
        void RunBizHawk()
        {
            string infile = IN_FromPath;
            string cue_content = null;

            var cfr = new CueFileResolver();

            RERUN:
            var ext = Path.GetExtension(infile).ToLowerInvariant();

            if (ext == ".iso")
            {
                //make a fake cue file to represent this iso file and rerun it as a cue
                string filebase = Path.GetFileName(infile);
                cue_content = string.Format(@"
                        FILE ""{0}"" BINARY
                            TRACK 01 MODE1/2048
                                INDEX 01 00:00:00",
                    filebase);
                infile = Path.ChangeExtension(infile, ".cue");
                goto RERUN;
            }
            if (ext == ".cue")
            {
                //TODO - make sure code is designed so no matter what happens, a disc is disposed in case of errors.
                //perhaps the CUE_Format2 (once renamed to something like Context) can handle that
                var cuePath = IN_FromPath;
                var cueContext = new CUE_Context();
                cueContext.DiscMountPolicy = IN_DiscMountPolicy;

                cueContext.Resolver = cfr;
                if (!cfr.IsHardcodedResolve) cfr.SetBaseDirectory(Path.GetDirectoryName(infile));

                //parse the cue file
                var parseJob = new ParseCueJob();
                if (cue_content == null)
                    cue_content = File.ReadAllText(cuePath);
                parseJob.IN_CueString = cue_content;
                parseJob.Run(parseJob);
                //TODO - need better handling of log output
                if (!string.IsNullOrEmpty(parseJob.OUT_Log)) Console.WriteLine(parseJob.OUT_Log);
                ConcatenateJobLog(parseJob);

                //compile the cue file:
                //includes this work: resolve required bin files and find out what it's gonna take to load the cue
                var compileJob = new CompileCueJob();
                compileJob.IN_CueContext = cueContext;
                compileJob.IN_CueFile = parseJob.OUT_CueFile;
                compileJob.Run();
                //TODO - need better handling of log output
                if (!string.IsNullOrEmpty(compileJob.OUT_Log)) Console.WriteLine(compileJob.OUT_Log);
                ConcatenateJobLog(compileJob);

                //check slow loading threshold
                if (compileJob.OUT_LoadTime >= IN_SlowLoadAbortThreshold)
                {
                    Warn("Loading terminated due to slow load threshold");
                    OUT_SlowLoadAborted = true;
                    goto DONE;
                }

                //actually load it all up
                var loadJob = new LoadCueJob();
                loadJob.IN_CompileJob = compileJob;
                loadJob.Run();
                //TODO - need better handling of log output
                if (!string.IsNullOrEmpty(loadJob.OUT_Log)) Console.WriteLine(loadJob.OUT_Log);
                ConcatenateJobLog(loadJob);

                OUT_Disc = loadJob.OUT_Disc;
                //OUT_Disc.DiscMountPolicy = IN_DiscMountPolicy; //NOT SURE WE NEED THIS (only makes sense for cue probably)

                //apply SBI if it exists (TODO - for formats other than cue?)
                var sbiPath = Path.ChangeExtension(IN_FromPath, ".sbi");
                if (File.Exists(sbiPath) && SBI.SBIFormat.QuickCheckISSBI(sbiPath))
                {
                    var loadSbiJob = new SBI.LoadSBIJob() { IN_Path = sbiPath };
                    loadSbiJob.Run();
                    var applySbiJob = new ApplySBIJob();
                    applySbiJob.Run(OUT_Disc, loadSbiJob.OUT_Data, IN_DiscMountPolicy.SBI_As_Mednafen);
                }
            }
            else if (ext == ".ccd")
            {
                CCD_Format ccdLoader = new CCD_Format();
                OUT_Disc = ccdLoader.LoadCCDToDisc(IN_FromPath, IN_DiscMountPolicy);
            }

            DONE: ;
        }
示例#22
0
 public ScsiCDBus(PCEngine pce, Disc disc)
 {
     this.pce = pce;
     this.disc = disc;
     subcodeReader = new SubcodeReader(disc);
 }
示例#23
0
        /// <summary>
        /// Loads a CCD at the specified path to a Disc object
        /// </summary>
        public Disc LoadCCDToDisc(string ccdPath)
        {
            var loadResults = LoadCCDPath(ccdPath);

            if (!loadResults.Valid)
            {
                throw loadResults.FailureException;
            }

            Disc disc = new Disc();

            var ccdf    = loadResults.ParsedCCDFile;
            var imgBlob = new Disc.Blob_RawFile()
            {
                PhysicalPath = loadResults.ImgPath
            };
            var subBlob = new Disc.Blob_RawFile()
            {
                PhysicalPath = loadResults.SubPath
            };

            disc.Blobs.Add(imgBlob);
            disc.Blobs.Add(subBlob);

            //generate DiscTOCRaw items from the ones specified in the CCD file
            //TODO - range validate these (too many truncations to byte)
            disc.RawTOCEntries = new List <RawTOCEntry>();
            BufferedSubcodeSector bss = new BufferedSubcodeSector();

            foreach (var entry in ccdf.TOCEntries)
            {
                var q = new SubchannelQ
                {
                    q_status = SubchannelQ.ComputeStatus(entry.ADR, (EControlQ)(entry.Control & 0xF)),
                    q_tno    = (byte)entry.TrackNo,
                    q_index  = (byte)entry.Point,
                    min      = BCD2.FromDecimal(entry.AMin),
                    sec      = BCD2.FromDecimal(entry.ASec),
                    frame    = BCD2.FromDecimal(entry.AFrame),
                    zero     = (byte)entry.Zero,
                    ap_min   = BCD2.FromDecimal(entry.PMin),
                    ap_sec   = BCD2.FromDecimal(entry.PSec),
                    ap_frame = BCD2.FromDecimal(entry.PFrame),
                };

                //CRC cant be calculated til we've got all the fields setup
                q.q_crc = bss.Synthesize_SubchannelQ(ref q, true);

                disc.RawTOCEntries.Add(new RawTOCEntry {
                    QData = q
                });
            }

            //generate the toc from the entries
            var tocSynth = new DiscTOCRaw.SynthesizeFromRawTOCEntriesJob()
            {
                Entries = disc.RawTOCEntries
            };

            tocSynth.Run();
            disc.TOCRaw = tocSynth.Result;

            //synthesize DiscStructure
            var structureSynth = new DiscStructure.SynthesizeFromDiscTOCRawJob()
            {
                TOCRaw = disc.TOCRaw
            };

            structureSynth.Run();
            disc.Structure = structureSynth.Result;

            //I *think* implicitly there is an index 0.. at.. i dunno, 0 maybe, for track 1
            {
                var dsi0 = new DiscStructure.Index();
                dsi0.LBA    = 0;
                dsi0.Number = 0;
                disc.Structure.Sessions[0].Tracks[0].Indexes.Add(dsi0);
            }

            //now, how to get the track types for the DiscStructure?
            //1. the CCD tells us (somehow the reader has judged)
            //2. scan it out of the Q subchannel
            //lets choose1.
            //TODO - better consider how to handle the situation where we have havent received all the [TRACK] items we need
            foreach (var st in disc.Structure.Sessions[0].Tracks)
            {
                var ccdt = ccdf.TracksByNumber[st.Number];
                switch (ccdt.Mode)
                {
                case 0:
                    st.TrackType = ETrackType.Audio;                             //for CCD, this means audio, apparently.
                    break;

                case 1:
                    st.TrackType = ETrackType.Mode1_2352;
                    break;

                case 2:
                    st.TrackType = ETrackType.Mode2_2352;
                    break;

                default:
                    throw new InvalidOperationException("Unsupported CCD mode");
                }

                //add indexes for this track
                foreach (var ccdi in ccdt.Indexes)
                {
                    var dsi = new DiscStructure.Index();
                    //if (ccdi.Key == 0) continue;
                    dsi.LBA    = ccdi.Value;
                    dsi.Number = ccdi.Key;
                    st.Indexes.Add(dsi);
                }
            }

            //add sectors for the lead-in, which isn't stored in the CCD file, I think
            //TODO - synthesize lead-in sectors from TOC, if the lead-in isn't available.
            //need a test case for that though.
            var leadin_sector_zero  = new Sector_Zero();
            var leadin_subcode_zero = new ZeroSubcodeSector();

            for (int i = 0; i < 150; i++)
            {
                var se = new SectorEntry(leadin_sector_zero);
                disc.Sectors.Add(se);
                se.SubcodeSector = leadin_subcode_zero;
            }

            //build the sectors:
            //set up as many sectors as we have img/sub for, even if the TOC doesnt reference them (TOC is unreliable, although the tracks should have covered it all)
            for (int i = 0; i < loadResults.NumImgSectors; i++)
            {
                var isec = new Sector_RawBlob();
                isec.Offset = ((long)i) * 2352;
                isec.Blob   = imgBlob;

                var se = new SectorEntry(isec);
                disc.Sectors.Add(se);

                var scsec = new BlobSubcodeSectorPreDeinterleaved();
                scsec.Offset     = ((long)i) * 96;
                scsec.Blob       = subBlob;
                se.SubcodeSector = scsec;
            }

            return(disc);
        }
示例#24
0
文件: Disc.cs 项目: ddugovic/RASuite
		public static Disc FromCuePath(string cuePath, CueBinPrefs prefs)
		{
			var ret = new Disc();
			ret.FromCuePathInternal(cuePath, prefs);
			ret.TOC.GeneratePoints();
			ret.PopulateQSubchannel();
			return ret;
		}
示例#25
0
 public void Install(Disc disc, Func<int, bool> condition, ISectorSynthJob2448 patch)
 {
     Parent = disc.SynthProvider;
     disc.SynthProvider = this;
     Condition = condition;
     Patch = patch;
 }
示例#26
0
 public CDAudio(Disc disc, int maxVolume = short.MaxValue)
 {
     Disc = disc;
     DiscSectorReader = new DiscSectorReader(disc);
     MaxVolume = maxVolume;
 }
示例#27
0
		public PCEngine(CoreComm comm, GameInfo game, Disc disc, object Settings, object syncSettings)
		{
			CoreComm = comm;
			CoreComm.CpuTraceAvailable = true;
			CoreComm.UsesDriveLed = true;
			systemid = "PCECD";
			Type = NecSystemType.TurboCD;
			this.disc = disc;
			this._settings = (PCESettings)Settings ?? new PCESettings();
			_syncSettings = (PCESyncSettings)syncSettings ?? new PCESyncSettings();

			GameInfo biosInfo;
			byte[] rom = CoreComm.CoreFileProvider.GetFirmwareWithGameInfo("PCECD", "Bios", true, out biosInfo,
				"PCE-CD System Card not found. Please check the BIOS settings in Config->Firmwares.");

			if (biosInfo.Status == RomStatus.BadDump)
			{
				CoreComm.ShowMessage(
					"The PCE-CD System Card you have selected is known to be a bad dump. This may cause problems playing PCE-CD games.\n\n"
					+ "It is recommended that you find a good dump of the system card. Sorry to be the bearer of bad news!");
			}
			else if (biosInfo.NotInDatabase)
			{
				CoreComm.ShowMessage(
					"The PCE-CD System Card you have selected is not recognized in our database. That might mean it's a bad dump, or isn't the correct rom.");
			}
			else if (biosInfo["BIOS"] == false)
			{
				//zeromus says: someone please write a note about how this could possibly happen.
				//it seems like this is a relic of using gameDB for storing whether something is a bios? firmwareDB should be handling it now.
				CoreComm.ShowMessage(
					"The PCE-CD System Card you have selected is not a BIOS image. You may have selected the wrong rom. FYI-Please report this to developers, I don't think this error message should happen.");
			}

			if (biosInfo["SuperSysCard"])
			{
				game.AddOption("SuperSysCard");
			}

			if (game["NeedSuperSysCard"] && game["SuperSysCard"] == false)
			{
				CoreComm.ShowMessage(
					"This game requires a version 3.0 System card and won't run with the system card you've selected. Try selecting a 3.0 System Card in the firmware configuration.");
				throw new Exception();
			}

			game.FirmwareHash = rom.HashSHA1();

			Init(game, rom);
			// the default RomStatusDetails don't do anything with Disc
			CoreComm.RomStatusDetails = string.Format("{0}\r\nDisk partial hash:{1}", game.Name, disc.GetHash());
			SetControllerButtons();
		}
示例#28
0
 public void Clear()
 {
     CurrentDisc = null;
     Queue.Clear();
 }
示例#29
0
        public static Disc FromCuePath(string cuePath, CueBinPrefs prefs)
        {
            var ret = new Disc();
            ret.FromCuePathInternal(cuePath, prefs);

            ret.Structure.Synthesize_TOCPointsFromSessions();
            ret.Synthesize_SubcodeFromStructure();
            ret.Synthesize_TOCRawFromStructure();

            //try loading SBI. make sure its done after the subcode is synthesized!
            string sbiPath = Path.ChangeExtension(cuePath, "sbi");
            if (File.Exists(sbiPath) && SBI_Format.QuickCheckISSBI(sbiPath))
            {
                var sbi = new SBI_Format().LoadSBIPath(sbiPath);
                ret.ApplySBI(sbi);
            }

            return ret;
        }
示例#30
0
 public void Enqueue(Disc disc)
 {
     Queue.Enqueue(disc);
 }
示例#31
0
文件: Disc.cs 项目: ddugovic/RASuite
		/// <summary>
		/// THIS HASNT BEEN TESTED IN A LONG TIME. DOES IT WORK?
		/// </summary>
		public static Disc FromIsoPath(string isoPath)
		{
			var ret = new Disc();
			ret.FromIsoPathInternal(isoPath);
			ret.TOC.GeneratePoints();
			ret.PopulateQSubchannel();
			return ret;
		}
示例#32
0
        void RunBizHawk()
        {
            string infile      = IN_FromPath;
            string cue_content = null;

            var cfr = new CueFileResolver();

RERUN:
            var ext = Path.GetExtension(infile).ToLowerInvariant();

            if (ext == ".iso")
            {
                //make a fake cue file to represent this iso file and rerun it as a cue
                string filebase = Path.GetFileName(infile);
                cue_content = $@"
					FILE ""{filebase}"" BINARY
						TRACK 01 MODE1/2048
							INDEX 01 00:00:00"                            ;
                infile      = Path.ChangeExtension(infile, ".cue");
                goto RERUN;
            }
            if (ext == ".cue")
            {
                //TODO - major renovation of error handling needed

                //TODO - make sure code is designed so no matter what happens, a disc is disposed in case of errors.
                //perhaps the CUE_Format2 (once renamed to something like Context) can handle that
                var cuePath    = IN_FromPath;
                var cueContext = new CUE_Context();
                cueContext.DiscMountPolicy = IN_DiscMountPolicy;

                cueContext.Resolver = cfr;
                if (!cfr.IsHardcodedResolve)
                {
                    cfr.SetBaseDirectory(Path.GetDirectoryName(infile));
                }

                //parse the cue file
                var parseJob = new ParseCueJob();
                if (cue_content == null)
                {
                    cue_content = File.ReadAllText(cuePath);
                }
                parseJob.IN_CueString = cue_content;
                bool okParse = true;
                try { parseJob.Run(parseJob); }
                catch (DiscJobAbortException) { okParse = false; parseJob.FinishLog(); }
                if (!string.IsNullOrEmpty(parseJob.OUT_Log))
                {
                    Console.WriteLine(parseJob.OUT_Log);
                }
                ConcatenateJobLog(parseJob);
                if (!okParse)
                {
                    goto DONE;
                }

                //compile the cue file:
                //includes this work: resolve required bin files and find out what it's gonna take to load the cue
                var compileJob = new CompileCueJob();
                compileJob.IN_CueContext = cueContext;
                compileJob.IN_CueFile    = parseJob.OUT_CueFile;
                bool okCompile = true;
                try { compileJob.Run(); }
                catch (DiscJobAbortException) { okCompile = false; compileJob.FinishLog(); }
                if (!string.IsNullOrEmpty(compileJob.OUT_Log))
                {
                    Console.WriteLine(compileJob.OUT_Log);
                }
                ConcatenateJobLog(compileJob);
                if (!okCompile || compileJob.OUT_ErrorLevel)
                {
                    goto DONE;
                }

                //check slow loading threshold
                if (compileJob.OUT_LoadTime > IN_SlowLoadAbortThreshold)
                {
                    Warn("Loading terminated due to slow load threshold");
                    OUT_SlowLoadAborted = true;
                    goto DONE;
                }

                //actually load it all up
                var loadJob = new LoadCueJob();
                loadJob.IN_CompileJob = compileJob;
                loadJob.Run();
                //TODO - need better handling of log output
                if (!string.IsNullOrEmpty(loadJob.OUT_Log))
                {
                    Console.WriteLine(loadJob.OUT_Log);
                }
                ConcatenateJobLog(loadJob);

                OUT_Disc = loadJob.OUT_Disc;
                //OUT_Disc.DiscMountPolicy = IN_DiscMountPolicy; //NOT SURE WE NEED THIS (only makes sense for cue probably)
            }
            else if (ext == ".ccd")
            {
                CCD_Format ccdLoader = new CCD_Format();
                OUT_Disc = ccdLoader.LoadCCDToDisc(IN_FromPath, IN_DiscMountPolicy);
            }
            else if (ext == ".mds")
            {
                MDS_Format mdsLoader = new MDS_Format();
                OUT_Disc = mdsLoader.LoadMDSToDisc(IN_FromPath, IN_DiscMountPolicy);
            }


DONE:

            //setup the lowest level synth provider
            if (OUT_Disc != null)
            {
                var sssp = new ArraySectorSynthProvider()
                {
                    Sectors  = OUT_Disc._Sectors,
                    FirstLBA = -150
                };
                OUT_Disc.SynthProvider = sssp;
            }
        }
示例#33
0
 public DiscSectorReader(Disc disc)
 {
     this.disc = disc;
 }
示例#34
0
 public ScsiCDBus(PCEngine pce, Disc disc)
 {
     this.pce = pce;
     this.disc = disc;
     DiscSectorReader = new DiscSectorReader(disc);
 }
示例#35
0
 public void Eject()
 {
     CurrentDisc = null;
 }
示例#36
0
        private static bool CompareFile(string infile, DiscInterface loadDiscInterface, DiscInterface cmpif, bool verbose, CancellationTokenSource cancelToken, StringWriter sw)
        {
            Disc srcDisc = null, dstDisc = null;

            try
            {
                bool success = false;

                sw.WriteLine("BEGIN COMPARE: {0}\nSRC {1} vs DST {2}", infile, loadDiscInterface, cmpif);

                //reload the original disc, with new policies as needed
                var dmj = new DiscMountJob(
                    fromPath: infile,
                    discMountPolicy: new DiscMountPolicy {
                    CUE_PregapContradictionModeA = cmpif != DiscInterface.MednaDisc
                },
                    discInterface: loadDiscInterface);
                dmj.Run();
                srcDisc = dmj.OUT_Disc;

                var dstDmj = new DiscMountJob(fromPath: infile, discInterface: cmpif);
                dstDmj.Run();
                dstDisc = dstDmj.OUT_Disc;

                var srcDsr = new DiscSectorReader(srcDisc);
                var dstDsr = new DiscSectorReader(dstDisc);

                var srcToc = srcDisc.TOC;
                var dstToc = dstDisc.TOC;

                var srcDataBuf = new byte[2448];
                var dstDataBuf = new byte[2448];

                void SwDumpTocOne(DiscTOC.TOCItem item)
                {
                    if (!item.Exists)
                    {
                        sw.Write("(---missing---)");
                    }
                    else
                    {
                        sw.Write("({0:X2} - {1})", (byte)item.Control, item.LBA);
                    }
                }

                void SwDumpToc(int index)
                {
                    sw.Write("SRC TOC#{0,3} ", index);
                    SwDumpTocOne(srcToc.TOCItems[index]);
                    sw.WriteLine();
                    sw.Write("DST TOC#{0,3} ", index);
                    SwDumpTocOne(dstToc.TOCItems[index]);
                    sw.WriteLine();
                }

                //verify sector count
                if (srcDisc.Session1.LeadoutLBA != dstDisc.Session1.LeadoutLBA)
                {
                    sw.Write("LeadoutTrack.LBA {0} vs {1}\n", srcDisc.Session1.LeadoutTrack.LBA, dstDisc.Session1.LeadoutTrack.LBA);
                    goto SKIPPO;
                }

                //verify TOC match
                if (srcDisc.TOC.FirstRecordedTrackNumber != dstDisc.TOC.FirstRecordedTrackNumber ||
                    srcDisc.TOC.LastRecordedTrackNumber != dstDisc.TOC.LastRecordedTrackNumber)
                {
                    sw.WriteLine("Mismatch of RecordedTrackNumbers: {0}-{1} vs {2}-{3}",
                                 srcDisc.TOC.FirstRecordedTrackNumber, srcDisc.TOC.LastRecordedTrackNumber,
                                 dstDisc.TOC.FirstRecordedTrackNumber, dstDisc.TOC.LastRecordedTrackNumber
                                 );
                    goto SKIPPO;
                }

                bool badToc = false;
                for (int t = 0; t < 101; t++)
                {
                    if (srcToc.TOCItems[t].Exists != dstToc.TOCItems[t].Exists ||
                        srcToc.TOCItems[t].Control != dstToc.TOCItems[t].Control ||
                        srcToc.TOCItems[t].LBA != dstToc.TOCItems[t].LBA
                        )
                    {
                        sw.WriteLine("Mismatch in TOCItem");
                        SwDumpToc(t);
                        badToc = true;
                    }
                }
                if (badToc)
                {
                    goto SKIPPO;
                }

                void SwDumpChunkOne(string comment, int lba, byte[] buf, int addr, int count)
                {
                    sw.Write("{0} -  ", comment);
                    for (int i = 0; i < count; i++)
                    {
                        if (i + addr >= buf.Length)
                        {
                            continue;
                        }
                        sw.Write("{0:X2}{1}", buf[addr + i], (i == count - 1) ? " " : "  ");
                    }

                    sw.WriteLine();
                }

                int[] offenders = new int[12];

                void SwDumpChunk(int lba, int dispAddr, int addr, int count, int numOffenders)
                {
                    var hashedOffenders = new HashSet <int>();

                    for (int i = 0; i < numOffenders; i++)
                    {
                        hashedOffenders.Add(offenders[i]);
                    }

                    sw.Write("                          ");
                    for (int i = 0; i < count; i++)
                    {
                        sw.Write((hashedOffenders.Contains(dispAddr + i)) ? "vvv " : "    ");
                    }

                    sw.WriteLine();
                    sw.Write("                          ");
                    for (int i = 0; i < count; i++)
                    {
                        sw.Write("{0:X3} ", dispAddr + i, (i == count - 1) ? " " : "  ");
                    }

                    sw.WriteLine();
                    sw.Write("                          ");
                    sw.Write(new string('-', count * 4));
                    sw.WriteLine();
                    SwDumpChunkOne($"SRC #{lba,6} ({new Timestamp(lba)})", lba, srcDataBuf, addr, count);
                    SwDumpChunkOne($"DST #{lba,6} ({new Timestamp(lba)})", lba, dstDataBuf, addr, count);
                }

                //verify each sector contents
                int nSectors = srcDisc.Session1.LeadoutLBA;
                for (int lba = -150; lba < nSectors; lba++)
                {
                    if (verbose)
                    {
                        if (lba % 1000 == 0)
                        {
                            Console.WriteLine("LBA {0} of {1}", lba, nSectors);
                        }
                    }

                    if (cancelToken != null)
                    {
                        if (cancelToken.Token.IsCancellationRequested)
                        {
                            return(false);
                        }
                    }

                    srcDsr.ReadLBA_2448(lba, srcDataBuf, 0);
                    dstDsr.ReadLBA_2448(lba, dstDataBuf, 0);

                    //check the header
                    for (int b = 0; b < 16; b++)
                    {
                        if (srcDataBuf[b] != dstDataBuf[b])
                        {
                            sw.WriteLine("Mismatch in sector header at byte {0}", b);
                            offenders[0] = b;
                            SwDumpChunk(lba, 0, 0, 16, 1);
                            goto SKIPPO;
                        }
                    }

                    // check userData
                    for (int b = 16; b < 2352; b++)
                    {
                        if (srcDataBuf[b] != dstDataBuf[b])
                        {
                            sw.Write("LBA {0} mismatch at userdata byte {1}; terminating sector cmp\n", lba, b);
                            goto SKIPPO;
                        }
                    }

                    // check subChannels
                    for (int c = 0, b = 2352; c < 8; c++)
                    {
                        int numOffenders = 0;
                        for (int e = 0; e < 12; e++, b++)
                        {
                            if (srcDataBuf[b] != dstDataBuf[b])
                            {
                                offenders[numOffenders++] = e;
                            }
                        }

                        if (numOffenders != 0)
                        {
                            sw.Write("LBA {0} mismatch(es) at subchannel {1}; terminating sector cmp\n", lba, (char)('P' + c));
                            SwDumpChunk(lba, 0, 2352 + c * 12, 12, numOffenders);
                            goto SKIPPO;
                        }
                    }
                }

                success = true;

SKIPPO:
                sw.WriteLine("END COMPARE");
                sw.WriteLine("-----------------------------");

                return(success);
            }
            finally
            {
                srcDisc?.Dispose();
                dstDisc?.Dispose();
            }
        }
示例#37
0
 public void Insert()
 {
     if (Queue.Count > 0)
         CurrentDisc = Queue.Peek();
 }
示例#38
0
		public DiscHasher(Disc disc)
		{
			this.disc = disc;
		}
示例#39
0
 public SubcodeReader(Disc disc)
 {
     this.disc = disc;
 }
示例#40
0
        public static void RunWithArgs(string[] args, Action <string> showComparisonResultsCallback)
        {
            bool   scanCues              = false;
            string dirArg                = null;
            string infile                = null;
            var    loadDiscInterface     = DiscInterface.BizHawk;
            var    compareDiscInterfaces = new List <DiscInterface>();
            bool   hawk      = false;
            bool   music     = false;
            bool   overwrite = false;
            int    idx       = 0;

            while (idx < args.Length)
            {
                string a  = args[idx++];
                string au = a.ToUpperInvariant();
                if (au == "LOAD")
                {
                    loadDiscInterface = (DiscInterface)Enum.Parse(typeof(DiscInterface), args[idx++], true);
                }
                else if (au == "COMPARE")
                {
                    compareDiscInterfaces.Add((DiscInterface)Enum.Parse(typeof(DiscInterface), args[idx++], true));
                }
                else if (au == "HAWK")
                {
                    hawk = true;
                }
                else if (au == "CUEDIR")
                {
                    dirArg   = args[idx++];
                    scanCues = true;
                }
                else if (au is "MUSIC")
                {
                    music = true;
                }
                else if (au is "OVERWRITE")
                {
                    overwrite = true;
                }
                else
                {
                    infile = a;
                }
            }

            if (hawk)
            {
                if (infile == null)
                {
                    return;
                }
                HawkAndWriteFile(
                    inputPath: infile,
                    errorCallback: err => Console.WriteLine($"failed to convert {infile}:\n{err}"),
                    discInterface: loadDiscInterface);
            }

            if (music)
            {
                if (infile is null)
                {
                    return;
                }
                using var disc = Disc.LoadAutomagic(infile);
                var path     = Path.GetDirectoryName(infile);
                var filename = Path.GetFileNameWithoutExtension(infile);
                bool?CheckOverwrite(string mp3Path)
                {
                    if (overwrite)
                    {
                        return(true);                               // overwrite
                    }
                    Console.WriteLine($"{mp3Path} already exists. Remove existing output files, or retry with the extra argument \"OVERWRITE\".");
                    return(null);                    // cancel
                }

                AudioExtractor.Extract(disc, path, filename, CheckOverwrite);
            }

            bool verbose = true;

            if (scanCues)
            {
                verbose = false;
                var todo = FindCuesRecurse(dirArg);
                var po   = new ParallelOptions();
                var cts  = new CancellationTokenSource();
                po.CancellationToken      = cts.Token;
                po.MaxDegreeOfParallelism = 1;
                if (po.MaxDegreeOfParallelism < 0)
                {
                    po.MaxDegreeOfParallelism = 1;
                }
                object olock   = new object();
                int    ctr     = 0;
                bool   blocked = false;
                try
                {
                    Parallel.ForEach(todo, po, (fp) =>
                    {
                        lock (olock)
                        {
                            ctr++;
                            int strlen = todo.Count.ToString().Length;
                            string fmt = string.Format("{{0,{0}}}/{{1,{0}}} {{2}}", strlen);
                            Console.WriteLine(fmt, ctr, todo.Count, Path.GetFileNameWithoutExtension(fp));
                        }

                        if (!blocked)
                        {
                            foreach (var cmpif in compareDiscInterfaces)
                            {
                                var sw       = new StringWriter();
                                bool success = CompareFile(fp, loadDiscInterface, cmpif, verbose, cts, sw);
                                if (!success)
                                {
                                    lock (Console.Out)
                                        Console.Out.Write(sw.ToString());

                                    cts.Cancel();
                                    return;
                                }
                            }
                        }
                    });
                }
                catch (AggregateException ae) {
                    Console.WriteLine(ae.ToString());
                }
                catch (OperationCanceledException oce)
                {
                    Console.WriteLine(oce.ToString());
                }
                Console.WriteLine("--TERMINATED--");
                return;
            }

            if (compareDiscInterfaces.Count != 0)
            {
                var sw = new StringWriter();
                foreach (var cmpif in compareDiscInterfaces)
                {
                    CompareFile(infile, loadDiscInterface, cmpif, verbose, null, sw);
                }

                sw.Flush();
                string results = sw.ToString();
                showComparisonResultsCallback(results);
            }
        }