Esempio n. 1
0
            public Model(Stream stream, string path)
            {
                base._data = Data = new Mp3Format(this, stream, path);

                if (Data.FileSize > Int32.MaxValue)
                {
                    IssueModel.Add("File is insanely large", Severity.Fatal);
                    return;
                }

                int mediaPos32;
                int mediaCount32;

                byte[] fBuf;

                fBuf = Data.fBuf = new byte[Data.FileSize];
                Data.fbs.Position = 0;
                if (Data.fbs.Read(fBuf, 0, (int)Data.FileSize) != Data.FileSize)
                {
                    IssueModel.Add("Read error", Severity.Fatal);
                    return;
                }

                // Detect ID3v2 tag block.
                if (fBuf[0] == 'I' && fBuf[1] == 'D' && fBuf[2] == '3')
                {
                    Data.id3v2Pos = 0;
                    if (Data.FileSize < 10)
                    {
                        IssueModel.Add("File truncated near ID3v2 header", Severity.Fatal);
                        return;
                    }

                    Data.Id3v2Major    = Data.fBuf[3];
                    Data.Id3v2Revision = Data.fBuf[4];

                    Data.storedId3v2DataSize = ((fBuf[6] & 0x7F) << 21) + ((fBuf[7] & 0x7F) << 14) + ((fBuf[8] & 0x7F) << 7) + (fBuf[9] & 0x7F);
                    if (Data.storedId3v2DataSize == 0 || Data.storedId3v2DataSize + 12 > Data.FileSize)
                    {
                        IssueModel.Add("ID3v2 size of " + Data.storedId3v2DataSize + " is bad or file is truncated", Severity.Fatal);
                        return;
                    }

                    if ((fBuf[6] & 0x80) != 0 || (fBuf[7] & 0x80) != 0 || (fBuf[8] & 0x80) != 0 || (Data.fBuf[9] & 0x80) != 0)
                    {
                        IssueModel.Add("Zero parity error on ID3v2 size");
                    }

                    Data.actualId3v2DataSize = Data.storedId3v2DataSize;

                    // Check for bug in old versions of EAC that 1.5% of time writes ID3v2 size over by 1.
                    if (Data.Id3v2Major == 3)
                    {
                        if ((fBuf[10 + Data.storedId3v2DataSize] & 0xFE) == 0xFA)
                        {
                            if (fBuf[9 + Data.storedId3v2DataSize] == 0xFF)
                            {
                                --Data.actualId3v2DataSize;
                                // Bug bite comfirmed.
                                Data.Id3v2TagRepair = String.Format("0009=0x{0:X2}", Data.actualId3v2DataSize & 0x7F);
                                if ((Data.actualId3v2DataSize & 0x7F) == 0x7F)
                                {
                                    Data.Id3v2TagRepair = String.Format("0008=0x{0:X2}, ", ((Data.actualId3v2DataSize >> 7) & 0x7F)) + Data.Id3v2TagRepair;
                                }
                            }
                        }
                    }

                    Data.ValidSize = 10 + Data.actualId3v2DataSize;
                }

                while (Data.ValidSize < Data.FileSize && fBuf[Data.ValidSize] == 0)
                {
                    ++Data.ValidSize;
                    ++Data.DeadBytes;
                }

                if (Data.FileSize - Data.ValidSize < 0xC0)
                {
                    IssueModel.Add("File appears truncated.", Severity.Fatal);
                    return;
                }

                Data.Header = new Mp3Header(fBuf, (int)Data.ValidSize);

                if (!Data.Header.IsMpegLayer3)
                {
                    IssueModel.Add("ID3v2 tag present but no MP3 marker found.", Severity.Fatal);
                    return;
                }

                if (Data.Header.MpegVersionBits == 1)
                {
                    IssueModel.Add("MP3 marker found but MPEG version is not valid.", Severity.Fatal);
                    return;
                }

                mediaPos32     = (int)Data.ValidSize;
                Data.ValidSize = Data.FileSize;

                // Keep the audio header.
                Data.aBuf = new byte[Data.Header.XingOffset + 0x9C];
                Array.Copy(fBuf, mediaPos32, Data.aBuf, 0, Data.aBuf.Length);

                // Detect Xing/LAME encodes:

                XingModel = Mp3XingBlock.Create(Data.aBuf, Data.Header);
                if (XingModel != null)
                {
                    LameModel = XingModel as Mp3LameBlock.Model;
                    Data.Xing = XingModel.Data;
                    Data.Lame = Data.Xing as Mp3LameBlock;
                }

                // Detect ID3v1 tag block:

                int ePos = (int)Data.FileSize;

                if (ePos >= 130 && fBuf[ePos - 128] == 'T' && fBuf[ePos - 127] == 'A' && fBuf[ePos - 126] == 'G')
                {
                    ePos           -= 128;
                    Data.id3v1Block = new byte[128];
                    Array.Copy(fBuf, ePos, Data.id3v1Block, 0, 128);
                }

                // Detect obsolete Lyrics3v2 block:

                if (ePos >= 15)
                {
                    if (fBuf[ePos - 9] == 'L' && fBuf[ePos - 8] == 'Y' && fBuf[ePos - 7] == 'R' && fBuf[ePos - 6] == 'I' && fBuf[ePos - 5] == 'C' && fBuf[ePos - 4] == 'S' &&
                        fBuf[ePos - 3] == '2' && fBuf[ePos - 2] == '0' && fBuf[ePos - 1] == '0')
                    {
                        int l3size = 0;
                        for (var bi = ePos - 15; bi < ePos - 9; ++bi)
                        {
                            if (fBuf[bi] < '0' || fBuf[bi] > '9')
                            {
                                IssueModel.Add("Invalid Lyrics3v2 length digit.");
                                return;
                            }
                            l3size = l3size * 10 + fBuf[bi] - '0';
                        }

                        Data.Lyrics3Size = l3size + 15;
                        ePos            -= Data.Lyrics3Size;
                        if (ePos < 2)
                        {
                            IssueModel.Add("Invalid Lyrics3v2 length.");
                            return;
                        }
                    }
                }

                // Detect APE tag block:

                if (ePos >= 34)
                {
                    int pos = ePos - 32;
                    if (fBuf[pos] == 'A' && fBuf[pos + 1] == 'P' && fBuf[pos + 2] == 'E' &&
                        fBuf[pos + 3] == 'T' && fBuf[pos + 4] == 'A' && fBuf[pos + 5] == 'G' && fBuf[pos + 6] == 'E' && fBuf[pos + 7] == 'X')
                    {
                        Data.ApeSize = 32 + fBuf[pos + 12] + (fBuf[pos + 13] << 8) + (fBuf[pos + 14] << 16) + (fBuf[pos + 15] << 24);
                        ePos        -= Data.ApeSize;
                    }
                }

                if (ePos <= mediaPos32)
                {
                    IssueModel.Add("Missing audio", Severity.Fatal);
                    return;
                }

                mediaCount32 = ePos - mediaPos32;

                // Detect 2nd, phantom ID3v1 tag block:

                if (Data.Lame != null && mediaCount32 == Data.Lame.LameSize + 128 && Data.HasId3v1 && !Data.HasLyrics3 && !Data.HasApe && ePos > 34)
                {
                    if (fBuf[ePos - 128] == 'T' && fBuf[ePos - 127] == 'A' && fBuf[ePos - 126] == 'G')
                    {
                        ePos           -= 128;
                        mediaCount32   -= 128;
                        Data.ValidSize -= 128;

                        Data.excess     = Data.id3v1Block;
                        Data.id3v1Block = new byte[128];
                        Array.Copy(fBuf, ePos, Data.id3v1Block, 0, 128);
                        Data.Watermark = Likeliness.Probable;
                    }
                }

                Data.mediaPosition = mediaPos32;
                Data.MediaCount    = mediaCount32;

                GetDiagnostics();
            }
Esempio n. 2
0
            protected void ComputeContentHashes(CryptoHasher hasher, Hashes mediaHash = Hashes.None)
            {
                System.Diagnostics.Debug.Assert(Data.HashedFiles.HashLength == hasher.HashLength);

                for (int index = 0; index < Data.HashedFiles.Items.Count; ++index)
                {
                    HashedFile item       = Data.HashedFiles.Items[index];
                    string     msg        = null;
                    var        targetName = Data.HashedFiles.GetPath(index);

                    try
                    {
                        using (var tfs = new FileStream(targetName, FileMode.Open, FileAccess.Read))
                        {
                            HashedModel.SetIsFound(index, true);
                            byte[] hash = null;

                            if (item.Style == HashStyle.Media)
                            {
                                if (mediaHash == Hashes.None)
                                {
                                    IssueModel.Add("Unexpected media hash on item " + (index + 1) + ".");
                                }
                                else
                                {
                                    var hdr = new byte[0x3F];
                                    tfs.Position = 0;
                                    int             got = tfs.Read(hdr, 0, hdr.Length);
                                    Mp3Format.Model fmt = Mp3Format.CreateModel(tfs, hdr, targetName);
                                    if (fmt == null)
                                    {
                                        // Only MP3 supported for now.
                                        IssueModel.Add("Unexpected file format.");
                                    }
                                    else
                                    {
                                        fmt.CalcHashes(mediaHash, Validations.None);
                                        fmt.CloseFile();
                                        hash = fmt.Data.MediaSHA1;
                                    }
                                }
                            }
                            else
                            {
                                hasher.Append(tfs);
                                hash = hasher.GetHashAndReset();
                            }

                            HashedModel.SetActualHash(index, hash);
                            if (item.IsMatch == false)
                            {
                                IssueModel.Add(Data.HasherName + " mismatch on '" + item.FileName + "'.");
                            }
                        }
                    }
                    catch (FileNotFoundException ex)
                    { msg = ex.Message.TrimEnd(null); }
                    catch (IOException ex)
                    { msg = ex.Message.TrimEnd(null); }
                    catch (UnauthorizedAccessException ex)
                    { msg = ex.Message.TrimEnd(null); }

                    if (msg != null)
                    {
                        HashedModel.SetIsFound(index, false);
                        IssueModel.Add(msg);
                    }
                }

                string tx = Data.HasherName + " validation of " + Data.HashedFiles.Items.Count + " file";

                if (Data.HashedFiles.Items.Count != 1)
                {
                    tx += "s";
                }
                if (base.Data.Issues.MaxSeverity < Severity.Error)
                {
                    tx += " successful.";
                }
                else
                {
                    tx += " failed with " + Data.HashedFiles.FoundCount + " found and " + Data.HashedFiles.MatchCount + " matched.";
                }

                IssueModel.Add(tx, Severity.Advisory);
            }