Exemple #1
0
        /// <exception cref="NotSupportedException"><paramref name="view"/> is not <see cref="DiscSectorReaderPolicy.EUserData2048Mode.AssumeMode1"/> or <see cref="DiscSectorReaderPolicy.EUserData2048Mode.AssumeMode2_Form1"/></exception>
        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 {nameof(EDiscStreamView)}");
            }


            currPosition       = from_lba * SectorSize;
            cachedSector       = -1;
            cachedSectorBuffer = new byte[SectorSize];
        }
Exemple #2
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];
		}
Exemple #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;
		}
Exemple #4
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;
        }
Exemple #5
0
        public DiscIdentifier(Disc disc)
        {
            _disc = disc;
            _dsr  = new DiscSectorReader(disc);

            //the first check for mode 0 should be sufficient for blocking attempts to read audio sectors
            //but github #928 had a data track with an audio sector
            //so let's be careful here.. we're just trying to ID things, not be robust
            _dsr.Policy.ThrowExceptions2048 = false;
        }
        /// <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;
                }
            }
        }
        /// <summary>
        /// calculates the hash for quick PSX Disc identification
        /// </summary>
        public uint Calculate_PSX_BizIDHash()
        {
            //notes about the hash:
            //"Arc the Lad II (J) 1.0 and 1.1 conflict up to 25 sectors (so use 26)
            //Tekken 3 (Europe) (Alt) and Tekken 3 (Europe) conflict in track 2 and 3 unfortunately, not sure what to do about this yet
            //the TOC isn't needed!
            //but it will help detect dumps with mangled TOCs which are all too common

            CRC32 crc = new();

            byte[] buffer2352 = new byte[2352];

            var dsr = new DiscSectorReader(disc)
            {
                Policy = { DeterministicClearBuffer = false }                 // live dangerously
            };
Exemple #8
0
		// gets an identifying hash. hashes the first 512 sectors of 
		// the first data track on the disc.
		//TODO - this is a very platform-specific thing. hashing the TOC may be faster and be just as effective. so, rename it appropriately
		public string OldHash()
		{
			byte[] buffer = new byte[512 * 2352];
			DiscSectorReader dsr = new DiscSectorReader(disc);
			foreach (var track in disc.Session1.Tracks)
			{
				if (track.IsAudio)
					continue;

				int lba_len = Math.Min(track.NextTrack.LBA, 512);
				for (int s = 0; s < 512 && s < lba_len; s++)
					dsr.ReadLBA_2352(track.LBA + s, buffer, s * 2352);

				return buffer.HashMD5(0, lba_len * 2352);
			}
			return "no data track found";
		}
Exemple #9
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];
        }
Exemple #10
0
		/// <summary>
		/// calculates the complete disc hash for matching to a redump
		/// </summary>
		public uint Calculate_PSX_RedumpHash()
		{
			//a special CRC32 is used to help us match redump's DB
			SpecialCRC32 crc = new SpecialCRC32();
			byte[] buffer2352 = new byte[2352];

			var dsr = new DiscSectorReader(disc);
			dsr.Policy.DeterministicClearBuffer = false; //live dangerously

			//read all sectors for redump hash
			for (int i = 0; i < disc.Session1.LeadoutLBA; i++)
			{
				dsr.ReadLBA_2352(i, buffer2352, 0);
				crc.Add(buffer2352, 0, 2352);
			}

			return crc.Result;
		}
Exemple #11
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;
                }
            }
        }
Exemple #12
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);
				}
			}
		}
Exemple #13
0
        /// <summary>
        /// Easily extracts a mode1 sector range (suitable for extracting ISO FS data files)
        /// </summary>
        public byte[] Easy_Extract_Mode1(int lba_start, int lba_count, int byteLength = -1)
        {
            int totsize = lba_count * 2048;

            byte[] ret = new byte[totsize];
            var    dsr = new DiscSectorReader(this);

            dsr.Policy.DeterministicClearBuffer = false;
            for (int i = 0; i < lba_count; i++)
            {
                dsr.ReadLBA_2048(lba_start + i, ret, i * 2048);
            }
            if (byteLength != -1 && byteLength != totsize)
            {
                byte[] newret = new byte[byteLength];
                Array.Copy(ret, newret, byteLength);
                return(newret);
            }
            return(ret);
        }
Exemple #14
0
        /// <summary>
        /// calculates the complete disc hash for matching to a redump
        /// </summary>
        public uint Calculate_PSX_RedumpHash()
        {
            //a special CRC32 is used to help us match redump's DB
            SpecialCRC32 crc = new SpecialCRC32();

            byte[] buffer2352 = new byte[2352];

            var dsr = new DiscSectorReader(disc);

            dsr.Policy.DeterministicClearBuffer = false;             //live dangerously

            //read all sectors for redump hash
            for (int i = 0; i < disc.Session1.LeadoutLBA; i++)
            {
                dsr.ReadLBA_2352(i, buffer2352, 0);
                crc.Add(buffer2352, 0, 2352);
            }

            return(crc.Result);
        }
Exemple #15
0
        /// <summary>
        /// calculates the hash for quick PSX Disc identification
        /// </summary>
        public uint Calculate_PSX_BizIDHash()
        {
            //notes about the hash:
            //"Arc the Lad II (J) 1.0 and 1.1 conflict up to 25 sectors (so use 26)
            //Tekken 3 (Europe) (Alt) and Tekken 3 (Europe) conflict in track 2 and 3 unfortunately, not sure what to do about this yet
            //the TOC isn't needed!
            //but it will help detect dumps with mangled TOCs which are all too common
            //
            //a possibly special CRC32 is used to help us match redump's DB elsewhere

            SpecialCRC32 crc = new SpecialCRC32();

            byte[] buffer2352 = new byte[2352];

            var dsr = new DiscSectorReader(disc)
            {
                Policy = { DeterministicClearBuffer = false }                 // live dangerously
            };

            //hash the TOC
            crc.Add((int)disc.TOC.Session1Format);
            crc.Add(disc.TOC.FirstRecordedTrackNumber);
            crc.Add(disc.TOC.LastRecordedTrackNumber);
            for (int i = 1; i <= 100; i++)
            {
                //if (disc.TOC.TOCItems[i].Exists) Console.WriteLine("{0:X8} {1:X2} {2:X2} {3:X8}", crc.Current, (int)disc.TOC.TOCItems[i].Control, disc.TOC.TOCItems[i].Exists ? 1 : 0, disc.TOC.TOCItems[i].LBATimestamp.Sector); //a little debugging
                crc.Add((int)disc.TOC.TOCItems[i].Control);
                crc.Add(disc.TOC.TOCItems[i].Exists ? 1 : 0);
                crc.Add((int)disc.TOC.TOCItems[i].LBA);
            }

            //hash first 26 sectors
            for (int i = 0; i < 26; i++)
            {
                dsr.ReadLBA_2352(i, buffer2352, 0);
                crc.Add(buffer2352, 0, 2352);
            }

            return(crc.Result);
        }
Exemple #16
0
        // gets an identifying hash. hashes the first 512 sectors of
        // the first data track on the disc.
        //TODO - this is a very platform-specific thing. hashing the TOC may be faster and be just as effective. so, rename it appropriately
        public string OldHash()
        {
            byte[]           buffer = new byte[512 * 2352];
            DiscSectorReader dsr    = new DiscSectorReader(disc);

            foreach (var track in disc.Session1.Tracks)
            {
                if (track.IsAudio)
                {
                    continue;
                }

                int lba_len = Math.Min(track.NextTrack.LBA, 512);
                for (int s = 0; s < 512 && s < lba_len; s++)
                {
                    dsr.ReadLBA_2352(track.LBA + s, buffer, s * 2352);
                }

                return(buffer.HashMD5(0, lba_len * 2352));
            }
            return("no data track found");
        }
Exemple #17
0
		/// <summary>
		/// calculates the hash for quick PSX Disc identification
		/// </summary>
		public uint Calculate_PSX_BizIDHash()
		{
			//notes about the hash:
			//"Arc the Lad II (J) 1.0 and 1.1 conflict up to 25 sectors (so use 26)
			//Tekken 3 (Europe) (Alt) and Tekken 3 (Europe) conflict in track 2 and 3 unfortunately, not sure what to do about this yet
			//the TOC isn't needed!
			//but it will help detect dumps with mangled TOCs which are all too common
			//
			//a possibly special CRC32 is used to help us match redump's DB elsewhere

			SpecialCRC32 crc = new SpecialCRC32();
			byte[] buffer2352 = new byte[2352];

			var dsr = new DiscSectorReader(disc);
			dsr.Policy.DeterministicClearBuffer = false; //live dangerously

			//hash the TOC
			crc.Add((int)disc.TOC.Session1Format);
			crc.Add(disc.TOC.FirstRecordedTrackNumber);
			crc.Add(disc.TOC.LastRecordedTrackNumber);
			for (int i = 1; i <= 100; i++)
			{
				//if (disc.TOC.TOCItems[i].Exists) Console.WriteLine("{0:X8} {1:X2} {2:X2} {3:X8}", crc.Current, (int)disc.TOC.TOCItems[i].Control, disc.TOC.TOCItems[i].Exists ? 1 : 0, disc.TOC.TOCItems[i].LBATimestamp.Sector); //a little debugging
				crc.Add((int)disc.TOC.TOCItems[i].Control);
				crc.Add(disc.TOC.TOCItems[i].Exists ? 1 : 0);
				crc.Add((int)disc.TOC.TOCItems[i].LBA);
			}

			//hash first 26 sectors
			for (int i = 0; i < 26; i++)
			{
				dsr.ReadLBA_2352(i, buffer2352, 0);
				crc.Add(buffer2352, 0, 2352);
			}

			return crc.Result;
		}
Exemple #18
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, don't 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);
            }
        }
Exemple #19
0
 public CDAudio(Disc disc, int maxVolume = short.MaxValue)
 {
     Disc = disc;
     DiscSectorReader = new DiscSectorReader(disc);
     MaxVolume = maxVolume;
 }
Exemple #20
0
        /// <exception cref="InvalidOperationException">first track of <see cref="TOCRaw"/> is not <c>1</c></exception>
        public void Run()
        {
            var dsr = new DiscSectorReader(IN_Disc)
            {
                Policy = { DeterministicClearBuffer = false }
            };

            Result = new DiscStructure();
            var session = new DiscStructure.Session();

            Result.Sessions.Add(null);             //placeholder session for reindexing
            Result.Sessions.Add(session);

            session.Number = 1;

            if (TOCRaw.FirstRecordedTrackNumber != 1)
            {
                throw new InvalidOperationException($"Unsupported: {nameof(TOCRaw.FirstRecordedTrackNumber)} != 1");
            }

            //add a lead-in track
            session.Tracks.Add(new DiscStructure.Track
            {
                Number  = 0,
                Control = EControlQ.None,                   //we'll set this later
                LBA     = -new Timestamp(99, 99, 99).Sector //obvious garbage
            });

            int ntracks = TOCRaw.LastRecordedTrackNumber - TOCRaw.FirstRecordedTrackNumber + 1;

            for (int i = 0; i < ntracks; i++)
            {
                var item  = TOCRaw.TOCItems[i + 1];
                var track = new DiscStructure.Track
                {
                    Number  = i + 1,
                    Control = item.Control,
                    LBA     = item.LBA
                };
                session.Tracks.Add(track);

                if (!item.IsData)
                {
                    track.Mode = 0;
                }
                else
                {
                    //determine the mode by a hardcoded heuristic: check mode of first sector
                    track.Mode = dsr.ReadLBA_Mode(track.LBA);
                }

                //determine track length according to... how? It isn't clear.
                //Let's not do this until it's needed.
                //if (i == ntracks - 1)
                //  track.Length = TOCRaw.LeadoutLBA.Sector - track.LBA;
                //else track.Length = (TOCRaw.TOCItems[i + 2].LBATimestamp.Sector - track.LBA);
            }

            //add lead-out track
            session.Tracks.Add(new DiscStructure.Track
            {
                Number = 0xA0,                 //right?
                //kind of a guess, but not completely
                Control = session.Tracks[session.Tracks.Count - 1].Control,
                Mode    = session.Tracks[session.Tracks.Count - 1].Mode,
                LBA     = TOCRaw.LeadoutLBA
            });

            //link track list
            for (int i = 0; i < session.Tracks.Count - 1; i++)
            {
                session.Tracks[i].NextTrack = session.Tracks[i + 1];
            }

            //fix lead-in track type
            //guesses:
            session.Tracks[0].Control = session.Tracks[1].Control;
            session.Tracks[0].Mode    = session.Tracks[1].Mode;
        }
Exemple #21
0
        public void Think()
        {
            if (RST)
            {
                ResetDevice();
                return;
            }

            if (DataReadInProgress && pce.Cpu.TotalExecutedCycles > DataReadWaitTimer)
            {
                if (SectorsLeftToRead > 0)
                    pce.DriveLightOn = true;

                if (DataIn.Count == 0)
                {
                    // read in a sector and shove it in the queue
                    DiscSystem.DiscSectorReader dsr = new DiscSectorReader(disc); //TODO - cache reader
                    dsr.ReadLBA_2048(CurrentReadingSector, DataIn.GetBuffer(), 0);
                    DataIn.SignalBufferFilled(2048);
                    CurrentReadingSector++;
                    SectorsLeftToRead--;

                    pce.IntDataTransferReady = true;

                    // If more sectors, should set the next think-clock to however long it takes to read 1 sector
                    // but I dont. I dont think transfers actually happen sector by sector
                    // like this, they probably become available as the bits come off the disc.
                    // but lets get some basic functionality before we go crazy.
                    //  Idunno, maybe they do come in a sector at a time.

                    //note to vecna: maybe not at the sector level, but at a level > 1 sample and <= 1 sector, samples come out in blocks
                    //due to the way they are jumbled up (seriously, like put into a blender) for error correction purposes.
                    //we may as well assume that the cd audio decoding magic works at the level of one sector, but it isnt one sample.

                    if (SectorsLeftToRead == 0)
                    {
                        DataReadInProgress = false;
                        DataTransferWasDone = true;
                    }
                    SetPhase(BusPhase_DataIn);
                }
            }

            do
            {
                signalsChanged = false;
                busPhaseChanged = false;

                if (SEL && !BSY)
                {
                    SetPhase(BusPhase_Command);
                }
                else if (ATN && !REQ && !ACK)
                {
                    SetPhase(BusPhase_MessageOut);
                }
                else switch (Phase)
                    {
                        case BusPhase_Command: ThinkCommandPhase(); break;
                        case BusPhase_DataIn: ThinkDataInPhase(); break;
                        case BusPhase_DataOut: ThinkDataOutPhase(); break;
                        case BusPhase_MessageIn: ThinkMessageInPhase(); break;
                        case BusPhase_MessageOut: ThinkMessageOutPhase(); break;
                        case BusPhase_Status: ThinkStatusPhase(); break;
                        default: break;
                    }
            } while (signalsChanged || busPhaseChanged);
        }
        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();
            }
        }
Exemple #23
0
 public DiscIdentifier(Disc disc)
 {
     this.disc = disc;
     dsr = new DiscSectorReader(disc);
 }
Exemple #24
0
 public ScsiCDBus(PCEngine pce, Disc disc)
 {
     this.pce = pce;
     this.disc = disc;
     DiscSectorReader = new DiscSectorReader(disc);
 }
		public void Run()
		{
			var dsr = new DiscSectorReader(IN_Disc);
			dsr.Policy.DeterministicClearBuffer = false;

			Result = new DiscStructure();
			var session = new DiscStructure.Session();
			Result.Sessions.Add(null); //placeholder session for reindexing
			Result.Sessions.Add(session);

			session.Number = 1;

			if (TOCRaw.FirstRecordedTrackNumber != 1)
				throw new InvalidOperationException("Unsupported: FirstRecordedTrackNumber != 1");

			//add a lead-in track
			session.Tracks.Add(new DiscStructure.Track()
			{
				Number = 0,
				Control = EControlQ.None, //we'll set this later
				LBA = -new Timestamp(99,99,99).Sector //obvious garbage
			});

			int ntracks = TOCRaw.LastRecordedTrackNumber - TOCRaw.FirstRecordedTrackNumber + 1;
			for (int i = 0; i < ntracks; i++)
			{
				var item = TOCRaw.TOCItems[i + 1];
				var track = new DiscStructure.Track()
				{
					Number = i + 1,
					Control = item.Control,
					LBA = item.LBA
				};
				session.Tracks.Add(track);

				if (!item.IsData)
					track.Mode = 0;
				else
				{
					//determine the mode by a hardcoded heuristic: check mode of first sector
					track.Mode = dsr.ReadLBA_Mode(track.LBA);
				}

				//determine track length according to... how? It isn't clear.
				//Let's not do this until it's needed.
				//if (i == ntracks - 1)
				//  track.Length = TOCRaw.LeadoutLBA.Sector - track.LBA;
				//else track.Length = (TOCRaw.TOCItems[i + 2].LBATimestamp.Sector - track.LBA);
			}

			//add lead-out track
			session.Tracks.Add(new DiscStructure.Track()
			{
				Number = 0xA0, //right?
				//kind of a guess, but not completely
				Control = session.Tracks[session.Tracks.Count -1 ].Control,
				Mode = session.Tracks[session.Tracks.Count - 1].Mode,
				LBA = TOCRaw.LeadoutLBA
			});

			//link track list 
			for (int i = 0; i < session.Tracks.Count - 1; i++)
			{
				session.Tracks[i].NextTrack = session.Tracks[i + 1];
			}

			//fix lead-in track type
			//guesses:
			session.Tracks[0].Control = session.Tracks[1].Control;
			session.Tracks[0].Mode = session.Tracks[1].Mode;
		}
Exemple #26
0
        static bool CompareFile(string infile, DiscInterface loadDiscInterface, DiscInterface cmpif, bool verbose, CancellationTokenSource cancelToken, StringWriter sw)
        {
            Disc src_disc = null, dst_disc = 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 { IN_DiscInterface = loadDiscInterface, IN_FromPath = infile };
                if (cmpif == DiscInterface.MednaDisc)
                {
                    dmj.IN_DiscMountPolicy.CUE_PregapContradictionModeA = false;
                }
                dmj.Run();

                src_disc = dmj.OUT_Disc;

                var dst_dmj = new DiscMountJob { IN_DiscInterface = cmpif, IN_FromPath = infile };
                dst_dmj.Run();
                dst_disc = dst_dmj.OUT_Disc;

                var src_dsr = new DiscSectorReader(src_disc);
                var dst_dsr = new DiscSectorReader(dst_disc);

                var src_toc = src_disc.TOC;
                var dst_toc = dst_disc.TOC;

                var src_databuf = new byte[2448];
                var dst_databuf = new byte[2448];

                Action<DiscTOC.TOCItem> sw_dump_toc_one = (item) =>
                {
                    if (!item.Exists)
                        sw.Write("(---missing---)");
                    else
                        sw.Write("({0:X2} - {1})", (byte)item.Control, item.LBA);
                };

                Action<int> sw_dump_toc = (index) =>
                {
                    sw.Write("SRC TOC#{0,3} ", index); sw_dump_toc_one(src_toc.TOCItems[index]); sw.WriteLine();
                    sw.Write("DST TOC#{0,3} ", index); sw_dump_toc_one(dst_toc.TOCItems[index]); sw.WriteLine();
                };

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

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

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

                Action<string, int, byte[], int, int> sw_dump_chunk_one = (comment, lba, buf, addr, 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];
                Action<int, int, int, int, int> sw_dump_chunk = (lba, dispaddr, addr, count, 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();
                    sw_dump_chunk_one(string.Format("SRC #{0,6} ({1})", lba, new Timestamp(lba)), lba, src_databuf, addr, count);
                    sw_dump_chunk_one(string.Format("DST #{0,6} ({1})", lba, new Timestamp(lba)), lba, dst_databuf, addr, count);
                };

                //verify each sector contents
                int nSectors = src_disc.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;

                    src_dsr.ReadLBA_2448(lba, src_databuf, 0);
                    dst_dsr.ReadLBA_2448(lba, dst_databuf, 0);

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

                    //check userdata
                    for (int b = 16; b < 2352; b++)
                    {
                        if (src_databuf[b] != dst_databuf[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 (src_databuf[b] != dst_databuf[b])
                            {
                                offenders[numOffenders++] = e;
                            }
                        }
                        if (numOffenders != 0)
                        {
                            sw.Write("LBA {0} mismatch(es) at subchannel {1}; terminating sector cmp\n", lba, (char)('P' + c));
                            sw_dump_chunk(lba, 0, 2352 + c * 12, 12, numOffenders);
                            goto SKIPPO;
                        }
                    }
                }

                success = true;

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

                return success;
            }
            finally
            {
                if (src_disc != null)
                    src_disc.Dispose();
                if (dst_disc != null)
                    dst_disc.Dispose();
            }
        }