private AudioHeader(ByteVector data, TagLib.File file, long position) { this.duration = TimeSpan.Zero; stream_length = 0; string error = GetHeaderError(data); if (error != null) { throw new CorruptFileException(error); } flags = data.ToUInt(); xing_header = XingHeader.Unknown; vbri_header = VBRIHeader.Unknown; 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; } file.Seek(position + VBRIHeader.VBRIHeaderOffset()); ByteVector vbri_data = file.ReadBlock(24); if (vbri_data.Count == 24 && vbri_data.StartsWith(VBRIHeader.FileIdentifier)) { vbri_header = new VBRIHeader(vbri_data); } }
protected void Read(TagLib.File file) { if (file == null) { return; } try { file.Mode = FileAccessMode.Read; } catch (TagLibException) { return; } file.Seek(tagOffset); header.SetData(file.ReadBlock((int)Id3v2Header.Size)); // if the tag size is 0, then this is an invalid tag (tags must contain // at least one frame) if (header.TagSize == 0) { return; } Parse(file.ReadBlock((int)header.TagSize)); }
/// <summary> /// Populates the current instance be reading in a tag from /// a specified position in a specified file. /// </summary> /// <param name="file"> /// A <see cref="TagLib.File" /> object to read the tag from. /// </param> /// <param name="position"> /// A <see cref="long" /> value specifying the seek position /// at which to read the tag. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="file" /> is <see langword="null" />. /// </exception> /// <exception name="ArgumentOutOfRangeException"> /// <paramref name="position" /> is less than 0 or greater /// than the size of the file. /// </exception> 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 we've read a header, we don't have to seek to read // the content. If we've read a footer, we need to move // back to the start of the tag. if ((footer.Flags & FooterFlags.IsHeader) == 0) { file.Seek(position + Footer.Size - footer.TagSize); } Parse(file.ReadBlock((int)(footer.TagSize - Footer.Size))); }
/// <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] > 0xE0) { var data = buffer.Mid(i, 4); if (GetHeaderError(data) == null) { try { header = new AudioHeader( data, file, position + i); return(true); } catch (CorruptFileException) { } } } } position += TagLib.File.BufferSize; } while (buffer.Count > 3 && (length < 0 || position < end)); return(false); }
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(); }
/* * /// <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); */ }
/// <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; string error = GetHeaderError(data); if (error != null) { throw new CorruptFileException(error); } flags = data.ToUInt(); 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); } }
/// <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 langref="null" />. /// </exception> 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) { try { header = new AudioHeader( buffer.Mid(i, 4), file, position + i); return(true); } catch (CorruptFileException) { } } } position += File.BufferSize; } while (buffer.Count > 3 && (length < 0 || position < end)); return(false); }
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); }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="AppleAdditionalInfoBox" /> 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 AppleAdditionalInfoBox(BoxHeader header, TagLib.File file, IsoHandlerBox handler) : base(header, file, handler) { // We do not care what is in this custom data section // see: https://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap2/qtff2.html Data = file.ReadBlock(DataSize > 0 ? DataSize : 0); }
/// <summary> /// Constructs and initializes a new instance of /// <see /// cref="VideoHeader" /> /// by reading it from a specified /// location in a specified file. /// </summary> /// <param name="file"> /// A <see cref="TagLib.File" /> object to read 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="ArgumentNullException"> /// <paramref name="file" /> is <see langword="null" />. /// </exception> /// <exception cref="CorruptFileException"> /// Insufficient data could be read for the header. /// </exception> public VideoHeader(TagLib.File file, long position) { if (file == null) { throw new ArgumentNullException(nameof(file)); } file.Seek(position); var data = file.ReadBlock(7); if (data.Count < 7) { throw new CorruptFileException( "Insufficient data in header."); } VideoWidth = data.Mid(0, 2) .ToUShort() >> 4; VideoHeight = data.Mid(1, 2) .ToUShort() & 0x0FFF; frame_rate_index = data[3] & 0x0F; VideoBitrate = (int)((data.Mid(4, 3) .ToUInt() >> 6) & 0x3FFFF); }
/// <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 starts. If a tag is found, /// this value will be updated to the position at which the /// found tag ends. /// </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) { file.Seek(position); ByteVector data = file.ReadBlock(read_size); try { if (data.StartsWith(TagLib.Ape.Footer.FileIdentifier)) { TagLib.Ape.Footer footer = new TagLib.Ape.Footer(data); position += footer.CompleteTagSize; return(TagTypes.Ape); } if (data.StartsWith(TagLib.Id3v2.Header.FileIdentifier)) { TagLib.Id3v2.Header header = new TagLib.Id3v2.Header(data); position += header.CompleteTagSize; return(TagTypes.Id3v2); } } catch (CorruptFileException) { } return(TagTypes.None); }
/// <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); }
/// <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; box_size = data.Mid(offset, 8).ToULong(); offset += 8; } // 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; } }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="UnknownBox" /> 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 UnknownBox(BoxHeader header, TagLib.File file, IsoHandlerBox handler) : base(header, handler) { if (file == null) { throw new ArgumentNullException(nameof(file)); } data = file.ReadBlock(DataSize > 0 ? DataSize : 0); }
public IsoSampleDescriptionBox(BoxHeader header, TagLib.File file, IsoHandlerBox handler) : base(header, file, handler) { if (file == null) { throw new ArgumentNullException("file"); } entry_count = file.ReadBlock(4).ToUInt(); children = LoadChildren(file); }
/// <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)); }
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)); }
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(); }
public IsoChunkLargeOffsetBox(BoxHeader header, TagLib.File file, IsoHandlerBox handler) : base(header, file, handler) { ByteVector box_data = file.ReadBlock(DataSize); offsets = new ulong[(int)box_data.Mid(0, 4).ToUInt()]; for (int i = 0; i < offsets.Length; i++) { offsets[i] = box_data.Mid(4 + i * 8, 8).ToULong(); } }
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(); }
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))); }
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"); } }
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)); }
/// <summary> /// Constructs and initializes a new instance of /// <see /// cref="IsoChunkOffsetBox" /> /// 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> public IsoChunkOffsetBox(BoxHeader header, TagLib.File file, IsoHandlerBox handler) : base(header, file, handler) { var box_data = file.ReadBlock(DataSize); Offsets = new uint [(int) box_data.Mid(0, 4) .ToUInt()]; for (var i = 0; i < Offsets.Length; i++) { Offsets[i] = box_data.Mid(4 + i * 4, 4) .ToUInt(); } }
public AppleElementaryStreamDescriptor(BoxHeader header, TagLib.File file, IsoHandlerBox handler) : base(header, file, handler) { int offset = 0; ByteVector box_data = file.ReadBlock(DataSize); decoder_config = new ByteVector(); if (box_data[offset++] == 3) { if (ReadLength(box_data, ref offset) < 20) { throw new CorruptFileException("Insufficient data present."); } es_id = box_data.Mid(offset, 2).ToUShort(); offset += 2; stream_priority = box_data[offset++]; } else { es_id = box_data.Mid(offset, 2).ToUShort(); offset += 2; } if (box_data[offset++] != 4) { throw new CorruptFileException("Could not identify decoder configuration descriptor."); } if (ReadLength(box_data, ref offset) < 15) { throw new CorruptFileException("Could not read data. Too small."); } object_type_id = box_data[offset++]; stream_type = box_data[offset++]; buffer_size_db = box_data.Mid(offset, 3).ToUInt(); offset += 3; max_bitrate = box_data.Mid(offset, 4).ToUInt(); offset += 4; average_bitrate = box_data.Mid(offset, 4).ToUInt(); offset += 4; if (box_data[offset++] != 5) { throw new CorruptFileException("Could not identify decoder specific descriptor."); } uint length = ReadLength(box_data, ref offset); decoder_config = box_data.Mid(offset, (int)length); }
/// <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); } }
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); }
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; }
/// <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); }