Ejemplo n.º 1
0
            protected void ParseHashes()
            {
                Data.fbs.Position = 0;
                TextReader tr = new StreamReader(Data.fbs, Data.encoding);

                for (int line = 1;; ++line)
                {
                    var lx = tr.ReadLine();
                    if (lx == null)
                    {
                        return;
                    }

                    lx = lx.TrimStart();
                    if (lx.Length == 0 || lx[0] == ';')
                    {
                        continue;
                    }

                    if (lx.Length < Data.HashedFiles.HashLength * 2 + 3)
                    {
                        IssueModel.Add($"Too short, line {line}.", Severity.Fatal);
                        return;
                    }

                    // Try typical format with hash first.
                    byte[] hash = null;
                    if (lx[Data.HashedFiles.HashLength * 2] == ' ')
                    {
                        var modeChar = lx[Data.HashedFiles.HashLength * 2 + 1];

                        for (int modeIx = 1; modeIx < modeChars.Length; ++modeIx)
                        {
                            if (modeChar == modeChars[modeIx])
                            {
                                hash = ConvertTo.FromHexStringToBytes(lx, 0, Data.HashedFiles.HashLength);
                                if (hash != null)
                                {
                                    var targetName = lx.Substring(Data.HashedFiles.HashLength * 2 + 2);
                                    HashedModel.Add(targetName, hash, (HashMode)modeIx);
                                    break;
                                }
                            }
                        }

                        if (hash != null)
                        {
                            continue;
                        }
                    }

                    // Fall back to layout with name followed by hash.
                    if (lx[lx.Length - Data.HashedFiles.HashLength * 2 - 1] == ' ')
                    {
                        hash = ConvertTo.FromHexStringToBytes(lx, lx.Length - Data.HashedFiles.HashLength * 2, Data.HashedFiles.HashLength);
                        if (hash != null)
                        {
                            var targetName = lx.Substring(0, lx.Length - Data.HashedFiles.HashLength * 2 - 1);
                            HashedModel.Add(targetName, hash, HashMode.Binary);
                            continue;
                        }
                    }

                    IssueModel.Add($"Badly formed, line {line}.", Severity.Fatal);
                }
            }
Ejemplo n.º 2
0
            string Parse(LogBuffer parser)
            {
                string lx = null;

                ParseHeader();

                if (!Data.IsRangeRip)
                {
                    lx = ParseTracks();
                    if (Data.Issues.HasFatal)
                    {
                        return(null);
                    }
                }

                while (!parser.EOF && !lx.Contains("errors") && !lx.StartsWith("==== "))
                {
                    lx = parser.ReadLineLTrim();
                }

                if (lx == "No errors occured" || lx == "No errors occurred")
                {
                    lx = parser.ReadLineLTrim();
                }
                else if (lx == "There were errors")
                {
                    if (Data.Issues.MaxSeverity < Severity.Error)
                    {
                        IssueModel.Add("There were errors.");
                    }
                    lx = parser.ReadLineLTrim();
                }
                else
                {
                    IssueModel.Add("Missing 'errors' line.");
                }

                if (Data.IsRangeRip)
                {
                    if (lx == "AccurateRip summary")
                    {
                        for (;;)
                        {
                            lx = parser.ReadLineLTrim();
                            if (parser.EOF || !lx.StartsWith("Track "))
                            {
                                break;
                            }

                            if (lx.Contains("ccurately ripped (confidence "))
                            {
                                int arVersion    = lx.Contains("AR v2") ? 2 : 1;
                                int advanced     = ConvertTo.FromStringToInt32(lx, 40, out int val);
                                int arConfidence = advanced > 0 && val > 0 ? val : -1;
                                lx = parser.ReadLineLTrim();

                                if (Data.AccurateRipConfidence == null || Data.AccurateRipConfidence.Value > arConfidence)
                                {
                                    Data.AccurateRipConfidence = arConfidence;
                                }
                                if (Data.AccurateRip == null || Data.AccurateRip.Value > arVersion)
                                {
                                    Data.AccurateRip = arVersion;
                                }
                            }
                        }
                    }
                }

                if (lx == "All tracks accurately ripped")
                {
                    lx = parser.ReadLineLTrim();
                }

                if (lx.StartsWith("End of status report"))
                {
                    lx = parser.ReadLineLTrim();
                }

                if (lx.StartsWith("---- CUETools"))
                {
                    lx = ParseCueTools();
                }

                while (!parser.EOF && !lx.StartsWith("==== "))
                {
                    lx = parser.ReadLine();
                }

                if (lx.StartsWith("==== Log checksum ") && lx.Length >= 82)
                {
                    Data.storedHash = ConvertTo.FromHexStringToBytes(lx, 18, 32);

                    lx = parser.ReadLine();
                    if (!parser.EOF || !String.IsNullOrEmpty(lx))
                    {
                        IssueModel.Add("Unexpected content at end of file.", Severity.Warning, IssueTags.StrictErr);
                    }
                }

                return(lx);

                string ParseHeader()
                {
                    lx = parser.ReadLine();
                    if (lx.StartsWith("Exact Audio Copy V"))
                    {
                        var spacePos = lx.IndexOf(' ', 18);
                        if (spacePos > 0)
                        {
                            Data.EacVersionString = lx.Substring(18, spacePos - 18);
                        }

                        lx = parser.ReadLine();
                        lx = parser.ReadLine();
                    }

                    if (!lx.StartsWith("EAC extraction logfile from "))
                    {
                        IssueModel.Add("Unexpected contents, " + parser.GetPlace() + ": Expecting 'EAC extraction logfile'.");
                        return(lx);
                    }

                    lx = lx.Substring(28);
                    if (lx.Length < 12)
                    {
                        IssueModel.Add("Missing rip date, " + parser.GetPlace() + ".");
                        return(lx);
                    }
                    Data.RipDate = lx.EndsWith(" for CD") ? lx.Substring(0, lx.Length - 7) : lx;

                    lx = parser.ReadLine();
                    if (String.IsNullOrWhiteSpace(lx))
                    {
                        lx = parser.ReadLine();
                    }

                    int slashPos = lx.IndexOf('/');

                    if (slashPos < 0)
                    {
                        IssueModel.Add("Missing '<artist> / <album>', " + parser.GetPlace() + ".");
                        return(lx);
                    }
                    Data.RipArtist = lx.Substring(0, slashPos).Trim();
                    Data.RipAlbum  = lx.Substring(slashPos + 1).Trim();

                    for (;;)
                    {
TOP:
                        if (parser.EOF)
                        {
                            lx = String.Empty;
                            return(lx);
                        }

                        lx = parser.ReadLine();
                        if (lx.StartsWith("Track ") || lx.StartsWith("===="))
                        {
                            return(lx);
                        }

                        if (lx == "Range status and errors")
                        {
                            Data.IsRangeRip = true;
                            lx = parser.ReadLine();
                            return(lx);
                        }

                        if (lx == "TOC of the extracted CD")
                        {
                            for (Data.TocTrackCount = 0;;)
                            {
                                lx = parser.ReadLine();
                                if (parser.EOF || lx.StartsWith("==== ") || (lx.StartsWith("Track") && !lx.Contains("|")))
                                {
                                    return(lx);
                                }

                                if (lx == "Range status and errors")
                                {
                                    Data.IsRangeRip = true;
                                    lx = parser.ReadLine();
                                    return(lx);
                                }

                                if (lx.Length >= 60)
                                {
                                    if (int.TryParse(lx.Substring(0, 9), out int tn))
                                    {
                                        ++Data.TocTrackCount;
                                    }
                                }
                            }
                        }

                        int ik0 = 0, ik1 = 0, ii = 0, iv0 = 0, iv1;
                        for (;; ++ik0)
                        {
                            if (ik0 >= lx.Length)
                            {
                                goto TOP;
                            }
                            else if (lx[ik0] != ' ')
                            {
                                for (ii = ik0, ik1 = ii;;)
                                {
                                    ++ii;
                                    if (ii >= lx.Length)
                                    {
                                        string kk = lx.Substring(ik0, ik1 - ik0 + 1);
                                        if (kk == "Installed external ASPI interface" || kk == "Native Win32 interface for Win NT & 2000")
                                        {
                                            Data.Interface = kk;
                                        }
                                        goto TOP;
                                    }
                                    if (lx[ii] == ':')
                                    {
                                        break;
                                    }
                                    if (lx[ii] != ' ')
                                    {
                                        ik1 = ii;
                                    }
                                }

                                for (iv0 = ii + 1;; ++iv0)
                                {
                                    if (iv0 >= lx.Length)
                                    {
                                        goto TOP;
                                    }
                                    else if (lx[iv0] != ' ')
                                    {
                                        for (ii = iv0 + 1, iv1 = iv0;; ++ii)
                                        {
                                            if (ii == lx.Length)
                                            {
                                                break;
                                            }
                                            else if (lx[ii] != ' ')
                                            {
                                                iv1 = ii;
                                            }
                                        }

                                        string optKey = lx.Substring(ik0, ik1 - ik0 + 1),
                                               optVal = lx.Substring(iv0, iv1 - iv0 + 1);
                                        if (optKey == "Used drive")
                                        {
                                            Data.Drive = optVal;
                                        }
                                        else if (optKey == "Utilize accurate stream")
                                        {
                                            Data.AccurateStream = optVal;
                                        }
                                        else if (optKey == "Defeat audio cache")
                                        {
                                            Data.DefeatCache = optVal;
                                        }
                                        else if (optKey == "Make use of C2 pointers")
                                        {
                                            Data.UseC2 = optVal;
                                        }
                                        else if (optKey == "Read mode")
                                        {
                                            Data.ReadMode = optVal;
                                        }
                                        else if (optKey == "Read offset correction" || optKey == "Combined read/write offset correction")
                                        {
                                            Data.ReadOffset = optVal;
                                        }
                                        else if (optKey == "Overread into Lead-In and Lead-Out")
                                        {
                                            Data.Overread = optVal;
                                        }
                                        else if (optKey == "Fill up missing offset samples with silence")
                                        {
                                            Data.FillWithSilence = optVal;
                                        }
                                        else if (optKey == "Delete leading and trailing silent blocks")
                                        {
                                            Data.TrimSilence = optVal;
                                        }
                                        else if (optKey == "Null samples used in CRC calculations")
                                        {
                                            Data.CalcWithNulls = optVal;
                                        }
                                        else if (optKey == "Normalize to")
                                        {
                                            Data.NormalizeTo = optVal;
                                        }
                                        else if (optKey == "Used interface")
                                        {
                                            Data.Interface = optVal;
                                        }
                                        else if (optKey == "Gap handling")
                                        {
                                            Data.GapHandling = optVal;
                                        }
                                        else if (optKey == "Sample format")
                                        {
                                            Data.SampleFormat = optVal;
                                        }
                                        else if (optKey == "Quality")
                                        {
                                            Data.Quality = optVal;
                                        }
                                        else if (optKey == "Add ID3 tag")
                                        {
                                            Data.Id3Tag = optVal;
                                        }
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }

                string ParseTracks()
                {
                    for (;;)
                    {
                        if (parser.EOF ||
                            lx == "No errors occured" ||
                            lx == "No errors occurred" ||
                            lx == "There were errors" ||
                            lx.Contains("accurate"))
                        {
                            break;
                        }

                        if (!lx.StartsWith("Track") || lx.StartsWith("Track quality"))
                        {
                            lx = parser.ReadLineLTrim();
                            continue;
                        }

                        bool success = Int32.TryParse(lx.Substring(6), out int num);
                        if (!success)
                        {
                            Data.TkIssue = IssueModel.Add("Invalid track " + parser.GetPlace(), Severity.Fatal, IssueTags.Failure);
                            break;
                        }

                        lx = parser.ReadLineLTrim();
                        if (!lx.StartsWith("Filename "))
                        {
                            Data.TkIssue = IssueModel.Add($"Track {num}: Missing 'Filename'.", Severity.Error, IssueTags.Failure);
                        }
                        else
                        {
                            lx = ParseTrack(num);
                        }
                    }
                    return(lx);
                }

                string ParseTrack(int num)
                {
                    string name = "", peak = "", speed = "", pregap = "", qual = "";
                    int?   arVersion = null;
                    int?   arConfidence = null;
                    uint?  testCrc = null, copyCrc = null;
                    bool   trackErr = false;
                    uint   word;

                    name = lx.Substring(9);
                    if (name.Length < 10 || (lx.Length < 252 && !lx.EndsWith(".wav")))
                    {
                        IssueModel.Add("Unexpected extension " + parser.GetPlace());
                    }

                    lx = parser.ReadLineLTrim();
                    if (lx.StartsWith("Pre-gap length  "))
                    {
                        pregap = lx.Substring(16); lx = parser.ReadLineLTrim();
                    }

                    for (;;)
                    {
                        if (parser.EOF)
                        {
                            return(lx);
                        }

                        if (lx.StartsWith("Track quality") || lx.StartsWith("Peak level "))
                        {
                            break;
                        }

                        if (lx.StartsWith("Track "))
                        {
                            return(lx);  // Unexpected start of next track.
                        }
                        if (!trackErr)
                        {
                            trackErr = true;
                            IssueModel.Add($"Track {num}: '{lx}'.");
                        }
                        lx = parser.ReadLineLTrim();
                    }

                    if (lx.StartsWith("Peak level "))
                    {
                        peak = lx.Substring(11); lx = parser.ReadLineLTrim();
                    }

                    if (lx.StartsWith("Extraction speed "))
                    {
                        speed = lx.Substring(17); lx = parser.ReadLineLTrim();
                    }

                    if (lx.StartsWith("Track quality "))
                    {
                        qual = lx.Substring(14); lx = parser.ReadLineLTrim();
                    }

                    if (lx.StartsWith("Test CRC "))
                    {
                        if (uint.TryParse(lx.Substring(9), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out word))
                        {
                            testCrc = word;
                        }
                        else
                        {
                            Data.TpIssue = IssueModel.Add($"Track {num}: Invalid test CRC-32.", Severity.Error, IssueTags.Failure);
                        }
                        lx = parser.ReadLineLTrim();
                    }

                    if (!lx.StartsWith("Copy CRC "))
                    {
                        IssueModel.Add($"Track {num}: Missing copy CRC-32.", Severity.Warning);
                    }
                    else
                    {
                        if (uint.TryParse(lx.Substring(9), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out word))
                        {
                            copyCrc = word;
                        }
                        else
                        {
                            Data.TkIssue = IssueModel.Add($"Track {num}: Invalid copy CRC-32.", Severity.Error, IssueTags.Failure);
                        }
                        lx = parser.ReadLineLTrim();
                    }

                    if (lx.StartsWith("Accurately ripped (confidence "))
                    {
                        arVersion = lx.Contains("AR v2") ? 2 : 1;
                        int advanced = ConvertTo.FromStringToInt32(lx, 30, out int val);
                        arConfidence = advanced > 0 && val > 0 ? val : -1;
                        lx           = parser.ReadLineLTrim();
                    }
                    else if (lx.StartsWith("Cannot be verified"))
                    {
                        arVersion    = lx.Contains("AR v2") ? 2 : 1;
                        arConfidence = -1;
                        lx           = parser.ReadLineLTrim();
                    }
                    else if (lx.StartsWith("Track not present"))
                    {
                        if (peak != "0.0 %")
                        {
                            arConfidence = 0;
                        }
                        lx = parser.ReadLineLTrim();
                    }

                    if (arConfidence != null)
                    {
                        if (Data.AccurateRipConfidence == null || Data.AccurateRipConfidence > arConfidence)
                        {
                            Data.AccurateRipConfidence = arConfidence;
                        }
                        if (arVersion != null)
                        {
                            if (Data.AccurateRip == null || Data.AccurateRip.Value > arVersion.Value)
                            {
                                Data.AccurateRip = arVersion;
                            }
                        }
                    }

                    bool hasOK = false;

                    if (lx == "Copy OK")
                    {
                        hasOK = true;
                        lx    = parser.ReadLineLTrim();
                    }

                    TracksModel.Add(num, name, pregap, peak, speed, qual, testCrc, copyCrc, hasOK, arVersion, arConfidence);
                    return(lx);
                }

                string ParseCueTools()
                {
                    do
                    {
                        lx = parser.ReadLineLTrim();
                        if (parser.EOF || lx.StartsWith("==== "))
                        {
                            return(lx);
                        }
                    } while (!lx.StartsWith("[CTDB"));

                    if (lx.Contains("not present"))
                    {
                        Data.CueToolsConfidence = 0;
                        lx = parser.ReadLineLTrim();
                        if (!parser.EOF && lx.StartsWith("Submit"))
                        {
                            lx = parser.ReadLineLTrim();
                        }
                        return(lx);
                    }

                    if (!lx.Contains(" found"))
                    {
                        return(lx);
                    }

                    do
                    {
                        lx = parser.ReadLineLTrim();
                        if (parser.EOF || lx.StartsWith("==== "))
                        {
                            return(lx);
                        }

                        if (lx.StartsWith("["))
                        {
                            int ctConfidence = -1;
                            if (lx.Contains("Accurately ripped"))
                            {
                                int advanced = ConvertTo.FromStringToInt32(lx, 12, out ctConfidence);
                            }
                            Data.CueToolsConfidence = ctConfidence;
                            lx = parser.ReadLineLTrim();
                            return(lx);
                        }
                    } while (!lx.StartsWith("Track"));

                    for (int tx = 0; ; ++tx)
                    {
                        lx = parser.ReadLine();
                        if (parser.EOF || lx.StartsWith("==== ") || lx.StartsWith("All tracks"))
                        {
                            return(lx);
                        }

                        int ctConfidence;
                        if (lx.Contains("Accurately ripped"))
                        {
                            int advanced = ConvertTo.FromStringToInt32(lx, 9, out ctConfidence);
                            if (advanced == 0)
                            {
                                Data.CueToolsConfidence = -1; return(lx);
                            }
                        }
                        else if (lx.Contains("Differs"))
                        {
                            ctConfidence = -1;
                        }
                        else
                        {
                            break;
                        }

                        if (tx < TracksModel.Data.Items.Count)
                        {
                            TracksModel.SetCtConfidence(tx, ctConfidence);
                        }
                        if (Data.CueToolsConfidence == null || Data.CueToolsConfidence > ctConfidence)
                        {
                            Data.CueToolsConfidence = ctConfidence;
                        }
                    }
                    return(parser.ReadLineLTrim());
                }
            }