public bool Close() { if (!IsWriting) { ErrorMessage = "Image is not opened for writing"; return(false); } byte sessions = byte.MinValue; foreach (CommonTypes.Structs.Track t in _writingTracks.Where(t => t.TrackSession > byte.MinValue)) { sessions = (byte)t.TrackSession; } var header = new Header { signature = _alcoholSignature, version = new byte[] { 1, 5 }, type = MediaTypeToMediumType(_imageInfo.MediaType), sessions = sessions, structuresOffset = (uint)(_pfi == null ? 0 : 96), sessionOffset = (uint)(_pfi == null ? 96 : 4196), unknown1 = new ushort[2], unknown2 = new uint[2], unknown3 = new uint[6], unknown4 = new uint[3] }; // Alcohol sets this always, Daemon Tool expects this header.unknown1[0] = 2; _alcSessions = new Dictionary <int, Session>(); _alcTracks = new Dictionary <int, Track>(); _alcToc = new Dictionary <int, Dictionary <int, Track> >(); _writingTracks = _writingTracks.OrderBy(t => t.TrackSession).ThenBy(t => t.TrackSequence).ToList(); _alcTrackExtras = new Dictionary <int, TrackExtra>(); long currentTrackOffset = header.sessionOffset + (Marshal.SizeOf <Session>() * sessions); byte[] tmpToc = null; if (_fullToc != null) { byte[] fullTocSize = BigEndianBitConverter.GetBytes((short)_fullToc.Length); tmpToc = new byte[_fullToc.Length + 2]; Array.Copy(_fullToc, 0, tmpToc, 2, _fullToc.Length); tmpToc[0] = fullTocSize[0]; tmpToc[1] = fullTocSize[1]; } FullTOC.CDFullTOC?decodedToc = FullTOC.Decode(tmpToc); long currentExtraOffset = currentTrackOffset; int extraCount = 0; for (int i = 1; i <= sessions; i++) { if (decodedToc.HasValue) { extraCount += decodedToc.Value.TrackDescriptors.Count(t => t.SessionNumber == i); currentExtraOffset += Marshal.SizeOf <Track>() * decodedToc.Value.TrackDescriptors.Count(t => t.SessionNumber == i); } else { currentExtraOffset += Marshal.SizeOf <Track>() * 3; extraCount += 3; currentExtraOffset += Marshal.SizeOf <Track>() * _writingTracks.Count(t => t.TrackSession == i); extraCount += _writingTracks.Count(t => t.TrackSession == i); if (i < sessions) { currentExtraOffset += Marshal.SizeOf <Track>() * 2; extraCount += 2; } } } long footerOffset = currentExtraOffset + (Marshal.SizeOf <TrackExtra>() * extraCount); if (_bca != null) { header.bcaOffset = (uint)footerOffset; footerOffset += _bca.Length; } if (_isDvd) { _alcSessions.Add(1, new Session { sessionEnd = (int)((_writingTracks[0].TrackEndSector - _writingTracks[0].TrackStartSector) + 1), sessionSequence = 1, allBlocks = 1, nonTrackBlocks = 3, firstTrack = 1, lastTrack = 1, trackOffset = 4220 }); footerOffset = 4300; if (_bca != null) { footerOffset += _bca.Length; } _alcTracks.Add(1, new Track { mode = TrackMode.DVD, adrCtl = 20, point = 1, extraOffset = (uint)((_writingTracks[0].TrackEndSector - _writingTracks[0].TrackStartSector) + 1), sectorSize = 2048, files = 1, footerOffset = (uint)footerOffset, unknown = new byte[18], unknown2 = new byte[24] }); _alcToc.Add(1, _alcTracks); } else { for (int i = 1; i <= sessions; i++) { CommonTypes.Structs.Track firstTrack = _writingTracks.First(t => t.TrackSession == i); CommonTypes.Structs.Track lastTrack = _writingTracks.Last(t => t.TrackSession == i); _alcSessions.Add(i, new Session { sessionStart = (int)firstTrack.TrackStartSector - 150, sessionEnd = (int)lastTrack.TrackEndSector + 1, sessionSequence = (ushort)i, allBlocks = (byte)(decodedToc?.TrackDescriptors.Count(t => t.SessionNumber == i) ?? _writingTracks.Count(t => t.TrackSession == i) + 3), nonTrackBlocks = (byte)(decodedToc?.TrackDescriptors.Count(t => t.SessionNumber == i && t.POINT >= 0xA0 && t.POINT <= 0xAF) ?? 3), firstTrack = (ushort)firstTrack.TrackSequence, lastTrack = (ushort)lastTrack.TrackSequence, trackOffset = (uint)currentTrackOffset }); Dictionary <int, Track> thisSessionTracks = new Dictionary <int, Track>(); _trackFlags.TryGetValue((byte)firstTrack.TrackSequence, out byte firstTrackControl); _trackFlags.TryGetValue((byte)lastTrack.TrackSequence, out byte lastTrackControl); if (firstTrackControl == 0 && firstTrack.TrackType != TrackType.Audio) { firstTrackControl = (byte)CdFlags.DataTrack; } if (lastTrackControl == 0 && lastTrack.TrackType != TrackType.Audio) { lastTrackControl = (byte)CdFlags.DataTrack; } (byte minute, byte second, byte frame)leadinPmsf = LbaToMsf(lastTrack.TrackEndSector + 1); if (decodedToc?.TrackDescriptors.Any(t => t.SessionNumber == i && t.POINT >= 0xA0 && t.POINT <= 0xAF) == true) { foreach (FullTOC.TrackDataDescriptor tocTrk in decodedToc.Value.TrackDescriptors.Where(t => t.SessionNumber == i && t.POINT >= 0xA0 && t.POINT <= 0xAF)) { thisSessionTracks.Add(tocTrk.POINT, new Track { adrCtl = (byte)((tocTrk.ADR << 4) + tocTrk.CONTROL), tno = tocTrk.TNO, point = tocTrk.POINT, min = tocTrk.Min, sec = tocTrk.Sec, frame = tocTrk.Frame, zero = tocTrk.Zero, pmin = tocTrk.PMIN, psec = tocTrk.PSEC, pframe = tocTrk.PFRAME, mode = TrackMode.NoData, unknown = new byte[18], unknown2 = new byte[24], extraOffset = (uint)currentExtraOffset }); currentTrackOffset += Marshal.SizeOf <Track>(); currentExtraOffset += Marshal.SizeOf <TrackExtra>(); } } else { thisSessionTracks.Add(0xA0, new Track { adrCtl = (byte)((1 << 4) + firstTrackControl), pmin = (byte)firstTrack.TrackSequence, mode = TrackMode.NoData, point = 0xA0, unknown = new byte[18], unknown2 = new byte[24], psec = (byte)(_imageInfo.MediaType == MediaType.CDI ? 0x10 : _writingTracks.Any(t => t.TrackType == TrackType.CdMode2Form1 || t.TrackType == TrackType.CdMode2Form2 || t.TrackType == TrackType.CdMode2Formless) ? 0x20 : 0), extraOffset = (uint)currentExtraOffset }); thisSessionTracks.Add(0xA1, new Track { adrCtl = (byte)((1 << 4) + lastTrackControl), pmin = (byte)lastTrack.TrackSequence, mode = TrackMode.NoData, point = 0xA1, unknown = new byte[18], unknown2 = new byte[24], extraOffset = (uint)currentExtraOffset }); thisSessionTracks.Add(0xA2, new Track { adrCtl = (byte)((1 << 4) + firstTrackControl), zero = 0, pmin = leadinPmsf.minute, psec = leadinPmsf.second, pframe = leadinPmsf.frame, mode = TrackMode.NoData, point = 0xA2, unknown = new byte[18], unknown2 = new byte[24], extraOffset = (uint)currentExtraOffset }); currentExtraOffset += Marshal.SizeOf <TrackExtra>() * 3; currentTrackOffset += Marshal.SizeOf <Track>() * 3; } foreach (CommonTypes.Structs.Track track in _writingTracks.Where(t => t.TrackSession == i). OrderBy(t => t.TrackSequence)) { var alcTrk = new Track(); if (decodedToc?.TrackDescriptors.Any(t => t.SessionNumber == i && t.POINT == track.TrackSequence) == true) { FullTOC.TrackDataDescriptor tocTrk = decodedToc.Value.TrackDescriptors.First(t => t.SessionNumber == i && t.POINT == track.TrackSequence); alcTrk.adrCtl = (byte)((tocTrk.ADR << 4) + tocTrk.CONTROL); alcTrk.tno = tocTrk.TNO; alcTrk.point = tocTrk.POINT; alcTrk.min = tocTrk.Min; alcTrk.sec = tocTrk.Sec; alcTrk.frame = tocTrk.Frame; alcTrk.zero = tocTrk.Zero; alcTrk.pmin = tocTrk.PMIN; alcTrk.psec = tocTrk.PSEC; alcTrk.pframe = tocTrk.PFRAME; } else { (byte minute, byte second, byte frame)msf = LbaToMsf(track.TrackStartSector); _trackFlags.TryGetValue((byte)track.TrackSequence, out byte trackControl); if (trackControl == 0 && track.TrackType != TrackType.Audio) { trackControl = (byte)CdFlags.DataTrack; } alcTrk.adrCtl = (byte)((1 << 4) + trackControl); alcTrk.point = (byte)track.TrackSequence; alcTrk.zero = 0; alcTrk.pmin = msf.minute; alcTrk.psec = msf.second; alcTrk.pframe = msf.frame; } alcTrk.mode = TrackTypeToTrackMode(track.TrackType); alcTrk.subMode = track.TrackSubchannelType != TrackSubchannelType.None ? SubchannelMode.Interleaved : SubchannelMode.None; alcTrk.sectorSize = (ushort)(track.TrackRawBytesPerSector + (track.TrackSubchannelType != TrackSubchannelType.None ? 96 : 0)); alcTrk.startLba = (uint)(track.TrackStartSector + track.TrackPregap); alcTrk.startOffset = track.TrackFileOffset + (alcTrk.sectorSize * track.TrackPregap); alcTrk.files = 1; alcTrk.extraOffset = (uint)currentExtraOffset; alcTrk.footerOffset = (uint)footerOffset; if (track.TrackSequence == firstTrack.TrackSequence && track.TrackSequence > 1) { alcTrk.startLba -= 150; alcTrk.startOffset -= (ulong)(alcTrk.sectorSize * 150); } // Alcohol seems to set that for all CD tracks // Daemon Tools expect it to be like this alcTrk.unknown = new byte[] { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; alcTrk.unknown2 = new byte[24]; thisSessionTracks.Add((int)track.TrackSequence, alcTrk); currentTrackOffset += Marshal.SizeOf <Track>(); currentExtraOffset += Marshal.SizeOf <TrackExtra>(); var trkExtra = new TrackExtra { sectors = (uint)((track.TrackEndSector - track.TrackStartSector) + 1) }; if (track.TrackSequence == firstTrack.TrackSequence) { trkExtra.pregap = 150; } // When track mode changes there's a mandatory gap, Alcohol needs it else if (thisSessionTracks.TryGetValue((int)(track.TrackSequence - 1), out Track previousTrack) && _alcTrackExtras.TryGetValue((int)(track.TrackSequence - 1), out TrackExtra previousExtra) && previousTrack.mode != alcTrk.mode) { previousExtra.sectors -= 150; trkExtra.pregap = 150; _alcTrackExtras.Remove((int)(track.TrackSequence - 1)); _alcTrackExtras.Add((int)(track.TrackSequence - 1), previousExtra); } else { trkExtra.pregap = 0; } _alcTrackExtras.Add((int)track.TrackSequence, trkExtra); } if (decodedToc?.TrackDescriptors.Any(t => t.SessionNumber == i && t.POINT >= 0xB0) == true) { foreach (FullTOC.TrackDataDescriptor tocTrk in decodedToc.Value.TrackDescriptors.Where(t => t.SessionNumber == i && t.POINT >= 0xB0)) { thisSessionTracks.Add(tocTrk.POINT, new Track { adrCtl = (byte)((tocTrk.ADR << 4) + tocTrk.CONTROL), tno = tocTrk.TNO, point = tocTrk.POINT, min = tocTrk.Min, sec = tocTrk.Sec, frame = tocTrk.Frame, zero = tocTrk.Zero, pmin = tocTrk.PMIN, psec = tocTrk.PSEC, pframe = tocTrk.PFRAME, mode = TrackMode.NoData, unknown = new byte[18], unknown2 = new byte[24], extraOffset = (uint)currentExtraOffset }); currentExtraOffset += Marshal.SizeOf <TrackExtra>(); currentTrackOffset += Marshal.SizeOf <Track>(); } } else if (i < sessions) { (byte minute, byte second, byte frame)leadoutAmsf = LbaToMsf(_writingTracks.First(t => t.TrackSession == i + 1).TrackStartSector - 150); (byte minute, byte second, byte frame)leadoutPmsf = LbaToMsf(_writingTracks.OrderBy(t => t.TrackSession).ThenBy(t => t.TrackSequence).Last(). TrackStartSector); thisSessionTracks.Add(0xB0, new Track { point = 0xB0, adrCtl = 0x50, zero = 0, min = leadoutAmsf.minute, sec = leadoutAmsf.second, frame = leadoutAmsf.frame, pmin = leadoutPmsf.minute, psec = leadoutPmsf.second, pframe = leadoutPmsf.frame, unknown = new byte[18], unknown2 = new byte[24] }); thisSessionTracks.Add(0xC0, new Track { point = 0xC0, adrCtl = 0x50, min = 128, pmin = 97, psec = 25, unknown = new byte[18], unknown2 = new byte[24] }); currentTrackOffset += Marshal.SizeOf <Track>() * 2; } _alcToc.Add(i, thisSessionTracks); } } _alcFooter = new Footer { filenameOffset = (uint)(footerOffset + Marshal.SizeOf <Footer>()), widechar = 1 }; byte[] filename = Encoding.Unicode.GetBytes("*.mdf"); // Yup, Alcohol stores no filename but a wildcard. // Write header _descriptorStream.Seek(0, SeekOrigin.Begin); byte[] block = new byte[Marshal.SizeOf <Header>()]; IntPtr blockPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(Marshal.SizeOf <Header>()); System.Runtime.InteropServices.Marshal.StructureToPtr(header, blockPtr, true); System.Runtime.InteropServices.Marshal.Copy(blockPtr, block, 0, block.Length); System.Runtime.InteropServices.Marshal.FreeHGlobal(blockPtr); _descriptorStream.Write(block, 0, block.Length); // Write DVD structures if present if (header.structuresOffset != 0) { if (_dmi != null) { _descriptorStream.Seek(header.structuresOffset, SeekOrigin.Begin); switch (_dmi.Length) { case 2052: _descriptorStream.Write(_dmi, 0, 2052); break; case 2048: _descriptorStream.Write(new byte[] { 0x08, 0x02, 0x00, 0x00 }, 0, 4); _descriptorStream.Write(_dmi, 0, 2048); break; } } // TODO: Create fake PFI if none present if (_pfi != null) { _descriptorStream.Seek(header.structuresOffset + 2052, SeekOrigin.Begin); _descriptorStream.Write(_pfi, _pfi.Length - 2048, 2048); } } // Write sessions _descriptorStream.Seek(header.sessionOffset, SeekOrigin.Begin); foreach (Session session in _alcSessions.Values) { block = new byte[Marshal.SizeOf <Session>()]; blockPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(Marshal.SizeOf <Session>()); System.Runtime.InteropServices.Marshal.StructureToPtr(session, blockPtr, true); System.Runtime.InteropServices.Marshal.Copy(blockPtr, block, 0, block.Length); System.Runtime.InteropServices.Marshal.FreeHGlobal(blockPtr); _descriptorStream.Write(block, 0, block.Length); } // Write tracks foreach (KeyValuePair <int, Dictionary <int, Track> > kvp in _alcToc) { _descriptorStream.Seek(_alcSessions.First(t => t.Key == kvp.Key).Value.trackOffset, SeekOrigin.Begin); foreach (Track track in kvp.Value.Values) { Track alcoholTrack = track; // Write extra if (!_isDvd) { long position = _descriptorStream.Position; _descriptorStream.Seek(alcoholTrack.extraOffset, SeekOrigin.Begin); block = new byte[Marshal.SizeOf <TrackExtra>()]; if (_alcTrackExtras.TryGetValue(alcoholTrack.point, out TrackExtra extra)) { blockPtr = System.Runtime.InteropServices.Marshal. AllocHGlobal(Marshal.SizeOf <TrackExtra>()); System.Runtime.InteropServices.Marshal.StructureToPtr(extra, blockPtr, true); System.Runtime.InteropServices.Marshal.Copy(blockPtr, block, 0, block.Length); System.Runtime.InteropServices.Marshal.FreeHGlobal(blockPtr); } else { alcoholTrack.extraOffset = 0; } _descriptorStream.Write(block, 0, block.Length); _descriptorStream.Seek(position, SeekOrigin.Begin); } block = new byte[Marshal.SizeOf <Track>()]; blockPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(Marshal.SizeOf <Track>()); System.Runtime.InteropServices.Marshal.StructureToPtr(alcoholTrack, blockPtr, true); System.Runtime.InteropServices.Marshal.Copy(blockPtr, block, 0, block.Length); System.Runtime.InteropServices.Marshal.FreeHGlobal(blockPtr); _descriptorStream.Write(block, 0, block.Length); } } // Write BCA if (_bca != null) { _descriptorStream.Seek(header.bcaOffset, SeekOrigin.Begin); _descriptorStream.Write(_bca, 0, _bca.Length); } // Write footer _descriptorStream.Seek(footerOffset, SeekOrigin.Begin); block = new byte[Marshal.SizeOf <Footer>()]; blockPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(Marshal.SizeOf <Footer>()); System.Runtime.InteropServices.Marshal.StructureToPtr(_alcFooter, blockPtr, true); System.Runtime.InteropServices.Marshal.Copy(blockPtr, block, 0, block.Length); System.Runtime.InteropServices.Marshal.FreeHGlobal(blockPtr); _descriptorStream.Write(block, 0, block.Length); // Write filename _descriptorStream.Write(filename, 0, filename.Length); // Write filename null termination _descriptorStream.Write(new byte[] { 0, 0 }, 0, 2); _descriptorStream.Flush(); _descriptorStream.Close(); _imageStream.Flush(); _imageStream.Close(); IsWriting = false; ErrorMessage = ""; return(true); }
static void ReadLeadOutUsingTrapDisc(string devPath, Device dev) { string strDev; int item; bool tocIsNotBcd = false; bool sense; byte[] buffer; byte[] senseBuffer; int retries; start: System.Console.Clear(); AaruConsole.WriteLine("Ejecting disc..."); dev.AllowMediumRemoval(out _, dev.Timeout, out _); dev.EjectTray(out _, dev.Timeout, out _); AaruConsole.WriteLine("Please insert a data only disc inside..."); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadLine(); AaruConsole.WriteLine("Sending READ FULL TOC to the device..."); retries = 0; do { retries++; sense = dev.ScsiTestUnitReady(out senseBuffer, dev.Timeout, out _); if (!sense) { break; } DecodedSense?decodedSense = Sense.Decode(senseBuffer); if (decodedSense.Value.ASC != 0x04) { break; } if (decodedSense.Value.ASCQ != 0x01) { break; } Thread.Sleep(2000); } while(retries < 25); sense = dev.ReadRawToc(out buffer, out senseBuffer, 1, dev.Timeout, out _); if (sense) { AaruConsole.WriteLine("READ FULL TOC failed..."); AaruConsole.WriteLine("{0}", Sense.PrettifySense(senseBuffer)); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadLine(); return; } FullTOC.CDFullTOC?decodedToc = FullTOC.Decode(buffer); if (decodedToc is null) { AaruConsole.WriteLine("Could not decode TOC..."); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadLine(); return; } FullTOC.CDFullTOC toc = decodedToc.Value; FullTOC.TrackDataDescriptor leadOutTrack = toc.TrackDescriptors.FirstOrDefault(t => t.POINT == 0xA2); if (leadOutTrack.POINT != 0xA2) { AaruConsole.WriteLine("Cannot find lead-out..."); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadLine(); return; } int min = ((leadOutTrack.PMIN >> 4) * 10) + (leadOutTrack.PMIN & 0x0F); int sec = ((leadOutTrack.PSEC >> 4) * 10) + (leadOutTrack.PSEC & 0x0F); int frame = ((leadOutTrack.PFRAME >> 4) * 10) + (leadOutTrack.PFRAME & 0x0F); int sectors = (min * 60 * 75) + (sec * 75) + frame - 150; AaruConsole.WriteLine("Data disc shows {0} sectors...", sectors); AaruConsole.WriteLine("Ejecting disc..."); dev.AllowMediumRemoval(out _, dev.Timeout, out _); dev.EjectTray(out _, dev.Timeout, out _); AaruConsole.WriteLine("Please insert the trap disc inside..."); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadLine(); AaruConsole.WriteLine("Sending READ FULL TOC to the device..."); retries = 0; do { retries++; sense = dev.ScsiTestUnitReady(out senseBuffer, dev.Timeout, out _); if (!sense) { break; } DecodedSense?decodedSense = Sense.Decode(senseBuffer); if (decodedSense.Value.ASC != 0x04) { break; } if (decodedSense.Value.ASCQ != 0x01) { break; } Thread.Sleep(2000); } while(retries < 25); sense = dev.ReadRawToc(out buffer, out senseBuffer, 1, dev.Timeout, out _); if (sense) { AaruConsole.WriteLine("READ FULL TOC failed..."); AaruConsole.WriteLine("{0}", Sense.PrettifySense(senseBuffer)); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadLine(); return; } decodedToc = FullTOC.Decode(buffer); if (decodedToc is null) { AaruConsole.WriteLine("Could not decode TOC..."); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadLine(); return; } toc = decodedToc.Value; leadOutTrack = toc.TrackDescriptors.FirstOrDefault(t => t.POINT == 0xA2); if (leadOutTrack.POINT != 0xA2) { AaruConsole.WriteLine("Cannot find lead-out..."); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadLine(); return; } min = 0; if (leadOutTrack.PMIN == 122) { tocIsNotBcd = true; } if (leadOutTrack.PMIN >= 0xA0 && !tocIsNotBcd) { min += 90; leadOutTrack.PMIN -= 0x90; } if (tocIsNotBcd) { min = leadOutTrack.PMIN; sec = leadOutTrack.PSEC; frame = leadOutTrack.PFRAME; } else { min += ((leadOutTrack.PMIN >> 4) * 10) + (leadOutTrack.PMIN & 0x0F); sec = ((leadOutTrack.PSEC >> 4) * 10) + (leadOutTrack.PSEC & 0x0F); frame = ((leadOutTrack.PFRAME >> 4) * 10) + (leadOutTrack.PFRAME & 0x0F); } int trapSectors = (min * 60 * 75) + (sec * 75) + frame - 150; AaruConsole.WriteLine("Trap disc shows {0} sectors...", trapSectors); if (trapSectors < sectors + 100) { AaruConsole.WriteLine("Trap disc doesn't have enough sectors..."); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadLine(); return; } AaruConsole.WriteLine("Stopping motor..."); dev.StopUnit(out _, dev.Timeout, out _); AaruConsole.WriteLine("Please MANUALLY get the trap disc out and put the data disc back inside..."); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadLine(); AaruConsole.WriteLine("Waiting 5 seconds..."); Thread.Sleep(5000); AaruConsole.WriteLine("Sending READ FULL TOC to the device..."); retries = 0; do { retries++; sense = dev.ReadRawToc(out buffer, out senseBuffer, 1, dev.Timeout, out _); if (!sense) { break; } DecodedSense?decodedSense = Sense.Decode(senseBuffer); if (decodedSense.Value.ASC != 0x04) { break; } if (decodedSense.Value.ASCQ != 0x01) { break; } } while(retries < 25); if (sense) { AaruConsole.WriteLine("READ FULL TOC failed..."); AaruConsole.WriteLine("{0}", Sense.PrettifySense(senseBuffer)); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadLine(); return; } decodedToc = FullTOC.Decode(buffer); if (decodedToc is null) { AaruConsole.WriteLine("Could not decode TOC..."); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadLine(); return; } toc = decodedToc.Value; FullTOC.TrackDataDescriptor newLeadOutTrack = toc.TrackDescriptors.FirstOrDefault(t => t.POINT == 0xA2); if (newLeadOutTrack.POINT != 0xA2) { AaruConsole.WriteLine("Cannot find lead-out..."); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadLine(); return; } if (newLeadOutTrack.PMIN >= 0xA0 && !tocIsNotBcd) { newLeadOutTrack.PMIN -= 0x90; } if (newLeadOutTrack.PMIN != leadOutTrack.PMIN || newLeadOutTrack.PSEC != leadOutTrack.PSEC || newLeadOutTrack.PFRAME != leadOutTrack.PFRAME) { AaruConsole.WriteLine("Lead-out has changed, this drive does not support hot swapping discs..."); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadLine(); return; } AaruConsole.Write("Reading LBA {0}... ", sectors + 5); bool dataResult = dev.ReadCd(out byte[] dataBuffer, out byte[] dataSense, (uint)(sectors + 5), 2352, 1, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); AaruConsole.WriteLine(dataResult ? "FAIL!" : "Success!"); AaruConsole.Write("Reading LBA {0} as audio (scrambled)... ", sectors + 5); bool scrambledResult = dev.ReadCd(out byte[] scrambledBuffer, out byte[] scrambledSense, (uint)(sectors + 5), 2352, 1, MmcSectorTypes.Cdda, false, false, false, MmcHeaderCodes.None, true, false, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); AaruConsole.WriteLine(scrambledResult ? "FAIL!" : "Success!"); AaruConsole.Write("Reading LBA {0}'s PQ subchannel... ", sectors + 5); bool pqResult = dev.ReadCd(out byte[] pqBuffer, out byte[] pqSense, (uint)(sectors + 5), 16, 1, MmcSectorTypes.AllTypes, false, false, false, MmcHeaderCodes.None, false, false, MmcErrorField.None, MmcSubchannel.Q16, dev.Timeout, out _); if (pqResult) { pqResult = dev.ReadCd(out pqBuffer, out pqSense, (uint)(sectors + 5), 16, 1, MmcSectorTypes.AllTypes, false, false, false, MmcHeaderCodes.None, false, false, MmcErrorField.None, MmcSubchannel.Q16, dev.Timeout, out _); } AaruConsole.WriteLine(pqResult ? "FAIL!" : "Success!"); AaruConsole.Write("Reading LBA {0}'s PQ subchannel... ", sectors + 5); bool rwResult = dev.ReadCd(out byte[] rwBuffer, out byte[] rwSense, (uint)(sectors + 5), 16, 1, MmcSectorTypes.AllTypes, false, false, false, MmcHeaderCodes.None, false, false, MmcErrorField.None, MmcSubchannel.Rw, dev.Timeout, out _); if (rwResult) { rwResult = dev.ReadCd(out rwBuffer, out rwSense, (uint)(sectors + 5), 16, 1, MmcSectorTypes.Cdda, false, false, false, MmcHeaderCodes.None, false, false, MmcErrorField.None, MmcSubchannel.Rw, dev.Timeout, out _); } AaruConsole.WriteLine(pqResult ? "FAIL!" : "Success!"); menu: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("Device {0} read Lead-Out.", dataResult && scrambledResult ? "cannot" : "can"); AaruConsole.WriteLine("LBA {0} sense is {1}, buffer is {2}, sense buffer is {3}.", sectors + 5, dataResult, dataBuffer is null ? "null" : ArrayHelpers.ArrayIsNullOrEmpty(dataBuffer) ? "empty" : $"{dataBuffer.Length} bytes", dataSense is null ? "null" : ArrayHelpers. ArrayIsNullOrEmpty(dataSense) ? "empty" : $"{dataSense.Length}"); AaruConsole.WriteLine("LBA {0} (scrambled) sense is {1}, buffer is {2}, sense buffer is {3}.", sectors + 5, scrambledResult, scrambledBuffer is null ? "null" : ArrayHelpers.ArrayIsNullOrEmpty(scrambledBuffer) ? "empty" : $"{scrambledBuffer.Length} bytes", scrambledSense is null ? "null" : ArrayHelpers.ArrayIsNullOrEmpty(scrambledSense) ? "empty" : $"{scrambledSense.Length}"); AaruConsole.WriteLine("LBA {0}'s PQ sense is {1}, buffer is {2}, sense buffer is {3}.", sectors + 5, pqResult, pqBuffer is null ? "null" : ArrayHelpers.ArrayIsNullOrEmpty(pqBuffer) ? "empty" : $"{pqBuffer.Length} bytes", pqSense is null ? "null" : ArrayHelpers.ArrayIsNullOrEmpty(pqSense) ? "empty" : $"{pqSense.Length}"); AaruConsole.WriteLine("LBA {0}'s RW sense is {1}, buffer is {2}, sense buffer is {3}.", sectors + 5, rwResult, rwBuffer is null ? "null" : ArrayHelpers.ArrayIsNullOrEmpty(rwBuffer) ? "empty" : $"{rwBuffer.Length} bytes", rwSense is null ? "null" : ArrayHelpers.ArrayIsNullOrEmpty(rwSense) ? "empty" : $"{rwSense.Length}"); AaruConsole.WriteLine(); AaruConsole.WriteLine("Choose what to do:"); AaruConsole.WriteLine("1.- Print LBA {0} buffer.", sectors + 5); AaruConsole.WriteLine("2.- Print LBA {0} sense buffer.", sectors + 5); AaruConsole.WriteLine("3.- Decode LBA {0} sense buffer.", sectors + 5); AaruConsole.WriteLine("4.- Print LBA {0} (scrambled) buffer.", sectors + 5); AaruConsole.WriteLine("5.- Print LBA {0} (scrambled) sense buffer.", sectors + 5); AaruConsole.WriteLine("6.- Decode LBA {0} (scrambled) sense buffer.", sectors + 5); AaruConsole.WriteLine("7.- Print LBA {0}'s PQ buffer.", sectors + 5); AaruConsole.WriteLine("8.- Print LBA {0}'s PQ sense buffer.", sectors + 5); AaruConsole.WriteLine("9.- Decode LBA {0}'s PQ sense buffer.", sectors + 5); AaruConsole.WriteLine("10.- Print LBA {0}'s RW buffer.", sectors + 5); AaruConsole.WriteLine("11.- Print LBA {0}'s RW sense buffer.", sectors + 5); AaruConsole.WriteLine("12.- Decode LBA {0}'s RW sense buffer.", sectors + 5); AaruConsole.WriteLine("13.- Send command again."); AaruConsole.WriteLine("0.- Return to special SCSI MultiMedia Commands menu."); AaruConsole.Write("Choose: "); strDev = System.Console.ReadLine(); if (!int.TryParse(strDev, out item)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); goto menu; } switch (item) { case 0: AaruConsole.WriteLine("Returning to special SCSI MultiMedia Commands menu..."); return; case 1: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA {0} response:", sectors + 5); if (buffer != null) { PrintHex.PrintHexArray(dataBuffer, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 2: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA {0} sense:", sectors + 5); if (senseBuffer != null) { PrintHex.PrintHexArray(dataSense, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 3: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA {0} decoded sense:", sectors + 5); AaruConsole.Write("{0}", Sense.PrettifySense(dataSense)); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 4: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA {0} (scrambled) response:", sectors + 5); if (buffer != null) { PrintHex.PrintHexArray(scrambledBuffer, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 5: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA {0} (scrambled) sense:", sectors + 5); if (senseBuffer != null) { PrintHex.PrintHexArray(scrambledSense, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 6: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA {0} (scrambled) decoded sense:", sectors + 5); AaruConsole.Write("{0}", Sense.PrettifySense(scrambledSense)); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 7: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA's PQ {0} response:", sectors + 5); if (buffer != null) { PrintHex.PrintHexArray(pqBuffer, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 8: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA's PQ {0} sense:", sectors + 5); if (senseBuffer != null) { PrintHex.PrintHexArray(pqSense, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 9: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA's PQ {0} decoded sense:", sectors + 5); AaruConsole.Write("{0}", Sense.PrettifySense(pqSense)); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 10: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA's RW {0} response:", sectors + 5); if (buffer != null) { PrintHex.PrintHexArray(rwBuffer, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 11: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA's RW {0} sense:", sectors + 5); if (senseBuffer != null) { PrintHex.PrintHexArray(rwSense, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 12: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA's RW {0} decoded sense:", sectors + 5); AaruConsole.Write("{0}", Sense.PrettifySense(rwSense)); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 13: goto start; default: AaruConsole.WriteLine("Incorrect option. Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); goto menu; } }
static void CheckGdromReadability(string devPath, Device dev) { string strDev; int item; bool tocIsNotBcd = false; bool sense; byte[] buffer; byte[] senseBuffer; int retries; start: System.Console.Clear(); AaruConsole.WriteLine("Ejecting disc..."); dev.AllowMediumRemoval(out _, dev.Timeout, out _); dev.EjectTray(out _, dev.Timeout, out _); AaruConsole.WriteLine("Please insert trap disc inside..."); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadLine(); AaruConsole.WriteLine("Sending READ FULL TOC to the device..."); retries = 0; do { retries++; sense = dev.ScsiTestUnitReady(out senseBuffer, dev.Timeout, out _); if (!sense) { break; } var decodedSense = Sense.Decode(senseBuffer); if (decodedSense.Value.ASC != 0x04) { break; } if (decodedSense.Value.ASCQ != 0x01) { break; } Thread.Sleep(2000); } while(retries < 25); sense = dev.ReadRawToc(out buffer, out senseBuffer, 1, dev.Timeout, out _); if (sense) { AaruConsole.WriteLine("READ FULL TOC failed..."); AaruConsole.WriteLine("{0}", Sense.PrettifySense(senseBuffer)); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadLine(); return; } FullTOC.CDFullTOC?decodedToc = FullTOC.Decode(buffer); if (decodedToc is null) { AaruConsole.WriteLine("Could not decode TOC..."); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadLine(); return; } FullTOC.CDFullTOC toc = decodedToc.Value; FullTOC.TrackDataDescriptor leadOutTrack = toc.TrackDescriptors.FirstOrDefault(t => t.POINT == 0xA2); if (leadOutTrack.POINT != 0xA2) { AaruConsole.WriteLine("Cannot find lead-out..."); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadLine(); return; } int min = 0, sec, frame; if (leadOutTrack.PMIN == 122) { tocIsNotBcd = true; } if (leadOutTrack.PMIN >= 0xA0 && !tocIsNotBcd) { min += 90; leadOutTrack.PMIN -= 0x90; } if (tocIsNotBcd) { min = leadOutTrack.PMIN; sec = leadOutTrack.PSEC; frame = leadOutTrack.PFRAME; } else { min += ((leadOutTrack.PMIN >> 4) * 10) + (leadOutTrack.PMIN & 0x0F); sec = ((leadOutTrack.PSEC >> 4) * 10) + (leadOutTrack.PSEC & 0x0F); frame = ((leadOutTrack.PFRAME >> 4) * 10) + (leadOutTrack.PFRAME & 0x0F); } int sectors = ((min * 60 * 75) + (sec * 75) + frame) - 150; AaruConsole.WriteLine("Trap disc shows {0} sectors...", sectors); if (sectors < 450000) { AaruConsole.WriteLine("Trap disc doesn't have enough sectors..."); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadLine(); return; } AaruConsole.WriteLine("Stopping motor..."); dev.StopUnit(out _, dev.Timeout, out _); AaruConsole.WriteLine("Please MANUALLY get the trap disc out and put the GD-ROM disc inside..."); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadLine(); AaruConsole.WriteLine("Waiting 5 seconds..."); Thread.Sleep(5000); AaruConsole.WriteLine("Sending READ FULL TOC to the device..."); retries = 0; do { retries++; sense = dev.ReadRawToc(out buffer, out senseBuffer, 1, dev.Timeout, out _); if (!sense) { break; } var decodedSense = Sense.Decode(senseBuffer); if (decodedSense.Value.ASC != 0x04) { break; } if (decodedSense.Value.ASCQ != 0x01) { break; } } while(retries < 25); if (sense) { AaruConsole.WriteLine("READ FULL TOC failed..."); AaruConsole.WriteLine("{0}", Sense.PrettifySense(senseBuffer)); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadLine(); return; } decodedToc = FullTOC.Decode(buffer); if (decodedToc is null) { AaruConsole.WriteLine("Could not decode TOC..."); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadLine(); return; } toc = decodedToc.Value; FullTOC.TrackDataDescriptor newLeadOutTrack = toc.TrackDescriptors.FirstOrDefault(t => t.POINT == 0xA2); if (newLeadOutTrack.POINT != 0xA2) { AaruConsole.WriteLine("Cannot find lead-out..."); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadLine(); return; } if (newLeadOutTrack.PMIN >= 0xA0 && !tocIsNotBcd) { newLeadOutTrack.PMIN -= 0x90; } if (newLeadOutTrack.PMIN != leadOutTrack.PMIN || newLeadOutTrack.PSEC != leadOutTrack.PSEC || newLeadOutTrack.PFRAME != leadOutTrack.PFRAME) { AaruConsole.WriteLine("Lead-out has changed, this drive does not support hot swapping discs..."); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadLine(); return; } dev.SetCdSpeed(out _, RotationalControl.PureCav, 170, 0, dev.Timeout, out _); AaruConsole.Write("Reading LBA 0... "); bool lba0Result = dev.ReadCd(out byte[] lba0Buffer, out byte[] lba0Sense, 0, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); AaruConsole.WriteLine(lba0Result ? "FAIL!" : "Success!"); AaruConsole.Write("Reading LBA 0 as audio (scrambled)... "); bool lba0ScrambledResult = dev.ReadCd(out byte[] lba0ScrambledBuffer, out byte[] lba0ScrambledSense, 0, 2352, 1, MmcSectorTypes.Cdda, false, false, false, MmcHeaderCodes.None, true, false, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); AaruConsole.WriteLine(lba0ScrambledResult ? "FAIL!" : "Success!"); AaruConsole.Write("Reading LBA 100000... "); bool lba100000Result = dev.ReadCd(out byte[] lba100000Buffer, out byte[] lba100000Sense, 100000, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); AaruConsole.WriteLine(lba100000Result ? "FAIL!" : "Success!"); AaruConsole.Write("Reading LBA 50000... "); bool lba50000Result = dev.ReadCd(out byte[] lba50000Buffer, out byte[] lba50000Sense, 50000, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); AaruConsole.WriteLine(lba50000Result ? "FAIL!" : "Success!"); AaruConsole.Write("Reading LBA 450000... "); bool lba450000Result = dev.ReadCd(out byte[] lba450000Buffer, out byte[] lba450000Sense, 450000, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); AaruConsole.WriteLine(lba450000Result ? "FAIL!" : "Success!"); AaruConsole.Write("Reading LBA 400000... "); bool lba400000Result = dev.ReadCd(out byte[] lba400000Buffer, out byte[] lba400000Sense, 400000, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); AaruConsole.WriteLine(lba400000Result ? "FAIL!" : "Success!"); AaruConsole.Write("Reading LBA 45000... "); bool lba45000Result = dev.ReadCd(out byte[] lba45000Buffer, out byte[] lba45000Sense, 45000, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); AaruConsole.WriteLine(lba45000Result ? "FAIL!" : "Success!"); AaruConsole.Write("Reading LBA 44990... "); bool lba44990Result = dev.ReadCd(out byte[] lba44990Buffer, out byte[] lba44990Sense, 44990, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); AaruConsole.WriteLine(lba44990Result ? "FAIL!" : "Success!"); menu: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("Device {0} read HD area.", lba450000Result ? "cannot" : "can"); AaruConsole.WriteLine("LBA 0 sense is {0}, buffer is {1}, sense buffer is {2}.", lba0Result, lba0Buffer is null ? "null" : ArrayHelpers.ArrayIsNullOrEmpty(lba0Buffer) ? "empty" : $"{lba0Buffer.Length} bytes", lba0Sense is null ? "null" : ArrayHelpers. ArrayIsNullOrEmpty(lba0Sense) ? "empty" : $"{lba0Sense.Length}"); AaruConsole.WriteLine("LBA 0 (scrambled) sense is {0}, buffer is {1}, sense buffer is {2}.", lba0ScrambledResult, lba0ScrambledBuffer is null ? "null" : ArrayHelpers.ArrayIsNullOrEmpty(lba0ScrambledBuffer) ? "empty" : $"{lba0ScrambledBuffer.Length} bytes", lba0ScrambledSense is null ? "null" : ArrayHelpers.ArrayIsNullOrEmpty(lba0ScrambledSense) ? "empty" : $"{lba0ScrambledSense.Length}"); AaruConsole.WriteLine("LBA 44990 sense is {0}, buffer is {1}, sense buffer is {2}.", lba44990Result, lba44990Buffer is null ? "null" : ArrayHelpers.ArrayIsNullOrEmpty(lba44990Buffer) ? "empty" : $"{lba44990Buffer.Length} bytes", lba44990Sense is null ? "null" : ArrayHelpers. ArrayIsNullOrEmpty(lba44990Sense) ? "empty" : $"{lba44990Sense.Length}"); AaruConsole.WriteLine("LBA 45000 sense is {0}, buffer is {1}, sense buffer is {2}.", lba45000Result, lba45000Buffer is null ? "null" : ArrayHelpers.ArrayIsNullOrEmpty(lba45000Buffer) ? "empty" : $"{lba45000Buffer.Length} bytes", lba45000Sense is null ? "null" : ArrayHelpers. ArrayIsNullOrEmpty(lba45000Sense) ? "empty" : $"{lba45000Sense.Length}"); AaruConsole.WriteLine("LBA 50000 sense is {0}, buffer is {1}, sense buffer is {2}.", lba50000Result, lba50000Buffer is null ? "null" : ArrayHelpers.ArrayIsNullOrEmpty(lba50000Buffer) ? "empty" : $"{lba50000Buffer.Length} bytes", lba50000Sense is null ? "null" : ArrayHelpers. ArrayIsNullOrEmpty(lba50000Sense) ? "empty" : $"{lba50000Sense.Length}"); AaruConsole.WriteLine("LBA 100000 sense is {0}, buffer is {1}, sense buffer is {2}.", lba100000Result, lba100000Buffer is null ? "null" : ArrayHelpers.ArrayIsNullOrEmpty(lba100000Buffer) ? "empty" : $"{lba100000Buffer.Length} bytes", lba100000Sense is null ? "null" : ArrayHelpers. ArrayIsNullOrEmpty(lba100000Sense) ? "empty" : $"{lba100000Sense.Length}"); AaruConsole.WriteLine("LBA 400000 sense is {0}, buffer is {1}, sense buffer is {2}.", lba400000Result, lba400000Buffer is null ? "null" : ArrayHelpers.ArrayIsNullOrEmpty(lba400000Buffer) ? "empty" : $"{lba400000Buffer.Length} bytes", lba400000Sense is null ? "null" : ArrayHelpers. ArrayIsNullOrEmpty(lba400000Sense) ? "empty" : $"{lba400000Sense.Length}"); AaruConsole.WriteLine("LBA 450000 sense is {0}, buffer is {1}, sense buffer is {2}.", lba450000Result, lba450000Buffer is null ? "null" : ArrayHelpers.ArrayIsNullOrEmpty(lba450000Buffer) ? "empty" : $"{lba450000Buffer.Length} bytes", lba450000Sense is null ? "null" : ArrayHelpers. ArrayIsNullOrEmpty(lba450000Sense) ? "empty" : $"{lba450000Sense.Length}"); AaruConsole.WriteLine(); AaruConsole.WriteLine("Choose what to do:"); AaruConsole.WriteLine("1.- Print LBA 0 buffer."); AaruConsole.WriteLine("2.- Print LBA 0 sense buffer."); AaruConsole.WriteLine("3.- Decode LBA 0 sense buffer."); AaruConsole.WriteLine("4.- Print LBA 0 (scrambled) buffer."); AaruConsole.WriteLine("5.- Print LBA 0 (scrambled) sense buffer."); AaruConsole.WriteLine("6.- Decode LBA 0 (scrambled) sense buffer."); AaruConsole.WriteLine("7.- Print LBA 44990 buffer."); AaruConsole.WriteLine("8.- Print LBA 44990 sense buffer."); AaruConsole.WriteLine("9.- Decode LBA 44990 sense buffer."); AaruConsole.WriteLine("10.- Print LBA 45000 buffer."); AaruConsole.WriteLine("11.- Print LBA 45000 sense buffer."); AaruConsole.WriteLine("12.- Decode LBA 45000 sense buffer."); AaruConsole.WriteLine("13.- Print LBA 50000 buffer."); AaruConsole.WriteLine("14.- Print LBA 50000 sense buffer."); AaruConsole.WriteLine("15.- Decode LBA 50000 sense buffer."); AaruConsole.WriteLine("16.- Print LBA 100000 buffer."); AaruConsole.WriteLine("17.- Print LBA 100000 sense buffer."); AaruConsole.WriteLine("18.- Decode LBA 100000 sense buffer."); AaruConsole.WriteLine("19.- Print LBA 400000 buffer."); AaruConsole.WriteLine("20.- Print LBA 400000 sense buffer."); AaruConsole.WriteLine("21.- Decode LBA 400000 sense buffer."); AaruConsole.WriteLine("22.- Print LBA 450000 buffer."); AaruConsole.WriteLine("23.- Print LBA 450000 sense buffer."); AaruConsole.WriteLine("24.- Decode LBA 450000 sense buffer."); AaruConsole.WriteLine("25.- Send command again."); AaruConsole.WriteLine("0.- Return to special SCSI MultiMedia Commands menu."); AaruConsole.Write("Choose: "); strDev = System.Console.ReadLine(); if (!int.TryParse(strDev, out item)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); goto menu; } switch (item) { case 0: AaruConsole.WriteLine("Returning to special SCSI MultiMedia Commands menu..."); return; case 1: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA 0 response:"); if (buffer != null) { PrintHex.PrintHexArray(lba0Buffer, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 2: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA 0 sense:"); if (senseBuffer != null) { PrintHex.PrintHexArray(lba0Sense, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 3: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA 0 decoded sense:"); AaruConsole.Write("{0}", Sense.PrettifySense(lba0Sense)); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 4: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA 0 (scrambled) response:"); if (buffer != null) { PrintHex.PrintHexArray(lba0ScrambledBuffer, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 5: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA 0 (scrambled) sense:"); if (senseBuffer != null) { PrintHex.PrintHexArray(lba0ScrambledSense, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 6: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA 0 (scrambled) decoded sense:"); AaruConsole.Write("{0}", Sense.PrettifySense(lba0ScrambledSense)); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 7: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA 44990 response:"); if (buffer != null) { PrintHex.PrintHexArray(lba44990Buffer, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 8: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA 44990 sense:"); if (senseBuffer != null) { PrintHex.PrintHexArray(lba44990Sense, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 9: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA 44990 decoded sense:"); AaruConsole.Write("{0}", Sense.PrettifySense(lba44990Sense)); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 10: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA 45000 response:"); if (buffer != null) { PrintHex.PrintHexArray(lba45000Buffer, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 11: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA 45000 sense:"); if (senseBuffer != null) { PrintHex.PrintHexArray(lba45000Sense, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 12: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA 45000 decoded sense:"); AaruConsole.Write("{0}", Sense.PrettifySense(lba45000Sense)); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 13: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA 50000 response:"); if (buffer != null) { PrintHex.PrintHexArray(lba50000Buffer, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 14: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA 50000 sense:"); if (senseBuffer != null) { PrintHex.PrintHexArray(lba50000Sense, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 15: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA 50000 decoded sense:"); AaruConsole.Write("{0}", Sense.PrettifySense(lba50000Sense)); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 16: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA 100000 response:"); if (buffer != null) { PrintHex.PrintHexArray(lba100000Buffer, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 17: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA 100000 sense:"); if (senseBuffer != null) { PrintHex.PrintHexArray(lba100000Sense, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 18: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA 100000 decoded sense:"); AaruConsole.Write("{0}", Sense.PrettifySense(lba100000Sense)); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 19: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA 400000 response:"); if (buffer != null) { PrintHex.PrintHexArray(lba400000Buffer, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 20: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA 400000 sense:"); if (senseBuffer != null) { PrintHex.PrintHexArray(lba400000Sense, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 21: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA 400000 decoded sense:"); AaruConsole.Write("{0}", Sense.PrettifySense(lba400000Sense)); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 22: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA 450000 response:"); if (buffer != null) { PrintHex.PrintHexArray(lba450000Buffer, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 23: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA 450000 sense:"); if (senseBuffer != null) { PrintHex.PrintHexArray(lba450000Sense, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 24: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("LBA 450000 decoded sense:"); AaruConsole.Write("{0}", Sense.PrettifySense(lba450000Sense)); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); goto menu; case 25: goto start; default: AaruConsole.WriteLine("Incorrect option. Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); goto menu; } }
public static void DetectDiscType(ref MediaType mediaType, int sessions, FullTOC.CDFullTOC?decodedToc, Device dev, out bool hiddenTrack, out bool hiddenData, int firstTrackLastSession) { uint startOfFirstDataTrack = uint.MaxValue; byte[] cmdBuf; bool sense; byte secondSessionFirstTrack = 0; byte[] sector0; byte[] sector1 = null; byte[] ps2BootSectors = null; byte[] playdia1 = null; byte[] playdia2 = null; byte[] firstDataSectorNotZero = null; byte[] secondDataSectorNotZero = null; byte[] firstTrackSecondSession = null; byte[] firstTrackSecondSessionAudio = null; byte[] videoNowColorFrame; hiddenTrack = false; hiddenData = false; if (decodedToc.HasValue) { if (decodedToc.Value.TrackDescriptors.Any(t => t.SessionNumber == 2)) { secondSessionFirstTrack = decodedToc.Value.TrackDescriptors.Where(t => t.SessionNumber == 2).Min(t => t.POINT); } } if (mediaType == MediaType.CD || mediaType == MediaType.CDROMXA) { bool hasDataTrack = false; bool hasAudioTrack = false; bool allFirstSessionTracksAreAudio = true; bool hasVideoTrack = false; if (decodedToc.HasValue) { foreach (FullTOC.TrackDataDescriptor track in decodedToc.Value.TrackDescriptors) { if (track.TNO == 1 && ((TocControl)(track.CONTROL & 0x0D) == TocControl.DataTrack || (TocControl)(track.CONTROL & 0x0D) == TocControl.DataTrackIncremental)) { allFirstSessionTracksAreAudio &= firstTrackLastSession != 1; } if ((TocControl)(track.CONTROL & 0x0D) == TocControl.DataTrack || (TocControl)(track.CONTROL & 0x0D) == TocControl.DataTrackIncremental) { uint startAddress = (uint)(((track.PHOUR * 3600 * 75) + (track.PMIN * 60 * 75) + (track.PSEC * 75) + track.PFRAME) - 150); if (startAddress < startOfFirstDataTrack) { startOfFirstDataTrack = startAddress; } hasDataTrack = true; allFirstSessionTracksAreAudio &= track.POINT >= firstTrackLastSession; } else { hasAudioTrack = true; } hasVideoTrack |= track.ADR == 4; } } if (hasDataTrack && hasAudioTrack && allFirstSessionTracksAreAudio && sessions == 2) { mediaType = MediaType.CDPLUS; } if (!hasDataTrack && hasAudioTrack && sessions == 1) { mediaType = MediaType.CDDA; } if (hasDataTrack && !hasAudioTrack && sessions == 1) { mediaType = MediaType.CDROM; } if (hasVideoTrack && !hasDataTrack && sessions == 1) { mediaType = MediaType.CDV; } } if (secondSessionFirstTrack != 0 && decodedToc.HasValue && decodedToc.Value.TrackDescriptors.Any(t => t.POINT == secondSessionFirstTrack)) { FullTOC.TrackDataDescriptor secondSessionFirstTrackTrack = decodedToc.Value.TrackDescriptors.First(t => t.POINT == secondSessionFirstTrack); uint firstSectorSecondSessionFirstTrack = (uint)(((secondSessionFirstTrackTrack.PHOUR * 3600 * 75) + (secondSessionFirstTrackTrack.PMIN * 60 * 75) + (secondSessionFirstTrackTrack.PSEC * 75) + secondSessionFirstTrackTrack.PFRAME) - 150); sense = dev.ReadCd(out cmdBuf, out _, firstSectorSecondSessionFirstTrack, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (!sense && !dev.Error) { firstTrackSecondSession = cmdBuf; } else { sense = dev.ReadCd(out cmdBuf, out _, firstSectorSecondSessionFirstTrack, 2352, 1, MmcSectorTypes.Cdda, false, false, true, MmcHeaderCodes.None, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (!sense && !dev.Error) { firstTrackSecondSession = cmdBuf; } } sense = dev.ReadCd(out cmdBuf, out _, firstSectorSecondSessionFirstTrack - 1, 2352, 3, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (!sense && !dev.Error) { firstTrackSecondSessionAudio = cmdBuf; } else { sense = dev.ReadCd(out cmdBuf, out _, firstSectorSecondSessionFirstTrack - 1, 2352, 3, MmcSectorTypes.Cdda, false, false, true, MmcHeaderCodes.None, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (!sense && !dev.Error) { firstTrackSecondSessionAudio = cmdBuf; } } } videoNowColorFrame = new byte[9 * 2352]; for (int i = 0; i < 9; i++) { sense = dev.ReadCd(out cmdBuf, out _, (uint)i, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (sense || dev.Error) { sense = dev.ReadCd(out cmdBuf, out _, (uint)i, 2352, 1, MmcSectorTypes.Cdda, false, false, true, MmcHeaderCodes.None, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (sense || !dev.Error) { videoNowColorFrame = null; break; } } Array.Copy(cmdBuf, 0, videoNowColorFrame, i * 2352, 2352); } if (decodedToc.HasValue) { FullTOC.TrackDataDescriptor firstTrack = decodedToc.Value.TrackDescriptors.FirstOrDefault(t => t.POINT == 1); if (firstTrack.POINT == 1) { uint firstTrackSector = (uint)(((firstTrack.PHOUR * 3600 * 75) + (firstTrack.PMIN * 60 * 75) + (firstTrack.PSEC * 75) + firstTrack.PFRAME) - 150); // Check for hidden data before start of track 1 if (firstTrackSector > 0) { sense = dev.ReadCd(out sector0, out _, 0, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (!dev.Error && !sense) { hiddenTrack = true; hiddenData = IsData(sector0); if (hiddenData) { sense = dev.ReadCd(out byte[] sector16, out _, 16, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (IsCdi(sector0, sector16)) { mediaType = MediaType.CDIREADY; } } } } } } sector0 = null; switch (mediaType) { case MediaType.CD: case MediaType.CDDA: case MediaType.CDPLUS: case MediaType.CDROM: case MediaType.CDROMXA: { sense = dev.ReadCd(out cmdBuf, out _, 0, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (!sense && !dev.Error) { sector0 = new byte[2048]; Array.Copy(cmdBuf, 16, sector0, 0, 2048); sense = dev.ReadCd(out cmdBuf, out _, 1, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (!sense && !dev.Error) { sector1 = new byte[2048]; Array.Copy(cmdBuf, 16, sector1, 0, 2048); } sense = dev.ReadCd(out cmdBuf, out _, 4200, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (!sense && !dev.Error) { playdia1 = new byte[2048]; Array.Copy(cmdBuf, 24, playdia1, 0, 2048); } sense = dev.ReadCd(out cmdBuf, out _, 4201, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (!sense && !dev.Error) { playdia2 = new byte[2048]; Array.Copy(cmdBuf, 24, playdia2, 0, 2048); } if (startOfFirstDataTrack != uint.MaxValue) { sense = dev.ReadCd(out cmdBuf, out _, startOfFirstDataTrack, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (!sense && !dev.Error) { firstDataSectorNotZero = new byte[2048]; Array.Copy(cmdBuf, 16, firstDataSectorNotZero, 0, 2048); } sense = dev.ReadCd(out cmdBuf, out _, startOfFirstDataTrack + 1, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (!sense && !dev.Error) { secondDataSectorNotZero = new byte[2048]; Array.Copy(cmdBuf, 16, secondDataSectorNotZero, 0, 2048); } } var ps2Ms = new MemoryStream(); for (uint p = 0; p < 12; p++) { sense = dev.ReadCd(out cmdBuf, out _, p, 2352, 1, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (sense || dev.Error) { break; } ps2Ms.Write(cmdBuf, cmdBuf[0x0F] == 0x02 ? 24 : 16, 2048); } if (ps2Ms.Length == 0x6000) { ps2BootSectors = ps2Ms.ToArray(); } } else { sense = dev.ReadCd(out cmdBuf, out _, 0, 2324, 1, MmcSectorTypes.Mode2, false, false, true, MmcHeaderCodes.None, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (!sense && !dev.Error) { sector0 = new byte[2048]; Array.Copy(cmdBuf, 0, sector0, 0, 2048); sense = dev.ReadCd(out cmdBuf, out _, 1, 2324, 1, MmcSectorTypes.Mode2, false, false, true, MmcHeaderCodes.None, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (!sense && !dev.Error) { sector1 = new byte[2048]; Array.Copy(cmdBuf, 1, sector0, 0, 2048); } sense = dev.ReadCd(out cmdBuf, out _, 4200, 2324, 1, MmcSectorTypes.Mode2, false, false, true, MmcHeaderCodes.None, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (!sense && !dev.Error) { playdia1 = new byte[2048]; Array.Copy(cmdBuf, 0, playdia1, 0, 2048); } sense = dev.ReadCd(out cmdBuf, out _, 4201, 2324, 1, MmcSectorTypes.Mode2, false, false, true, MmcHeaderCodes.None, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (!sense && !dev.Error) { playdia2 = new byte[2048]; Array.Copy(cmdBuf, 0, playdia2, 0, 2048); } if (startOfFirstDataTrack != uint.MaxValue) { sense = dev.ReadCd(out cmdBuf, out _, startOfFirstDataTrack, 2324, 1, MmcSectorTypes.Mode2, false, false, true, MmcHeaderCodes.None, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (!sense && !dev.Error) { firstDataSectorNotZero = new byte[2048]; Array.Copy(cmdBuf, 0, firstDataSectorNotZero, 0, 2048); } sense = dev.ReadCd(out cmdBuf, out _, startOfFirstDataTrack + 1, 2324, 1, MmcSectorTypes.Mode2, false, false, true, MmcHeaderCodes.None, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (!sense && !dev.Error) { secondDataSectorNotZero = new byte[2048]; Array.Copy(cmdBuf, 0, secondDataSectorNotZero, 0, 2048); } } var ps2Ms = new MemoryStream(); for (uint p = 0; p < 12; p++) { sense = dev.ReadCd(out cmdBuf, out _, p, 2324, 1, MmcSectorTypes.Mode2, false, false, true, MmcHeaderCodes.None, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (sense || dev.Error) { break; } ps2Ms.Write(cmdBuf, 0, 2048); } if (ps2Ms.Length == 0x6000) { ps2BootSectors = ps2Ms.ToArray(); } } else { sense = dev.ReadCd(out cmdBuf, out _, 0, 2048, 1, MmcSectorTypes.Mode1, false, false, true, MmcHeaderCodes.None, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (!sense && !dev.Error) { sector0 = cmdBuf; sense = dev.ReadCd(out cmdBuf, out _, 0, 2048, 1, MmcSectorTypes.Mode1, false, false, true, MmcHeaderCodes.None, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (!sense && !dev.Error) { sector1 = cmdBuf; } sense = dev.ReadCd(out cmdBuf, out _, 0, 2048, 12, MmcSectorTypes.Mode1, false, false, true, MmcHeaderCodes.None, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (!sense && !dev.Error) { ps2BootSectors = cmdBuf; } if (startOfFirstDataTrack != uint.MaxValue) { sense = dev.ReadCd(out cmdBuf, out _, startOfFirstDataTrack, 2048, 1, MmcSectorTypes.Mode1, false, false, true, MmcHeaderCodes.None, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (!sense && !dev.Error) { firstDataSectorNotZero = cmdBuf; } sense = dev.ReadCd(out cmdBuf, out _, startOfFirstDataTrack + 1, 2048, 1, MmcSectorTypes.Mode1, false, false, true, MmcHeaderCodes.None, true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _); if (!sense && !dev.Error) { secondDataSectorNotZero = cmdBuf; } } } else { goto case MediaType.DVDROM; } } } break; } // TODO: Check for CD-i Ready case MediaType.CDI: break; case MediaType.DVDROM: case MediaType.HDDVDROM: case MediaType.BDROM: case MediaType.Unknown: sense = dev.Read16(out cmdBuf, out _, 0, false, true, false, 0, 2048, 0, 1, false, dev.Timeout, out _); if (!sense && !dev.Error) { sector0 = cmdBuf; sense = dev.Read16(out cmdBuf, out _, 0, false, true, false, 1, 2048, 0, 1, false, dev.Timeout, out _); if (!sense && !dev.Error) { sector1 = cmdBuf; } sense = dev.Read16(out cmdBuf, out _, 0, false, true, false, 0, 2048, 0, 12, false, dev.Timeout, out _); if (!sense && !dev.Error && cmdBuf.Length == 0x6000) { ps2BootSectors = cmdBuf; } } else { sense = dev.Read12(out cmdBuf, out _, 0, false, true, false, false, 0, 2048, 0, 1, false, dev.Timeout, out _); if (!sense && !dev.Error) { sector0 = cmdBuf; sense = dev.Read12(out cmdBuf, out _, 0, false, true, false, false, 1, 2048, 0, 1, false, dev.Timeout, out _); if (!sense && !dev.Error) { sector1 = cmdBuf; } sense = dev.Read12(out cmdBuf, out _, 0, false, true, false, false, 0, 2048, 0, 12, false, dev.Timeout, out _); if (!sense && !dev.Error && cmdBuf.Length == 0x6000) { ps2BootSectors = cmdBuf; } } else { sense = dev.Read10(out cmdBuf, out _, 0, false, true, false, false, 0, 2048, 0, 1, dev.Timeout, out _); if (!sense && !dev.Error) { sector0 = cmdBuf; sense = dev.Read10(out cmdBuf, out _, 0, false, true, false, false, 1, 2048, 0, 1, dev.Timeout, out _); if (!sense && !dev.Error) { sector1 = cmdBuf; } sense = dev.Read10(out cmdBuf, out _, 0, false, true, false, false, 0, 2048, 0, 12, dev.Timeout, out _); if (!sense && !dev.Error && cmdBuf.Length == 0x6000) { ps2BootSectors = cmdBuf; } } else { sense = dev.Read6(out cmdBuf, out _, 0, 2048, 1, dev.Timeout, out _); if (!sense && !dev.Error) { sector0 = cmdBuf; sense = dev.Read6(out cmdBuf, out _, 1, 2048, 1, dev.Timeout, out _); if (!sense && !dev.Error) { sector1 = cmdBuf; } sense = dev.Read6(out cmdBuf, out _, 0, 2048, 12, dev.Timeout, out _); if (!sense && !dev.Error && cmdBuf.Length == 0x6000) { ps2BootSectors = cmdBuf; } } } } } break; // Recordables will not be checked case MediaType.CDR: case MediaType.CDRW: case MediaType.CDMRW: case MediaType.DDCDR: case MediaType.DDCDRW: case MediaType.DVDR: case MediaType.DVDRW: case MediaType.DVDPR: case MediaType.DVDPRW: case MediaType.DVDPRWDL: case MediaType.DVDRDL: case MediaType.DVDPRDL: case MediaType.DVDRAM: case MediaType.DVDRWDL: case MediaType.DVDDownload: case MediaType.HDDVDRAM: case MediaType.HDDVDR: case MediaType.HDDVDRW: case MediaType.HDDVDRDL: case MediaType.HDDVDRWDL: case MediaType.BDR: case MediaType.BDRE: case MediaType.BDRXL: case MediaType.BDREXL: return; } if (sector0 == null) { return; } switch (mediaType) { case MediaType.CD: case MediaType.CDDA: case MediaType.CDPLUS: case MediaType.CDROM: case MediaType.CDROMXA: // TODO: CDTV requires reading the filesystem, searching for a file called "/CDTV.TM" // TODO: CD32 requires reading the filesystem, searching for a file called "/CD32.TM" // TODO: Neo-Geo CD requires reading the filesystem and checking that the file "/IPL.TXT" is correct // TODO: Pippin requires interpreting Apple Partition Map, reading HFS and checking for Pippin signatures { if (CD.DecodeIPBin(sector0).HasValue) { mediaType = MediaType.MEGACD; return; } if (Saturn.DecodeIPBin(sector0).HasValue) { mediaType = MediaType.SATURNCD; } // Are GDR detectable ??? if (Dreamcast.DecodeIPBin(sector0).HasValue) { mediaType = MediaType.GDROM; } if (ps2BootSectors != null && ps2BootSectors.Length == 0x6000) { // The decryption key is applied as XOR. As first byte is originally always NULL, it gives us the key :) byte decryptByte = ps2BootSectors[0]; for (int i = 0; i < 0x6000; i++) { ps2BootSectors[i] ^= decryptByte; } string ps2BootSectorsHash = Sha256Context.Data(ps2BootSectors, out _); DicConsole.DebugWriteLine("Media-info Command", "PlayStation 2 boot sectors SHA256: {0}", ps2BootSectorsHash); if (ps2BootSectorsHash == PS2_PAL_HASH || ps2BootSectorsHash == PS2_NTSC_HASH || ps2BootSectorsHash == PS2_JAPANESE_HASH) { mediaType = MediaType.PS2CD; } } if (sector0 != null) { byte[] syncBytes = new byte[7]; Array.Copy(sector0, 0, syncBytes, 0, 7); if (_operaId.SequenceEqual(syncBytes)) { mediaType = MediaType.ThreeDO; } if (_fmTownsBootId.SequenceEqual(syncBytes)) { mediaType = MediaType.FMTOWNS; } } if (playdia1 != null && playdia2 != null) { byte[] pd1 = new byte[_playdiaCopyright.Length]; byte[] pd2 = new byte[_playdiaCopyright.Length]; Array.Copy(playdia1, 38, pd1, 0, pd1.Length); Array.Copy(playdia2, 0, pd2, 0, pd1.Length); if (_playdiaCopyright.SequenceEqual(pd1) && _playdiaCopyright.SequenceEqual(pd2)) { mediaType = MediaType.Playdia; } } if (secondDataSectorNotZero != null) { byte[] pce = new byte[_pcEngineSignature.Length]; Array.Copy(secondDataSectorNotZero, 32, pce, 0, pce.Length); if (_pcEngineSignature.SequenceEqual(pce)) { mediaType = MediaType.SuperCDROM2; } } if (firstDataSectorNotZero != null) { byte[] pcfx = new byte[_pcFxSignature.Length]; Array.Copy(firstDataSectorNotZero, 0, pcfx, 0, pcfx.Length); if (_pcFxSignature.SequenceEqual(pcfx)) { mediaType = MediaType.PCFX; } } if (firstTrackSecondSessionAudio != null) { byte[] jaguar = new byte[_atariSignature.Length]; for (int i = 0; i + jaguar.Length <= firstTrackSecondSessionAudio.Length; i += 2) { Array.Copy(firstTrackSecondSessionAudio, i, jaguar, 0, jaguar.Length); if (!_atariSignature.SequenceEqual(jaguar)) { continue; } mediaType = MediaType.JaguarCD; break; } } if (firstTrackSecondSession != null) { if (firstTrackSecondSession.Length >= 2336) { byte[] milcd = new byte[2048]; Array.Copy(firstTrackSecondSession, 24, milcd, 0, 2048); if (Dreamcast.DecodeIPBin(milcd).HasValue) { mediaType = MediaType.MilCD; } } } // TODO: Detect black and white VideoNow // TODO: Detect VideoNow XP if (IsVideoNowColor(videoNowColorFrame)) { mediaType = MediaType.VideoNowColor; } break; } // TODO: Check for CD-i Ready case MediaType.CDI: break; case MediaType.DVDROM: case MediaType.HDDVDROM: case MediaType.BDROM: case MediaType.Unknown: // TODO: Nuon requires reading the filesystem, searching for a file called "/NUON/NUON.RUN" if (ps2BootSectors != null && ps2BootSectors.Length == 0x6000) { // The decryption key is applied as XOR. As first byte is originally always NULL, it gives us the key :) byte decryptByte = ps2BootSectors[0]; for (int i = 0; i < 0x6000; i++) { ps2BootSectors[i] ^= decryptByte; } string ps2BootSectorsHash = Sha256Context.Data(ps2BootSectors, out _); DicConsole.DebugWriteLine("Media-info Command", "PlayStation 2 boot sectors SHA256: {0}", ps2BootSectorsHash); if (ps2BootSectorsHash == PS2_PAL_HASH || ps2BootSectorsHash == PS2_NTSC_HASH || ps2BootSectorsHash == PS2_JAPANESE_HASH) { mediaType = MediaType.PS2DVD; } } if (sector1 != null) { byte[] tmp = new byte[_ps3Id.Length]; Array.Copy(sector1, 0, tmp, 0, tmp.Length); if (tmp.SequenceEqual(_ps3Id)) { switch (mediaType) { case MediaType.BDROM: mediaType = MediaType.PS3BD; break; case MediaType.DVDROM: mediaType = MediaType.PS3DVD; break; } } tmp = new byte[_ps4Id.Length]; Array.Copy(sector1, 512, tmp, 0, tmp.Length); if (tmp.SequenceEqual(_ps4Id) && mediaType == MediaType.BDROM) { mediaType = MediaType.PS4BD; } } // TODO: Identify discs that require reading tracks (PC-FX, PlayStation, Sega, etc) break; } }