Esempio n. 1
0
        public void EmptyFile()
        {
            byte[] result =
                CRC16CCITTContext.File(Path.Combine(Consts.TEST_FILES_ROOT, "Checksum test files", "empty"));

            result.Should().BeEquivalentTo(_expectedEmpty);
        }
Esempio n. 2
0
        public void Crc16EmptyFile()
        {
            byte[] result =
                CRC16CCITTContext.File(Path.Combine(Consts.TEST_FILES_ROOT, "Checksum test files", "empty"));

            Assert.AreEqual(_expectedEmpty, result);
        }
Esempio n. 3
0
        public void Crc16CcittRandomFile()
        {
            byte[] result =
                CRC16CCITTContext.File(Path.Combine(Consts.TEST_FILES_ROOT, "Checksum test files", "random"));

            Assert.AreEqual(_expectedRandom, result);
        }
Esempio n. 4
0
        public void RandomData()
        {
            byte[] data = new byte[1048576];

            var fs = new FileStream(Path.Combine(Consts.TEST_FILES_ROOT, "Checksum test files", "random"),
                                    FileMode.Open, FileAccess.Read);

            fs.Read(data, 0, 1048576);
            fs.Close();
            fs.Dispose();
            CRC16CCITTContext.Data(data, out byte[] result);
            result.Should().BeEquivalentTo(_expectedRandom);
        }
Esempio n. 5
0
        public void Crc16EmptyData()
        {
            byte[] data = new byte[1048576];

            var fs = new FileStream(Path.Combine(Consts.TEST_FILES_ROOT, "Checksum test files", "empty"), FileMode.Open,
                                    FileAccess.Read);

            fs.Read(data, 0, 1048576);
            fs.Close();
            fs.Dispose();
            CRC16CCITTContext.Data(data, out byte[] result);
            Assert.AreEqual(_expectedEmpty, result);
        }
Esempio n. 6
0
        public void Crc16RandomData()
        {
            byte[] data = new byte[1048576];

            var fs = new FileStream(Path.Combine(Consts.TestFilesRoot, "checksums", "random"), FileMode.Open,
                                    FileAccess.Read);

            fs.Read(data, 0, 1048576);
            fs.Close();
            fs.Dispose();
            CRC16CCITTContext.Data(data, out byte[] result);
            Assert.AreEqual(ExpectedRandom, result);
        }
Esempio n. 7
0
        public void EmptyInstance()
        {
            byte[] data = new byte[1048576];

            var fs = new FileStream(Path.Combine(Consts.TEST_FILES_ROOT, "Checksum test files", "empty"), FileMode.Open,
                                    FileAccess.Read);

            fs.Read(data, 0, 1048576);
            fs.Close();
            fs.Dispose();
            var ctx = new CRC16CCITTContext();

            ctx.Update(data);
            byte[] result = ctx.Final();
            result.Should().BeEquivalentTo(_expectedEmpty);
        }
Esempio n. 8
0
        public void Crc16EmptyInstance()
        {
            byte[] data = new byte[1048576];

            var fs = new FileStream(Path.Combine(Consts.TEST_FILES_ROOT, "Checksum test files", "empty"), FileMode.Open,
                                    FileAccess.Read);

            fs.Read(data, 0, 1048576);
            fs.Close();
            fs.Dispose();
            IChecksum ctx = new CRC16CCITTContext();

            ctx.Update(data);
            byte[] result = ctx.Final();
            Assert.AreEqual(_expectedEmpty, result);
        }
Esempio n. 9
0
        public void Crc16RandomInstance()
        {
            byte[] data = new byte[1048576];

            var fs = new FileStream(Path.Combine(Consts.TestFilesRoot, "checksums", "random"), FileMode.Open,
                                    FileAccess.Read);

            fs.Read(data, 0, 1048576);
            fs.Close();
            fs.Dispose();
            IChecksum ctx = new CRC16CCITTContext();

            ctx.Update(data);
            byte[] result = ctx.Final();
            Assert.AreEqual(ExpectedRandom, result);
        }
Esempio n. 10
0
        public static string PrettifyQ(byte[] subBuf, bool bcd, long lba, bool corruptedPause, bool pause, bool rwEmpty)
        {
            CRC16CCITTContext.Data(subBuf, 10, out byte[] crc);

            bool   crcOk  = crc[0] == subBuf[10] && crc[1] == subBuf[11];
            long   minute = (lba + 150) / 4500;
            long   second = (lba + 150) % 4500 / 75;
            long   frame  = (lba + 150) % 4500 % 75;
            string area;
            int    control = (subBuf[0] & 0xF0) / 16;
            int    adr     = subBuf[0] & 0x0F;

            string controlInfo = ((control & 0xC) / 4) switch
            {
                0 => $"stereo audio {((control       & 0x01) == 1 ? "with" : "without")} pre-emphasis",
                1 => $"{((control                    & 0x01) == 1 ? "incremental" : "uninterrupted")} data",
                2 => $"quadraphonic audio {((control & 0x01) == 1 ? "with" : "without")} pre-emphasis",
                _ => $"reserved control value {control & 0x01}"
            };

            string copy = (control & 0x02) > 0 ? "copy permitted" : "copy prohibited";

            if (bcd)
            {
                BcdToBinaryQ(subBuf);
            }

            int  qPos = (subBuf[3] * 60 * 75) + (subBuf[4] * 75) + subBuf[5] - 150;
            byte pmin = subBuf[7];
            byte psec = subBuf[8];

            int  qStart  = (subBuf[7] * 60 * 75) + (subBuf[8] * 75) + subBuf[9] - 150;
            int  nextPos = (subBuf[3] * 60 * 75) + (subBuf[4] * 75) + subBuf[5] - 150;
            byte zero    = subBuf[6];
            int  maxOut  = (subBuf[7] * 60 * 75) + (subBuf[8] * 75) + subBuf[9] - 150;
            bool final   = subBuf[3] == 0xFF && subBuf[4] == 0xFF && subBuf[5] == 0xFF;

            BinaryToBcdQ(subBuf);

            if (lba < 0)
            {
                area = "Lead-In";

                switch (adr)
                {
                case 1 when subBuf[2] < 0xA0:
Esempio n. 11
0
        public static void SolveTrackPregaps(Device dev, DumpLog dumpLog, UpdateStatusHandler updateStatus,
                                             Track[] tracks, bool supportsPqSubchannel, bool supportsRwSubchannel,
                                             Database.Models.Device dbDev, out bool inexactPositioning)
        {
            bool                  sense  = true; // Sense indicator
            byte[]                subBuf = null;
            int                   posQ;
            uint                  retries;
            bool?                 bcd = null;
            byte[]                crc;
            Dictionary<uint, int> pregaps = new Dictionary<uint, int>();
            inexactPositioning = false;

            if(!supportsPqSubchannel &&
               !supportsRwSubchannel)
                return;

            // Check if subchannel is BCD
            for(retries = 0; retries < 10; retries++)
            {
                sense = supportsRwSubchannel ? GetSectorForPregapRaw(dev, 11, dbDev, out subBuf, false)
                            : GetSectorForPregapQ16(dev, 11, dbDev, out subBuf, false);

                if(sense)
                    continue;

                bcd = (subBuf[9] & 0x10) > 0;

                break;
            }

            AaruConsole.DebugWriteLine("Pregap calculator", bcd == true
                                                                ? "Subchannel is BCD"
                                                                : bcd == false
                                                                    ? "Subchannel is not BCD"
                                                                    : "Could not detect drive subchannel BCD");

            if(bcd is null)
            {
                dumpLog?.WriteLine("Could not detect if drive subchannel is BCD or not, pregaps could not be calculated, dump may be incorrect...");

                updateStatus?.
                    Invoke("Could not detect if drive subchannel is BCD or not, pregaps could not be calculated, dump may be incorrect...");

                return;
            }

            // Initialize the dictionary
            for(int i = 0; i < tracks.Length; i++)
                pregaps[tracks[i].TrackSequence] = 0;

            for(int t = 0; t < tracks.Length; t++)
            {
                Track track        = tracks[t];
                int   trackRetries = 0;

                // First track of each session has at least 150 sectors of pregap and is not readable always
                if(tracks.Where(t => t.TrackSession == track.TrackSession).OrderBy(t => t.TrackSequence).
                          FirstOrDefault().TrackSequence == track.TrackSequence)
                {
                    AaruConsole.DebugWriteLine("Pregap calculator", "Skipping track {0}", track.TrackSequence);

                    if(track.TrackSequence > 1)
                        pregaps[track.TrackSequence] = 150;

                    continue;
                }

                if(t                       > 0 &&
                   tracks[t - 1].TrackType == tracks[t].TrackType)
                {
                    AaruConsole.DebugWriteLine("Pregap calculator", "Skipping track {0}", track.TrackSequence);

                    continue;
                }

                AaruConsole.DebugWriteLine("Pregap calculator", "Track {0}", track.TrackSequence);

                int   lba           = (int)track.TrackStartSector - 1;
                bool  pregapFound   = false;
                Track previousTrack = tracks.FirstOrDefault(t => t.TrackSequence == track.TrackSequence - 1);

                bool goneBack                      = false;
                bool goFront                       = false;
                bool forward                       = false;
                bool crcOk                         = false;
                bool previousPregapIsPreviousTrack = false;

                // Check if pregap is 0
                for(retries = 0; retries < 10 && !pregapFound; retries++)
                {
                    sense = supportsRwSubchannel
                                ? GetSectorForPregapRaw(dev, (uint)lba, dbDev, out subBuf,
                                                        track.TrackType == TrackType.Audio)
                                : GetSectorForPregapQ16(dev, (uint)lba, dbDev, out subBuf,
                                                        track.TrackType == TrackType.Audio);

                    if(sense)
                    {
                        AaruConsole.DebugWriteLine("Pregap calculator", "LBA: {0}, Try {1}, Sense {2}", lba,
                                                   retries + 1, sense);

                        continue;
                    }

                    if(bcd == false)
                        BinaryToBcdQ(subBuf);

                    CRC16CCITTContext.Data(subBuf, 10, out crc);

                    AaruConsole.DebugWriteLine("Pregap calculator",
                                               "LBA: {0}, Try {1}, Sense {2}, Q: {3:X2} {4:X2} {5:X2} {6:X2} {7:X2} {8:X2} {9:X2} {10:X2} {11:X2} {12:X2} CRC 0x{13:X2}{14:X2}, Calculated CRC: 0x{15:X2}{16:X2}",
                                               lba, retries + 1, sense, subBuf[0], subBuf[1], subBuf[2], subBuf[3],
                                               subBuf[4], subBuf[5], subBuf[6], subBuf[7], subBuf[8], subBuf[9],
                                               subBuf[10], subBuf[11], crc[0], crc[1]);

                    crcOk = crc[0] == subBuf[10] && crc[1] == subBuf[11];

                    // Try to do a simple correction
                    if(!crcOk)
                    {
                        // Data track cannot have 11xxb in CONTROL
                        if((subBuf[0] & 0x40) > 0)
                            subBuf[0] &= 0x7F;

                        // ADR only uses two bits
                        subBuf[0] &= 0xF3;

                        // Don't care about other Q modes
                        if((subBuf[0] & 0xF) == 1)
                        {
                            // ZERO only used in DDCD
                            subBuf[6] = 0;

                            // Fix BCD numbering
                            for(int i = 1; i < 10; i++)
                            {
                                if((subBuf[i] & 0xF0) > 0xA0)
                                    subBuf[i] &= 0x7F;

                                if((subBuf[i] & 0x0F) > 0x0A)
                                    subBuf[i] &= 0xF7;
                            }
                        }

                        CRC16CCITTContext.Data(subBuf, 10, out crc);

                        crcOk = crc[0] == subBuf[10] && crc[1] == subBuf[11];

                        if(crcOk)
                        {
                            AaruConsole.DebugWriteLine("Pregap calculator",
                                                       "LBA: {0}, Try {1}, Sense {2}, Q (FIXED): {3:X2} {4:X2} {5:X2} {6:X2} {7:X2} {8:X2} {9:X2} {10:X2} {11:X2} {12:X2} CRC 0x{13:X2}{14:X2}, Calculated CRC: 0x{15:X2}{16:X2}",
                                                       lba, retries + 1, sense, subBuf[0], subBuf[1], subBuf[2],
                                                       subBuf[3], subBuf[4], subBuf[5], subBuf[6], subBuf[7], subBuf[8],
                                                       subBuf[9], subBuf[10], subBuf[11], crc[0], crc[1]);
                        }
                        else
                            continue;
                    }

                    BcdToBinaryQ(subBuf);

                    // Q position
                    if((subBuf[0] & 0xF) != 1)
                        continue;

                    posQ = ((subBuf[7] * 60 * 75) + (subBuf[8] * 75) + subBuf[9]) - 150;

                    if(subBuf[1] != track.TrackSequence - 1 ||
                       subBuf[2] == 0                       ||
                       posQ      != lba)
                        break;

                    pregaps[track.TrackSequence] = 0;

                    pregapFound = true;
                }

                if(pregapFound)
                    continue;

                // Calculate pregap
                lba = (int)track.TrackStartSector - 150;

                while(lba > (int)previousTrack.TrackStartSector &&
                      lba <= (int)track.TrackStartSector)
                {
                    // Some drives crash if you try to read just before the previous read, so seek away first
                    if(!forward)
                        sense = supportsRwSubchannel
                                    ? GetSectorForPregapRaw(dev, (uint)lba - 10, dbDev, out subBuf,
                                                            track.TrackType == TrackType.Audio)
                                    : GetSectorForPregapQ16(dev, (uint)lba - 10, dbDev, out subBuf,
                                                            track.TrackType == TrackType.Audio);

                    for(retries = 0; retries < 10; retries++)
                    {
                        sense = supportsRwSubchannel
                                    ? GetSectorForPregapRaw(dev, (uint)lba, dbDev, out subBuf,
                                                            track.TrackType == TrackType.Audio)
                                    : GetSectorForPregapQ16(dev, (uint)lba, dbDev, out subBuf,
                                                            track.TrackType == TrackType.Audio);

                        if(sense)
                            continue;

                        if(bcd == false)
                            BinaryToBcdQ(subBuf);

                        CRC16CCITTContext.Data(subBuf, 10, out crc);

                        AaruConsole.DebugWriteLine("Pregap calculator",
                                                   "LBA: {0}, Try {1}, Sense {2}, Q: {3:X2} {4:X2} {5:X2} {6:X2} {7:X2} {8:X2} {9:X2} {10:X2} {11:X2} {12:X2} CRC 0x{13:X2}{14:X2}, Calculated CRC: 0x{15:X2}{16:X2}",
                                                   lba, retries + 1, sense, subBuf[0], subBuf[1], subBuf[2], subBuf[3],
                                                   subBuf[4], subBuf[5], subBuf[6], subBuf[7], subBuf[8], subBuf[9],
                                                   subBuf[10], subBuf[11], crc[0], crc[1]);

                        crcOk = crc[0] == subBuf[10] && crc[1] == subBuf[11];

                        // Try to do a simple correction
                        if(!crcOk)
                        {
                            // Data track cannot have 11xxb in CONTROL
                            if((subBuf[0] & 0x40) > 0)
                                subBuf[0] &= 0x7F;

                            // ADR only uses two bits
                            subBuf[0] &= 0xF3;

                            // Don't care about other Q modes
                            if((subBuf[0] & 0xF) == 1)
                            {
                                // ZERO only used in DDCD
                                subBuf[6] = 0;

                                // Fix BCD numbering
                                for(int i = 1; i < 10; i++)
                                {
                                    if((subBuf[i] & 0xF0) > 0xA0)
                                        subBuf[i] &= 0x7F;

                                    if((subBuf[i] & 0x0F) > 0x0A)
                                        subBuf[i] &= 0xF7;
                                }
                            }

                            CRC16CCITTContext.Data(subBuf, 10, out crc);

                            crcOk = crc[0] == subBuf[10] && crc[1] == subBuf[11];

                            if(crcOk)
                            {
                                AaruConsole.DebugWriteLine("Pregap calculator",
                                                           "LBA: {0}, Try {1}, Sense {2}, Q (FIXED): {3:X2} {4:X2} {5:X2} {6:X2} {7:X2} {8:X2} {9:X2} {10:X2} {11:X2} {12:X2} CRC 0x{13:X2}{14:X2}, Calculated CRC: 0x{15:X2}{16:X2}",
                                                           lba, retries + 1, sense, subBuf[0], subBuf[1], subBuf[2],
                                                           subBuf[3], subBuf[4], subBuf[5], subBuf[6], subBuf[7],
                                                           subBuf[8], subBuf[9], subBuf[10], subBuf[11], crc[0],
                                                           crc[1]);

                                break;
                            }
                        }

                        if(crcOk)
                            break;
                    }

                    if(retries == 10)
                    {
                        if(sense)
                        {
                            trackRetries++;

                            if(trackRetries >= 10)
                            {
                                if(pregaps[track.TrackSequence] == 0)
                                {
                                    if((previousTrack.TrackType == TrackType.Audio &&
                                        track.TrackType         != TrackType.Audio) ||
                                       (previousTrack.TrackType != TrackType.Audio &&
                                        track.TrackType         == TrackType.Audio))
                                    {
                                        dumpLog?.
                                            WriteLine("Could not read subchannel for this track, supposing 150 sectors.");

                                        updateStatus?.
                                            Invoke("Could not read subchannel for this track, supposing 150 sectors.");
                                    }
                                    else
                                    {
                                        dumpLog?.
                                            WriteLine("Could not read subchannel for this track, supposing 0 sectors.");

                                        updateStatus?.
                                            Invoke("Could not read subchannel for this track, supposing 0 sectors.");
                                    }
                                }
                                else
                                {
                                    dumpLog?.
                                        WriteLine($"Could not read subchannel for this track, supposing {pregaps[track.TrackSequence]} sectors.");

                                    updateStatus?.
                                        Invoke($"Could not read subchannel for this track, supposing {pregaps[track.TrackSequence]} sectors.");
                                }

                                break;
                            }

                            dumpLog?.WriteLine($"Could not read subchannel for sector {lba}");
                            updateStatus?.Invoke($"Could not read subchannel for sector {lba}");

                            lba++;
                            forward = true;

                            continue;
                        }

                        dumpLog?.WriteLine($"Could not get correct subchannel for sector {lba}");
                        updateStatus?.Invoke($"Could not get correct subchannel for sector {lba}");
                    }

                    if(subBuf.All(b => b == 0))
                    {
                        inexactPositioning = true;

                        AaruConsole.DebugWriteLine("Pregap calculator", "All Q empty for LBA {0}", lba);

                        break;
                    }

                    BcdToBinaryQ(subBuf);

                    // If it's not Q position
                    if((subBuf[0] & 0xF) != 1)
                    {
                        // This means we already searched back, so search forward
                        if(goFront)
                        {
                            lba++;
                            forward = true;

                            if(lba == (int)previousTrack.TrackStartSector)
                                break;

                            continue;
                        }

                        // Search back
                        goneBack = true;
                        lba--;
                        forward = false;

                        continue;
                    }

                    // Previous track
                    if(subBuf[1] < track.TrackSequence)
                    {
                        lba++;
                        forward                       = true;
                        previousPregapIsPreviousTrack = true;

                        // Already gone back, so go forward
                        if(goneBack)
                            goFront = true;

                        continue;
                    }

                    // Same track, but not pregap
                    if(subBuf[1] == track.TrackSequence &&
                       subBuf[2] > 0)
                    {
                        lba--;
                        forward = false;

                        if(previousPregapIsPreviousTrack)
                            break;

                        continue;
                    }

                    previousPregapIsPreviousTrack = false;

                    // Pregap according to Q position
                    posQ = ((subBuf[7] * 60 * 75) + (subBuf[8] * 75) + subBuf[9]) - 150;
                    int diff    = posQ                               - lba;
                    int pregapQ = (int)track.TrackStartSector        - lba;

                    if(diff != 0)
                    {
                        AaruConsole.DebugWriteLine("Pregap calculator", "Invalid Q position for LBA {0}, got {1}", lba,
                                                   posQ);

                        inexactPositioning = true;
                    }

                    // Received a Q post the LBA we wanted, just go back. If we are already going forward, break
                    if(posQ > lba)
                    {
                        if(forward)
                            break;

                        lba--;

                        continue;
                    }

                    // Bigger than known change, otherwise we found it
                    if(pregapQ > pregaps[track.TrackSequence])
                    {
                        // If CRC is not OK, only accept pregaps less than 10 sectors longer than previously now
                        if(crcOk || pregapQ - pregaps[track.TrackSequence] < 10)
                        {
                            AaruConsole.DebugWriteLine("Pregap calculator", "Pregap for track {0}: {1}",
                                                       track.TrackSequence, pregapQ);

                            pregaps[track.TrackSequence] = pregapQ;
                        }

                        // We are going forward, so we have already been in the previous track, so add 1 to pregap and get out of here
                        else if(forward)
                        {
                            pregaps[track.TrackSequence]++;

                            break;
                        }
                    }
                    else if(pregapQ == pregaps[track.TrackSequence])
                        break;

                    lba--;
                    forward = false;
                }
            }

            for(int i = 0; i < tracks.Length; i++)
            {
                tracks[i].TrackPregap      =  (ulong)pregaps[tracks[i].TrackSequence];
                tracks[i].TrackStartSector -= tracks[i].TrackPregap;

            #if DEBUG
                dumpLog?.WriteLine($"Track {tracks[i].TrackSequence} pregap is {tracks[i].TrackPregap} sectors");
                updateStatus?.Invoke($"Track {tracks[i].TrackSequence} pregap is {tracks[i].TrackPregap} sectors");
            #endif
            }
        }
Esempio n. 12
0
 public void Crc16EmptyFile()
 {
     byte[] result = CRC16CCITTContext.File(Path.Combine(Consts.TestFilesRoot, "checksums", "empty"));
     Assert.AreEqual(ExpectedEmpty, result);
 }
Esempio n. 13
0
 public void Crc16RandomFile()
 {
     byte[] result = CRC16CCITTContext.File(Path.Combine(Consts.TestFilesRoot, "checksums", "random"));
     Assert.AreEqual(ExpectedRandom, result);
 }
Esempio n. 14
0
        public static void SolveTrackPregaps(Device dev, DumpLog dumpLog, UpdateStatusHandler updateStatus,
                                             Track[] tracks, bool supportsPqSubchannel, bool supportsRwSubchannel,
                                             Database.Models.Device dbDev, out bool inexactPositioning)
        {
            bool sense;                  // Sense indicator

            byte[] subBuf;
            int    posQ;
            uint   retries;
            bool?  bcd = null;

            byte[] crc;
            Dictionary <uint, int> pregaps = new Dictionary <uint, int>();

            inexactPositioning = false;

            if (!supportsPqSubchannel &&
                !supportsRwSubchannel)
            {
                return;
            }

            // Check if subchannel is BCD
            for (retries = 0; retries < 10; retries++)
            {
                sense = supportsRwSubchannel ? GetSectorForPregapRaw(dev, 11, dbDev, out subBuf)
                            : GetSectorForPregapQ16(dev, 11, dbDev, out subBuf);

                if (sense)
                {
                    continue;
                }

                bcd = (subBuf[9] & 0x10) > 0;

                break;
            }

            if (bcd is null)
            {
                dumpLog?.WriteLine("Could not detect if drive subchannel is BCD or not, pregaps could not be calculated, dump may be incorrect...");

                updateStatus?.
                Invoke("Could not detect if drive subchannel is BCD or not, pregaps could not be calculated, dump may be incorrect...");

                return;
            }

            // Initialize the dictionary
            for (int i = 0; i < tracks.Length; i++)
            {
                pregaps[tracks[i].TrackSequence] = 0;
            }

            foreach (Track track in tracks)
            {
                if (track.TrackSequence <= 1)
                {
                    continue;
                }

                int   lba           = (int)track.TrackStartSector - 1;
                bool  pregapFound   = false;
                Track previousTrack = tracks.FirstOrDefault(t => t.TrackSequence == track.TrackSequence - 1);

                bool goneBack = false;
                bool goFront  = false;

                // Check if pregap is 0
                for (retries = 0; retries < 10; retries++)
                {
                    sense = supportsRwSubchannel ? GetSectorForPregapRaw(dev, (uint)lba, dbDev, out subBuf)
                                : GetSectorForPregapQ16(dev, (uint)lba, dbDev, out subBuf);

                    if (sense)
                    {
                        continue;
                    }

                    if (bcd == false)
                    {
                        BinaryToBcdQ(subBuf);
                    }

                    CRC16CCITTContext.Data(subBuf, 10, out crc);

                    if (crc[0] != subBuf[10] ||
                        crc[1] != subBuf[11])
                    {
                        continue;
                    }

                    BcdToBinaryQ(subBuf);

                    // Q position
                    if ((subBuf[0] & 0xF) != 1)
                    {
                        continue;
                    }

                    posQ = ((subBuf[7] * 60 * 75) + (subBuf[8] * 75) + subBuf[9]) - 150;

                    if (subBuf[1] != track.TrackSequence - 1 ||
                        subBuf[2] == 0 ||
                        posQ != lba)
                    {
                        break;
                    }

                    pregaps[track.TrackSequence] = 0;

                    pregapFound = true;
                }

                if (pregapFound)
                {
                    continue;
                }

                // Calculate pregap
                lba = (int)track.TrackStartSector - 150;

                while (lba > (int)previousTrack.TrackStartSector)
                {
                    // Some drives crash if you try to read just before the previous read, so seek away first
                    sense = supportsRwSubchannel ? GetSectorForPregapRaw(dev, (uint)lba - 10, dbDev, out subBuf)
                                : GetSectorForPregapQ16(dev, (uint)lba - 10, dbDev, out subBuf);

                    for (retries = 0; retries < 10; retries++)
                    {
                        sense = supportsRwSubchannel ? GetSectorForPregapRaw(dev, (uint)lba, dbDev, out subBuf)
                                    : GetSectorForPregapQ16(dev, (uint)lba, dbDev, out subBuf);

                        if (sense)
                        {
                            continue;
                        }

                        if (bcd == false)
                        {
                            BinaryToBcdQ(subBuf);
                        }

                        CRC16CCITTContext.Data(subBuf, 10, out crc);

                        if (crc[0] == subBuf[10] &&
                            crc[1] == subBuf[11])
                        {
                            break;
                        }
                    }

                    if (retries == 10)
                    {
                        dumpLog?.WriteLine($"Could not get correct subchannel for sector {lba}");
                        updateStatus?.Invoke($"Could not get correct subchannel for sector {lba}");
                    }

                    BcdToBinaryQ(subBuf);

                    // If it's not Q position
                    if ((subBuf[0] & 0xF) != 1)
                    {
                        // This means we already searched back, so search forward
                        if (goFront)
                        {
                            lba++;

                            if (lba == (int)previousTrack.TrackStartSector)
                            {
                                break;
                            }

                            continue;
                        }

                        // Search back
                        goneBack = true;
                        lba--;

                        continue;
                    }

                    // Previous track
                    if (subBuf[1] < track.TrackSequence)
                    {
                        lba++;

                        // Already gone back, so go forward
                        if (goneBack)
                        {
                            goFront = true;
                        }

                        continue;
                    }

                    // Same track, but not pregap
                    if (subBuf[1] == track.TrackSequence &&
                        subBuf[2] > 0)
                    {
                        lba--;

                        continue;
                    }

                    // Pregap according to Q position
                    int pregapQ = (subBuf[3] * 60 * 75) + (subBuf[4] * 75) + subBuf[5] + 1;
                    posQ = ((subBuf[7] * 60 * 75) + (subBuf[8] * 75) + subBuf[9]) - 150;
                    int diff = posQ - lba;

                    if (diff != 0)
                    {
                        inexactPositioning = true;
                    }

                    // Bigger than known change, otherwise we found it
                    if (pregapQ > pregaps[track.TrackSequence])
                    {
                        pregaps[track.TrackSequence] = pregapQ;
                    }
                    else if (pregapQ == pregaps[track.TrackSequence])
                    {
                        break;
                    }

                    lba--;
                }
            }

            for (int i = 0; i < tracks.Length; i++)
            {
                tracks[i].TrackPregap       = (ulong)pregaps[tracks[i].TrackSequence];
                tracks[i].TrackStartSector -= tracks[i].TrackPregap;

            #if DEBUG
                dumpLog?.WriteLine($"Track {tracks[i].TrackSequence} pregap is {tracks[i].TrackPregap} sectors");
                updateStatus?.Invoke($"Track {tracks[i].TrackSequence} pregap is {tracks[i].TrackPregap} sectors");
            #endif
            }
        }
Esempio n. 15
0
        // Return true if indexes have changed
        bool WriteSubchannelToImage(MmcSubchannel supportedSubchannel, MmcSubchannel desiredSubchannel, byte[] sub,
                                    ulong sectorAddress, uint length, SubchannelLog subLog,
                                    Dictionary <byte, string> isrcs, byte currentTrack, ref string mcn, Track[] tracks)
        {
            if (supportedSubchannel == MmcSubchannel.Q16)
            {
                sub = Subchannel.ConvertQToRaw(sub);
            }

            if (desiredSubchannel != MmcSubchannel.None)
            {
                _outputPlugin.WriteSectorsTag(sub, sectorAddress, length, SectorTagType.CdSectorSubchannel);
            }

            subLog?.WriteEntry(sub, supportedSubchannel == MmcSubchannel.Raw, (long)sectorAddress, length);

            byte[] deSub = Subchannel.Deinterleave(sub);

            // Check subchannel
            for (int subPos = 0; subPos < deSub.Length; subPos += 96)
            {
                byte[] q = new byte[12];
                Array.Copy(deSub, subPos + 12, q, 0, 12);

                CRC16CCITTContext.Data(q, 10, out byte[] crc);
                bool crcOk = crc[0] == q[10] && crc[1] == q[11];

                // ISRC
                if ((q[0] & 0x3) == 3)
                {
                    string isrc = Subchannel.DecodeIsrc(q);

                    if (isrc == null ||
                        isrc == "000000000000")
                    {
                        continue;
                    }

                    if (!crcOk)
                    {
                        continue;
                    }

                    if (!isrcs.ContainsKey(currentTrack))
                    {
                        _dumpLog?.WriteLine($"Found new ISRC {isrc} for track {currentTrack}.");
                        UpdateStatus?.Invoke($"Found new ISRC {isrc} for track {currentTrack}.");
                    }
                    else if (isrcs[currentTrack] != isrc)
                    {
                        _dumpLog?.
                        WriteLine($"ISRC for track {currentTrack} changed from {isrcs[currentTrack]} to {isrc}.");

                        UpdateStatus?.
                        Invoke($"ISRC for track {currentTrack} changed from {isrcs[currentTrack]} to {isrc}.");
                    }

                    isrcs[currentTrack] = isrc;
                }
                else if ((q[0] & 0x3) == 2)
                {
                    string newMcn = Subchannel.DecodeMcn(q);

                    if (newMcn == null ||
                        newMcn == "0000000000000")
                    {
                        continue;
                    }

                    if (!crcOk)
                    {
                        continue;
                    }

                    if (mcn is null)
                    {
                        _dumpLog?.WriteLine($"Found new MCN {newMcn}.");
                        UpdateStatus?.Invoke($"Found new MCN {newMcn}.");
                    }
                    else if (mcn != newMcn)
                    {
                        _dumpLog?.WriteLine($"MCN changed from {mcn} to {newMcn}.");
                        UpdateStatus?.Invoke($"MCN changed from {mcn} to {newMcn}.");
                    }

                    mcn = newMcn;
                }
                else if ((q[0] & 0x3) == 1)
                {
                    // TODO: Indexes

                    // Pregap
                    if (q[2] != 0)
                    {
                        continue;
                    }

                    if (!crcOk)
                    {
                        continue;
                    }

                    byte trackNo = (byte)(((q[1] / 16) * 10) + (q[1] & 0x0F));

                    for (int i = 0; i < tracks.Length; i++)
                    {
                        if (tracks[i].TrackSequence != trackNo ||
                            trackNo == 1)
                        {
                            continue;
                        }

                        byte pmin   = (byte)(((q[3] / 16) * 10) + (q[3] & 0x0F));
                        byte psec   = (byte)(((q[4] / 16) * 10) + (q[4] & 0x0F));
                        byte pframe = (byte)(((q[5] / 16) * 10) + (q[5] & 0x0F));
                        int  qPos   = (pmin * 60 * 75) + (psec * 75) + pframe;

                        if (tracks[i].TrackPregap >= (ulong)(qPos + 1))
                        {
                            continue;
                        }

                        tracks[i].TrackPregap       = (ulong)(qPos + 1);
                        tracks[i].TrackStartSector -= tracks[i].TrackPregap;

                        if (i > 0)
                        {
                            tracks[i - 1].TrackEndSector = tracks[i].TrackStartSector - 1;
                        }

                        _dumpLog?.WriteLine($"Pregap for track {trackNo} set to {tracks[i].TrackPregap} sectors.");
                        UpdateStatus?.Invoke($"Pregap for track {trackNo} set to {tracks[i].TrackPregap} sectors.");

                        return(true);
                    }
                }
            }

            return(false);
        }