예제 #1
0
        /// <summary>
        ///    Looks for a tag ending at a specified position and moves
        ///    the cursor to its start position.
        /// </summary>
        /// <param name="position">
        ///    A <see cref="long" /> value reference specifying at what
        ///    position the potential tag ends. If a tag is found,
        ///    this value will be updated to the position at which the
        ///    found tag starts.
        /// </param>
        /// <returns>
        ///    A <see cref="TagLib.TagTypes" /> value specifying the
        ///    type of tag found at the specified position, or <see
        ///    cref="TagTypes.None" /> if no tag was found.
        /// </returns>
        private TagTypes ReadTagInfo(ref long position)
        {
            if (position - read_size < 0)
            {
                return(TagTypes.None);
            }

            file.Seek(position - read_size);
            ByteVector data = file.ReadBlock(read_size);

            try {
                int offset = (int)(data.Count - TagLib.Ape.Footer.Size);
                if (data.ContainsAt(TagLib.Ape.Footer.FileIdentifier,
                                    offset))
                {
                    TagLib.Ape.Footer footer =
                        new TagLib.Ape.Footer(
                            data.Mid(offset));

                    // If the complete tag size is zero or
                    // the tag is a header, this indicates
                    // some sort of corruption.
                    if (footer.CompleteTagSize == 0 ||
                        (footer.Flags &
                         TagLib.Ape.FooterFlags.IsHeader) != 0)
                    {
                        return(TagTypes.None);
                    }

                    position -= footer.CompleteTagSize;
                    return(TagTypes.Ape);
                }

                offset = (int)(data.Count - TagLib.Id3v2.Footer.Size);
                if (data.ContainsAt(TagLib.Id3v2.Footer.FileIdentifier,
                                    offset))
                {
                    TagLib.Id3v2.Footer footer =
                        new TagLib.Id3v2.Footer(
                            data.Mid(offset));

                    position -= footer.CompleteTagSize;
                    return(TagTypes.Id3v2);
                }

                if (data.StartsWith(
                        TagLib.Id3v1.Tag.FileIdentifier))
                {
                    position -= TagLib.Id3v1.Tag.Size;
                    return(TagTypes.Id3v1);
                }
            } catch (CorruptFileException) {
            }

            return(TagTypes.None);
        }
예제 #2
0
        public static bool Find(out AudioHeader header, TagLib.File file, long position, int length)
        {
            if (file == null)
            {
                throw new ArgumentNullException("file");
            }
            long end = position + length;

            header = AudioHeader.Unknown;
            file.Seek(position);
            ByteVector buffer = file.ReadBlock(3);

            if (buffer.Count < 3)
            {
                return(false);
            }
            do
            {
                file.Seek(position + 3);
                buffer = buffer.Mid(buffer.Count - 3);
                buffer.Add(file.ReadBlock((int)File.BufferSize));
                for (int i = 0; i < buffer.Count - 3 && (length < 0 || position + i < end); i++)
                {
                    if (buffer[i] == 0xFF && buffer[i + 1] > 0xE0)
                    {
                        ByteVector data = buffer.Mid(i, 4);
                        if (GetHeaderError(data) == null)
                        {
                            try
                            {
                                header = new AudioHeader(data, file, position + i);
                                return(true);
                            }
                            catch (CorruptFileException)
                            {
                            }
                        }
                    }
                }
                position += File.BufferSize;
            }while(buffer.Count > 3 && (length < 0 || position < end));
            return(false);
        }
예제 #3
0
 public IsoSampleEntry(BoxHeader header, TagLib.File file, IsoHandlerBox handler) :
     base(header, handler)
 {
     if (file == null)
     {
         throw new ArgumentNullException("file");
     }
     file.Seek(base.DataPosition + 6);
     data_reference_index = file.ReadBlock(2).ToUShort();
 }
예제 #4
0
        /// <summary>
        ///    Loads the data of the current instance from a specified
        ///    file using the internal data position and size.
        /// </summary>
        /// <param name="file">
        ///    The <see cref="TagLib.File" /> from which the current
        ///    instance was read and from which to read the data.
        /// </param>
        /// <returns>
        ///    A <see cref="ByteVector" /> object containing the data
        ///    read from the file.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        ///    <paramref name="file" /> is <see langref="null" />.
        /// </exception>
        protected ByteVector LoadData(TagLib.File file)
        {
            if (file == null)
            {
                throw new ArgumentNullException("file");
            }

            file.Seek(DataPosition);
            return(file.ReadBlock(DataSize));
        }
예제 #5
0
        /// <summary>
        ///    Constructs and initializes a new instance of <see
        ///    cref="IsoVisualSampleEntry" /> with a provided header and
        ///    handler by reading the contents from a specified file.
        /// </summary>
        /// <param name="header">
        ///    A <see cref="BoxHeader" /> object containing the header
        ///    to use for the new instance.
        /// </param>
        /// <param name="file">
        ///    A <see cref="TagLib.File" /> object to read the contents
        ///    of the box from.
        /// </param>
        /// <param name="handler">
        ///    A <see cref="IsoHandlerBox" /> object containing the
        ///    handler that applies to the new instance.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///    <paramref name="file" /> is <see langword="null" />.
        /// </exception>
        public IsoAudioSampleEntry(BoxHeader header, TagLib.File file,
                                   IsoHandlerBox handler)
            : base(header, file, handler)
        {
            if (file == null)
            {
                throw new ArgumentNullException("file");
            }

            file.Seek(base.DataPosition + 8);
            channel_count = file.ReadBlock(2)
                            .ToUShort();
            sample_size = file.ReadBlock(2)
                          .ToUShort();
            file.Seek(base.DataPosition + 16);
            sample_rate = file.ReadBlock(4)
                          .ToUInt();
            children = LoadChildren(file);
        }
예제 #6
0
        protected ListTag(TagLib.File file, long position, int length)
        {
            if (file == null)
            {
                throw new System.ArgumentNullException("file");
            }

            file.Seek(position);
            fields = new List(file.ReadBlock(length));
        }
예제 #7
0
        protected FullBox(BoxHeader header, TagLib.File file, IsoHandlerBox handler) :
            base(header, handler)
        {
            if (file == null)
            {
                throw new ArgumentNullException("file");
            }
            file.Seek(base.DataPosition);
            ByteVector header_data = file.ReadBlock(4);

            version = header_data[0];
            flags   = header_data.Mid(1, 3).ToUInt();
        }
        /*
         * /// <summary>
         * ///    Contains the children of the box.
         * /// </summary>
         * private BoxList children;
         */

        #endregion



        #region Constructors

        /// <summary>
        ///    Constructs and initializes a new instance of <see
        ///    cref="IsoVisualSampleEntry" /> with a provided header and
        ///    handler by reading the contents from a specified file.
        /// </summary>
        /// <param name="header">
        ///    A <see cref="BoxHeader" /> object containing the header
        ///    to use for the new instance.
        /// </param>
        /// <param name="file">
        ///    A <see cref="TagLib.File" /> object to read the contents
        ///    of the box from.
        /// </param>
        /// <param name="handler">
        ///    A <see cref="IsoHandlerBox" /> object containing the
        ///    handler that applies to the new instance.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///    <paramref name="file" /> is <see langword="null" />.
        /// </exception>
        public IsoVisualSampleEntry(BoxHeader header, TagLib.File file,
                                    IsoHandlerBox handler)
            : base(header, file, handler)
        {
            file.Seek(base.DataPosition + 16);
            width  = file.ReadBlock(2).ToUShort();
            height = file.ReadBlock(2).ToUShort();

            /*
             * TODO: What are the children anyway?
             * children = LoadChildren (file);
             */
        }
예제 #9
0
 protected void Read(TagLib.File file, long position)
 {
     if (file == null)
     {
         throw new ArgumentNullException("file");
     }
     file.Mode = File.AccessMode.Read;
     if (position < 0 || position > file.Length - Footer.Size)
     {
         throw new ArgumentOutOfRangeException("position");
     }
     file.Seek(position);
     footer = new Footer(file.ReadBlock((int)Footer.Size));
     if (footer.TagSize == 0)
     {
         throw new CorruptFileException("Tag size out of bounds.");
     }
     if ((footer.Flags & FooterFlags.IsHeader) == 0)
     {
         file.Seek(position + Footer.Size - footer.TagSize);
     }
     Parse(file.ReadBlock((int)(footer.TagSize - Footer.Size)));
 }
예제 #10
0
        public BoxHeader(TagLib.File file, long position)
        {
            if (file == null)
            {
                throw new ArgumentNullException("file");
            }
            this.box       = null;
            this.from_disk = true;
            this.position  = position;
            file.Seek(position);
            ByteVector data   = file.ReadBlock(32);
            int        offset = 0;

            if (data.Count < 8 + offset)
            {
                throw new CorruptFileException("Not enough data in box header.");
            }
            header_size = 8;
            box_size    = data.Mid(offset, 4).ToUInt();
            box_type    = data.Mid(offset + 4, 4);
            if (box_size == 1)
            {
                if (data.Count < 8 + offset)
                {
                    throw new CorruptFileException("Not enough data in box header.");
                }
                header_size += 8;
                box_size     = data.Mid(offset, 8).ToULong();
                offset      += 8;
            }
            if (box_type == Mpeg4.BoxType.Uuid)
            {
                if (data.Count < 16 + offset)
                {
                    throw new CorruptFileException("Not enough data in box header.");
                }
                header_size  += 16;
                extended_type = data.Mid(offset, 16);
            }
            else
            {
                extended_type = null;
            }
            if (box_size > (ulong)(file.Length - position))
            {
                throw new CorruptFileException("Box header specified a size of {0} bytes but only {1} bytes left in the file");
            }
        }
예제 #11
0
 public List(TagLib.File file, long position, int length)
 {
     if (file == null)
     {
         throw new ArgumentNullException("file");
     }
     if (length < 0)
     {
         throw new ArgumentOutOfRangeException("length");
     }
     if (position < 0 || position > file.Length - length)
     {
         throw new ArgumentOutOfRangeException("position");
     }
     file.Seek(position);
     Parse(file.ReadBlock(length));
 }
예제 #12
0
        public VideoHeader(TagLib.File file, long position)
        {
            if (file == null)
            {
                throw new ArgumentNullException("file");
            }
            file.Seek(position);
            ByteVector data = file.ReadBlock(7);

            if (data.Count < 7)
            {
                throw new CorruptFileException("Insufficient data in header.");
            }
            width            = data.Mid(0, 2).ToUShort() >> 4;
            height           = data.Mid(1, 2).ToUShort() & 0x0FFF;
            frame_rate_index = data[3] & 0x0F;
            bitrate          = (int)((data.Mid(4, 3).ToUInt() >> 6) & 0x3FFFF);
        }
예제 #13
0
 /// <summary>
 /// get the sha1 of media file data (not including tag info)
 /// </summary>
 /// <param name="file"></param>
 /// <returns></returns>
 public static byte[] MediaSHA1(TagLib.File file)
 {
     try
     {
         int len = (int)file.InvariantEndPosition - (int)file.InvariantStartPosition;
         file.Seek(file.InvariantStartPosition);
         //
         TagLib.ByteVector vector = file.ReadBlock(len);
         //
         byte[] data = vector.Data;
         return(Utility.CryptoFunctions.SHA1(data));
     }
     catch (OutOfMemoryException e)
     {
         Trace.WriteLine("OutOfMemoryException - " + file, Utility.Logger.Level.Error.ToString());
         return(null);
     }
 }
예제 #14
0
        public IsoHandlerBox(BoxHeader header, TagLib.File file, IsoHandlerBox handler) :
            base(header, file, handler)
        {
            if (file == null)
            {
                throw new System.ArgumentNullException("file");
            }
            file.Seek(DataPosition + 4);
            ByteVector box_data = file.ReadBlock(DataSize - 4);

            handler_type = box_data.Mid(0, 4);
            int end = box_data.Find((byte)0, 16);

            if (end < 16)
            {
                end = box_data.Count;
            }
            name = box_data.ToString(StringType.UTF8, 16, end - 16);
        }
예제 #15
0
        public IsoHandlerBox(BoxHeader header, TagLib.File file,
                             IsoHandlerBox handler)
            : base(header, file, handler)
        {
            if (file == null)
            {
                throw new ArgumentNullException("file");
            }

            file.Seek(DataPosition + 4);
            var box_data = file.ReadBlock(DataSize - 4);

            HandlerType = box_data.Mid(0, 4);

            var end = box_data.Find((byte)0, 16);

            if (end < 16)
            {
                end = box_data.Count;
            }
            Name = end > 16 ? box_data.ToString(StringType.UTF8, 16, end - 16) : string.Empty;
        }
예제 #16
0
        /// <summary>
        ///     Searches for an audio header in a <see cref="TagLib.File" /> starting at a specified position and searching through
        ///     a specified number of bytes.
        /// </summary>
        /// <param name="header">
        ///     A <see cref="AudioHeader" /> object in which the found
        ///     header will be stored.
        /// </param>
        /// <param name="file">
        ///     A <see cref="TagLib.File" /> object to search.
        /// </param>
        /// <param name="position">
        ///     A <see cref="long" /> value specifying the seek position
        ///     in <paramref name="file" /> at which to start searching.
        /// </param>
        /// <param name="length">
        ///     A <see cref="int" /> value specifying the maximum number
        ///     of bytes to search before aborting.
        /// </param>
        /// <returns>
        ///     A <see cref="bool" /> value indicating whether or not a
        ///     header was found.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="file" /> is <see langword="null" />.
        /// </exception>
        public static bool Find(out AudioHeader header,
                                TagLib.File file, long position, int length)
        {
            if (file == null)
            {
                throw new ArgumentNullException(nameof(file));
            }

            var end = position + length;

            header = Unknown;

            file.Seek(position);

            var buffer = file.ReadBlock(3);

            if (buffer.Count < 3)
            {
                return(false);
            }

            do
            {
                file.Seek(position + 3);
                buffer = buffer.Mid(buffer.Count - 3);
                buffer.Add(file.ReadBlock(
                               (int)TagLib.File.BufferSize));

                for (var i = 0;
                     i < buffer.Count - 3 &&
                     (length < 0 || position + i < end);
                     i++)
                {
                    if (buffer[i] == 0xFF &&
                        buffer[i + 1] >= 0xF0)                        // 0xFFF
                    {
                        try
                        {
                            var bits = new BitStream(buffer.Mid(i, 7)
                                                     .Data);

                            // 12 bits sync header
                            bits.ReadInt32(12);

                            // 1 bit mpeg 2/4
                            bits.ReadInt32(1);

                            // 2 bits layer
                            bits.ReadInt32(2);

                            // 1 bit protection absent
                            bits.ReadInt32(1);

                            // 2 bits profile object type
                            bits.ReadInt32(2);

                            // 4 bits sampling frequency index
                            var samplerateindex = bits.ReadInt32(4);
                            if (samplerateindex >= sample_rates.Length)
                            {
                                return(false);
                            }

                            long samplerate = sample_rates[samplerateindex];

                            // 1 bit private bit
                            bits.ReadInt32(1);

                            // 3 bits channel configuration
                            var channelconfigindex = bits.ReadInt32(3);
                            if (channelconfigindex >= channels.Length)
                            {
                                return(false);
                            }

                            // 4 copyright bits
                            bits.ReadInt32(4);

                            // 13 bits frame length
                            long framelength = bits.ReadInt32(13);                             // double check framelength
                            if (framelength < 7)
                            {
                                return(false);
                            }

                            // 11 bits buffer fullness
                            bits.ReadInt32(11);

                            // 2 bits number of raw data blocks in frame
                            var numberofframes = bits.ReadInt32(2) + 1;

                            long numberofsamples = numberofframes * 1024;
                            var  bitrate         = framelength * 8 * samplerate / numberofsamples;

                            header = new AudioHeader(channels[channelconfigindex],
                                                     (int)bitrate,
                                                     (int)samplerate,
                                                     (int)numberofsamples,
                                                     numberofframes);

                            return(true);
                        }
                        catch (CorruptFileException)
                        {
                        }
                    }
                }

                position += TagLib.File.BufferSize;
            } while (buffer.Count > 3 && (length < 0 || position < end));

            return(false);
        }
예제 #17
0
        /// <summary>
        ///    Constructs and initializes a new instance of <see
        ///    cref="IsoMovieHeaderBox" /> with a provided header and
        ///    handler by reading the contents from a specified file.
        /// </summary>
        /// <param name="header">
        ///    A <see cref="BoxHeader" /> object containing the header
        ///    to use for the new instance.
        /// </param>
        /// <param name="file">
        ///    A <see cref="TagLib.File" /> object to read the contents
        ///    of the box from.
        /// </param>
        /// <param name="handler">
        ///    A <see cref="IsoHandlerBox" /> object containing the
        ///    handler that applies to the new instance.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///    <paramref name="file" /> is <see langword="null" />.
        /// </exception>
        public IsoMovieHeaderBox(BoxHeader header, TagLib.File file,
                                 IsoHandlerBox handler)
            : base(header, file, handler)
        {
            if (file == null)
            {
                throw new ArgumentNullException("file");
            }

            int        bytes_remaining = DataSize;
            ByteVector data;

            if (Version == 1)
            {
                // Read version one (large integers).
                data = file.ReadBlock(Math.Min(28,
                                               bytes_remaining));
                if (data.Count >= 8)
                {
                    creation_time = data.Mid(0,
                                             8).ToULong();
                }
                if (data.Count >= 16)
                {
                    modification_time = data.Mid(8,
                                                 8).ToULong();
                }
                if (data.Count >= 20)
                {
                    timescale = data.Mid(16, 4).ToUInt();
                }
                if (data.Count >= 28)
                {
                    duration = data.Mid(20, 8).ToULong();
                }
                bytes_remaining -= 28;
            }
            else
            {
                // Read version zero (normal integers).
                data = file.ReadBlock(Math.Min(16,
                                               bytes_remaining));
                if (data.Count >= 4)
                {
                    creation_time = data.Mid(0,
                                             4).ToUInt();
                }
                if (data.Count >= 8)
                {
                    modification_time = data.Mid(4,
                                                 4).ToUInt();
                }
                if (data.Count >= 12)
                {
                    timescale = data.Mid(8, 4).ToUInt();
                }
                if (data.Count >= 16)
                {
                    duration = data.Mid(12, 4).ToUInt();
                }
                bytes_remaining -= 16;
            }

            data = file.ReadBlock(Math.Min(6, bytes_remaining));
            if (data.Count >= 4)
            {
                rate = data.Mid(0, 4).ToUInt();
            }
            if (data.Count >= 6)
            {
                volume = data.Mid(4, 2).ToUShort();
            }
            file.Seek(file.Tell + 70);
            bytes_remaining -= 76;

            data = file.ReadBlock(Math.Min(4,
                                           bytes_remaining));

            if (data.Count >= 4)
            {
                next_track_id = data.Mid(0, 4).ToUInt();
            }
        }
예제 #18
0
        /// <summary>
        ///    Constructs and initializes a new instance of <see
        ///    cref="AudioHeader" /> by reading its contents from a
        ///    <see cref="ByteVector" /> object and its Xing Header from
        ///    the appropriate location in the specified file.
        /// </summary>
        /// <param name="data">
        ///    A <see cref="ByteVector" /> object containing the header
        ///    to read.
        /// </param>
        /// <param name="file">
        ///    A <see cref="TagLib.File" /> object to read the Xing
        ///    header from.
        /// </param>
        /// <param name="position">
        ///    A <see cref="long" /> value indicating the position in
        ///    <paramref name="file" /> at which the header begins.
        /// </param>
        /// <exception cref="CorruptFileException">
        ///    <paramref name="data" /> is less than 4 bytes long,
        ///    does not begin with a MPEG audio synch, has a negative
        ///    bitrate, or has a sample rate of zero.
        /// </exception>
        private AudioHeader(ByteVector data, TagLib.File file,
                            long position)
        {
            this.duration = TimeSpan.Zero;
            stream_length = 0;

            if (data.Count < 4)
            {
                throw new CorruptFileException(
                          "Insufficient header length.");
            }

            if (data [0] != 0xFF)
            {
                throw new CorruptFileException(
                          "First byte did not match MPEG synch.");
            }

            if (data [1] < 0xE0)
            {
                throw new CorruptFileException(
                          "Second byte did not match MPEG synch.");
            }

            flags = data.ToUInt();

            if (((flags >> 12) & 0x0F) == 0x0F)
            {
                throw new CorruptFileException(
                          "Header uses invalid bitrate index.");
            }

            if (((flags >> 10) & 0x03) == 0x03)
            {
                throw new CorruptFileException(
                          "Invalid sample rate.");
            }

            xing_header = XingHeader.Unknown;

            vbri_header = VBRIHeader.Unknown;

            // Check for a Xing header that will help us in
            // gathering information about a VBR stream.
            file.Seek(position + XingHeader.XingHeaderOffset(
                          Version, ChannelMode));

            ByteVector xing_data = file.ReadBlock(16);

            if (xing_data.Count == 16 && xing_data.StartsWith(
                    XingHeader.FileIdentifier))
            {
                xing_header = new XingHeader(xing_data);
            }

            if (xing_header.Present)
            {
                return;
            }

            // A Xing header could not be found, next chec for a
            // Fraunhofer VBRI header.
            file.Seek(position + VBRIHeader.VBRIHeaderOffset());

            // Only get the first 24 bytes of the Header.
            // We're not interested in the TOC entries.
            ByteVector vbri_data = file.ReadBlock(24);

            if (vbri_data.Count == 24 &&
                vbri_data.StartsWith(VBRIHeader.FileIdentifier))
            {
                vbri_header = new VBRIHeader(vbri_data);
            }
        }
예제 #19
0
        /// <summary>
        ///    Constructs and initializes a new instance of <see
        ///    cref="BoxHeader" /> by reading it from a specified seek
        ///    position in a specified file.
        /// </summary>
        /// <param name="file">
        ///    A <see cref="TagLib.File" /> object to read the new
        ///    instance from.
        /// </param>
        /// <param name="position">
        ///    A <see cref="long" /> value specifiying the seek position
        ///    in <paramref name="file" /> at which to start reading.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///    <paramref name="file" /> is <see langword="null" />.
        /// </exception>
        /// <exception cref="CorruptFileException">
        ///    There isn't enough data in the file to read the complete
        ///    header.
        /// </exception>
        public BoxHeader(TagLib.File file, long position)
        {
            if (file == null)
            {
                throw new ArgumentNullException("file");
            }

            this.box       = null;
            this.from_disk = true;
            this.position  = position;
            file.Seek(position);

            ByteVector data   = file.ReadBlock(32);
            int        offset = 0;

            if (data.Count < 8 + offset)
            {
                throw new CorruptFileException(
                          "Not enough data in box header.");
            }

            header_size = 8;
            box_size    = data.Mid(offset, 4).ToUInt();
            box_type    = data.Mid(offset + 4, 4);

            // If the size is 1, that just tells us we have a
            // massive ULONG size waiting for us in the next 8
            // bytes.
            if (box_size == 1)
            {
                if (data.Count < 8 + offset)
                {
                    throw new CorruptFileException(
                              "Not enough data in box header.");
                }

                header_size += 8;
                offset      += 8;
                box_size     = data.Mid(offset, 8).ToULong();
            }

            // UUID has a special header with 16 extra bytes.
            if (box_type == Mpeg4.BoxType.Uuid)
            {
                if (data.Count < 16 + offset)
                {
                    throw new CorruptFileException(
                              "Not enough data in box header.");
                }

                header_size  += 16;
                extended_type = data.Mid(offset, 16);
            }
            else
            {
                extended_type = null;
            }

            if (box_size > (ulong)(file.Length - position))
            {
                throw new CorruptFileException(string.Format("Box header specified a size of {0} bytes but only {1} bytes left in the file", box_size, file.Length - position));
            }
        }