private void Parse(ByteVector data) { // Check to see if a valid Xing header is available. if (!data.StartsWith("Xing")) return; // If the XingHeader doesn'type contain the number of frames and the total stream // info it'field invalid. if ((data[7] & 0x02) == 0) { TagLibDebugger.Debug("MPEG::XingHeader::parse() -- Xing header doesn't contain the total number of frames."); return; } if ((data[7] & 0x04) == 0) { TagLibDebugger.Debug("MPEG::XingHeader::parse() -- Xing header doesn't contain the total stream size."); return; } frames = data.Mid(8, 4).ToUInt(); size = data.Mid(12, 4).ToUInt(); valid = true; }
public static AviStream ParseStreamList (ByteVector data) { if (data == null) throw new ArgumentNullException ("data"); AviStream stream = null; int pos = 4; if (data.StartsWith ("strl")) while (pos + 8 < data.Count) { ByteVector id = data.Mid (pos, 4); int block_length = (int) data.Mid (pos + 4, 4).ToUInt (false); if (id == "strh" && stream == null) { AviStreamHeader stream_header = new AviStreamHeader (data, pos + 8); if (stream_header.Type == "vids") stream = new AviVideoStream (stream_header); else if (stream_header.Type == "auds") stream = new AviAudioStream (stream_header); } else if (stream != null) stream.ParseItem (id, data, pos + 8, block_length); pos += block_length + 8; } return stream; }
//private void Read(ByteVector data, long stream_length, ReadStyle style) private void Read(ByteVector data, long streamLength) { if (data.StartsWith("MP+")) return; version = data[3] & 15; uint frames; if (version >= 7) { frames = data.Mid(4, 4).ToUInt(false); uint flags = data.Mid(8, 4).ToUInt(false); sampleRate = sfTable[(int)(((flags >> 17) & 1) * 2 + ((flags >> 16) & 1))]; channels = 2; } else { uint headerData = data.Mid(0, 4).ToUInt(false); bitrate = (int)((headerData >> 23) & 0x01ff); version = (int)((headerData >> 11) & 0x03ff); sampleRate = 44100; channels = 2; if (version >= 5) frames = data.Mid(4, 4).ToUInt(false); else frames = data.Mid(4, 2).ToUInt(false); } uint samples = frames * 1152 - 576; duration = sampleRate > 0 ? TimeSpan.FromSeconds((double)samples / (double)sampleRate + 0.5) : TimeSpan.Zero; if (bitrate == 0) bitrate = (int)(duration > TimeSpan.Zero ? ((streamLength * 8L) / duration.TotalSeconds) / 1000 : 0); }
public XingHeader(ByteVector data) { if (data == null) { throw new ArgumentNullException("data"); } if (!data.StartsWith(FileIdentifier)) { throw new CorruptFileException("Not a valid Xing header"); } int startIndex = 8; if ((data[7] & 1) != 0) { this.frames = data.Mid(startIndex, 4).ToUInt(); startIndex += 4; } else { this.frames = 0; } if ((data[7] & 2) != 0) { this.size = data.Mid(startIndex, 4).ToUInt(); startIndex += 4; } else { this.size = 0; } this.present = true; }
public Footer (ByteVector data) { if (data.Count < Size) throw new CorruptFileException ("Provided data is smaller than object size."); if (!data.StartsWith (FileIdentifier)) throw new CorruptFileException ("Provided data does not start with File Identifier"); major_version = data [3]; revision_number = data [4]; flags = (HeaderFlags) data [5]; if (major_version == 2 && (flags & (HeaderFlags) 127) != 0) throw new CorruptFileException ("Invalid flags set on version 2 tag."); if (major_version == 3 && (flags & (HeaderFlags) 15) != 0) throw new CorruptFileException ("Invalid flags set on version 3 tag."); if (major_version == 4 && (flags & (HeaderFlags) 7) != 0) throw new CorruptFileException ("Invalid flags set on version 4 tag."); ByteVector size_data = data.Mid (6, 4); foreach (byte b in size_data) if (b >= 128) throw new CorruptFileException ("One of the bytes in the header was greater than the allowed 128."); tag_size = SynchData.ToUInt (size_data); }
public static AviStream ParseStreamList(ByteVector data) { int num2; if (data == null) { throw new ArgumentNullException("data"); } if (!data.StartsWith("strl")) { return null; } AviStream stream = null; for (int i = 4; (i + 8) < data.Count; i += num2 + 8) { ByteVector id = data.Mid(i, 4); num2 = (int) data.Mid(i + 4, 4).ToUInt(false); if ((id == "strh") && (stream == null)) { AviStreamHeader header = new AviStreamHeader(data, i + 8); if (header.Type == "vids") { stream = new AviVideoStream(header); } else if (header.Type == "auds") { stream = new AviAudioStream(header); } } else if (stream != null) { stream.ParseItem(id, data, i + 8, num2); } } return stream; }
public StreamHeader(ByteVector data, long streamLength) { if (data == null) { throw new ArgumentNullException("data"); } if (!data.StartsWith(FileIdentifier)) { throw new CorruptFileException("Data does not begin with identifier."); } if (data.Count < 0x38L) { throw new CorruptFileException("Insufficient data in stream header"); } this.stream_length = streamLength; this.version = data[3] & 15; if (this.version >= 7) { this.frames = data.Mid(4, 4).ToUInt(false); uint num = data.Mid(8, 4).ToUInt(false); this.sample_rate = sftable[(((num >> 0x11) & 1) * 2) + ((num >> 0x10) & 1)]; this.header_data = 0; } else { this.header_data = data.Mid(0, 4).ToUInt(false); this.version = ((int) (this.header_data >> 11)) & 0x3ff; this.sample_rate = 0xac44; this.frames = data.Mid(4, (this.version < 5) ? 2 : 4).ToUInt(false); } }
public Tag(ByteVector data) { if (data == null) { throw new ArgumentNullException("data"); } if (data.Count < 0x80L) { throw new CorruptFileException("ID3v1 data is less than 128 bytes long."); } if (!data.StartsWith(FileIdentifier)) { throw new CorruptFileException("ID3v1 data does not start with identifier."); } this.Parse(data); }
public VBRIHeader(ByteVector data) { if (data == null) { throw new ArgumentNullException("data"); } if (!data.StartsWith(FileIdentifier)) { throw new CorruptFileException("Not a valid VBRI header"); } int startIndex = 10; this.size = data.Mid(startIndex, 4).ToUInt(); startIndex += 4; this.frames = data.Mid(startIndex, 4).ToUInt(); startIndex += 4; this.present = true; }
public Footer(ByteVector data) { if (data == null) { throw new ArgumentNullException("data"); } if (data.Count < 10L) { throw new CorruptFileException("Provided data is smaller than object size."); } if (!data.StartsWith(FileIdentifier)) { throw new CorruptFileException("Provided data does not start with the file identifier"); } this.major_version = data[3]; this.revision_number = data[4]; this.flags = (HeaderFlags) data[5]; if ((this.major_version == 2) && ((((int) this.flags) & 0x7f) != 0)) { throw new CorruptFileException("Invalid flags set on version 2 tag."); } if ((this.major_version == 3) && ((((int) this.flags) & 15) != 0)) { throw new CorruptFileException("Invalid flags set on version 3 tag."); } if ((this.major_version == 4) && ((((int) this.flags) & 7) != 0)) { throw new CorruptFileException("Invalid flags set on version 4 tag."); } for (int i = 6; i < 10; i++) { if (data[i] >= 0x80) { throw new CorruptFileException("One of the bytes in the header was greater than the allowed 128."); } } this.tag_size = SynchData.ToUInt(data.Mid(6, 4)); }
public StreamHeader(ByteVector data, long streamLength) { if (data == null) { throw new ArgumentNullException("data"); } if (!data.StartsWith(FileIdentifier)) { throw new CorruptFileException("Data does not begin with identifier."); } if (data.Count < 0x4cL) { throw new CorruptFileException("Insufficient data in stream header"); } this.stream_length = streamLength; this.version = data.Mid(4, 2).ToUShort(false); this.compression_level = (CompressionLevel) data.Mid(0x34, 2).ToUShort(false); this.blocks_per_frame = data.Mid(0x38, 4).ToUInt(false); this.final_frame_blocks = data.Mid(60, 4).ToUInt(false); this.total_frames = data.Mid(0x40, 4).ToUInt(false); this.bits_per_sample = data.Mid(0x44, 2).ToUShort(false); this.channels = data.Mid(70, 2).ToUShort(false); this.sample_rate = data.Mid(0x48, 4).ToUInt(false); }
/// <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."); } // Checking bits from high to low: // // First 3 bits MUST be set. Bits 4 and 5 can // be 00, 10, or 11 but not 01. One or more of // bits 6 and 7 must be set. Bit 8 can be // anything. if ((data [1] & 0xE6) <= 0xE0 || (data [1] & 0x18) == 0x08) { 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); } }
private IFDEntry ParseMakernote(ushort tag, ushort type, uint count, long base_offset, uint offset) { long makernote_offset = base_offset + offset; IFDStructure ifd_structure = new IFDStructure(); // This is the minimum size a makernote should have // The shortest header is PENTAX_HEADER (4) // + IFD entry count (2) // + at least one IFD etry (12) // + next IFD pointer (4) // = 22 .... // we use this number to read a header which is big used // to identify the makernote types int header_size = 18; long length = 0; try { length = file.Length; } catch (Exception) { // Use a safety-value of 4 gigabyte. length = 1073741824L * 4; } if (makernote_offset > length) { throw new Exception("offset to makernote is beyond file size"); } if (makernote_offset + header_size > length) { throw new Exception("data is to short to contain a maker note ifd"); } // read header file.Seek(makernote_offset, SeekOrigin.Begin); ByteVector header = file.ReadBlock(header_size); if (header.StartsWith(PANASONIC_HEADER)) { IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, base_offset, offset + 12, max_offset); reader.ReadIFD(base_offset, offset + 12, max_offset); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Panasonic, PANASONIC_HEADER, 12, true, null)); } if (header.StartsWith(PENTAX_HEADER)) { IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, base_offset, offset + 6, max_offset); reader.ReadIFD(base_offset, offset + 6, max_offset); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Pentax, header.Mid(0, 6), 6, true, null)); } if (header.StartsWith(OLYMPUS1_HEADER)) { IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, base_offset, offset + 8, max_offset); reader.Read(); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Olympus1, header.Mid(0, 8), 8, true, null)); } if (header.StartsWith(OLYMPUS2_HEADER)) { IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, makernote_offset, 12, count); reader.Read(); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Olympus2, header.Mid(0, 12), 12, false, null)); } if (header.StartsWith(SONY_HEADER)) { IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, base_offset, offset + 12, max_offset); reader.ReadIFD(base_offset, offset + 12, max_offset); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Sony, SONY_HEADER, 12, true, null)); } if (header.StartsWith(NIKON_HEADER)) { ByteVector endian_bytes = header.Mid(10, 2); if (endian_bytes.ToString() == "II" || endian_bytes.ToString() == "MM") { bool makernote_endian = endian_bytes.ToString().Equals("MM"); ushort magic = header.Mid(12, 2).ToUShort(is_bigendian); if (magic == 42) { // TODO: the max_offset value is not correct here. However, some nikon files have offsets to a sub-ifd // (preview image) which are not stored with the other makernote data. Therfore, we keep the max_offset // for now. (It is just an upper bound for some checks. So if it is too big, it doesn't matter) var reader = new Nikon3MakernoteReader(file, makernote_endian, ifd_structure, makernote_offset + 10, 8, max_offset - offset - 10); reader.Read(); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Nikon3, header.Mid(0, 18), 8, false, makernote_endian)); } } } if (header.StartsWith(LEICA_HEADER)) { IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, makernote_offset, 8, count); reader.Read(); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Leica, header.Mid(0, 8), 10, false, null)); } try { IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, base_offset, offset, max_offset); reader.Read(); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Canon)); } catch { return(null); } }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="StreamHeader" /> for a specified header block and /// stream length. /// </summary> /// <param name="data"> /// A <see cref="ByteVector" /> object containing the stream /// header data. /// </param> /// <param name="streamLength"> /// A <see cref="long" /> value containing the length of the /// Monkey Audio stream in bytes. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="data" /> is <see langword="null" />. /// </exception> /// <exception cref="CorruptFileException"> /// <paramref name="data" /> does not begin with <see /// cref="FileIdentifier" /> or is less than <see cref="Size" /// /> bytes long. /// </exception> public StreamHeader(ByteVector data, long streamLength) { if (data == null) throw new ArgumentNullException("data"); if (!data.StartsWith(FileIdentifier)) throw new CorruptFileException( "Data does not begin with identifier."); if (data.Count < Size) throw new CorruptFileException( "Insufficient data in stream header"); stream_length = streamLength; version = data.Mid (4, 2).ToUShort(false); compression_level = (CompressionLevel) data.Mid(52, 2) .ToUShort(false); // format_flags = data.Mid(54, 2).ToUShort(false); blocks_per_frame = data.Mid(56, 4).ToUInt(false); final_frame_blocks = data.Mid(60, 4).ToUInt(false); total_frames = data.Mid(64, 4).ToUInt(false); bits_per_sample = data.Mid(68, 2).ToUShort(false); channels = data.Mid(70, 2).ToUShort(false); sample_rate = data.Mid(72, 4).ToUInt(false); }
private IFDEntry ParseMakernote(ushort tag, ushort type, uint count, long base_offset, uint offset) { long makernote_offset = base_offset + offset; IFDStructure ifd_structure = new IFDStructure(); int header_size = 18; long length = 0; try { length = file.Length; } catch (Exception) { length = 1073741824L * 4; } if (makernote_offset > length) { file.MarkAsCorrupt("offset to makernote is beyond file size"); return(null); } if (makernote_offset + header_size > length) { file.MarkAsCorrupt("data is to short to contain a maker note ifd"); return(null); } file.Seek(makernote_offset, SeekOrigin.Begin); ByteVector header = file.ReadBlock(header_size); if (header.StartsWith(PANASONIC_HEADER)) { IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, base_offset, offset + 12, max_offset); reader.ReadIFD(base_offset, offset + 12, max_offset); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Panasonic, PANASONIC_HEADER, 12, true, null)); } if (header.StartsWith(PENTAX_HEADER)) { IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, base_offset, offset + 6, max_offset); reader.ReadIFD(base_offset, offset + 6, max_offset); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Pentax, header.Mid(0, 6), 6, true, null)); } if (header.StartsWith(OLYMPUS1_HEADER)) { IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, base_offset, offset + 8, max_offset); reader.Read(); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Olympus1, header.Mid(0, 8), 8, true, null)); } if (header.StartsWith(OLYMPUS2_HEADER)) { IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, makernote_offset, 12, count); reader.Read(); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Olympus2, header.Mid(0, 12), 12, false, null)); } if (header.StartsWith(SONY_HEADER)) { IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, base_offset, offset + 12, max_offset); reader.ReadIFD(base_offset, offset + 12, max_offset); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Sony, SONY_HEADER, 12, true, null)); } if (header.StartsWith(NIKON_HEADER)) { ByteVector endian_bytes = header.Mid(10, 2); if (endian_bytes.ToString() == "II" || endian_bytes.ToString() == "MM") { bool makernote_endian = endian_bytes.ToString().Equals("MM"); ushort magic = header.Mid(12, 2).ToUShort(is_bigendian); if (magic == 42) { var reader = new Nikon3MakernoteReader(file, makernote_endian, ifd_structure, makernote_offset + 10, 8, max_offset - offset - 10); reader.Read(); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Nikon3, header.Mid(0, 18), 8, false, makernote_endian)); } } } if (header.StartsWith(LEICA_HEADER)) { IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, makernote_offset, 8, count); reader.Read(); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Leica, header.Mid(0, 8), 10, false, null)); } try { IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, base_offset, offset, max_offset); reader.Read(); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Canon)); } catch { return(null); } }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="StreamHeader" /> for a specified header block and /// stream length. /// </summary> /// <param name="data"> /// A <see cref="ByteVector" /> object containing the stream /// header data. /// </param> /// <param name="streamLength"> /// A <see cref="long" /> value containing the length of the /// DSF Audio stream in bytes. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="data" /> is <see langword="null" />. /// </exception> /// <exception cref="CorruptFileException"> /// <paramref name="data" /> does not begin with <see /// cref="FileIdentifier" /> /// </exception> public StreamHeader(ByteVector data, long streamLength) { if (data == null) throw new ArgumentNullException("data"); if (!data.StartsWith(FileIdentifier)) throw new CorruptFileException( "Data does not begin with identifier."); stream_length = streamLength; // The first 12 bytes contain the Format chunk identifier "fmt " // And the size of the format chunk, which is always 52 version = data.Mid(12, 4).ToUShort(false); format_id = data.Mid(16, 4).ToUShort(false); channel_type = data.Mid(20, 4).ToUShort(false); channels = data.Mid(24, 4).ToUShort(false); sample_rate = data.Mid(28, 4).ToULong(false); bits_per_sample = data.Mid(32, 4).ToUShort(false); sample_count = data.Mid(36, 8).ToULong(false); channel_blksize = data.Mid(44, 4).ToUShort(false); }
/// <summary> /// Construcor. /// </summary> /// <param name="tag"> /// A <see cref="System.UInt16"/> with the tag ID of the entry this instance /// represents /// </param> /// <param name="data"> /// A <see cref="ByteVector"/> to be stored /// </param> /// <param name="file"> /// The file that's currently being parsed, used for reporting corruptions. /// </param> public UserCommentIFDEntry(ushort tag, ByteVector data, TagLib.File file) { Tag = tag; if (data.StartsWith(COMMENT_ASCII_CODE)) { Value = TrimNull(data.ToString(StringType.Latin1, COMMENT_ASCII_CODE.Count, data.Count - COMMENT_ASCII_CODE.Count)); return; } if (data.StartsWith(COMMENT_UNICODE_CODE)) { Value = TrimNull(data.ToString(StringType.UTF8, COMMENT_UNICODE_CODE.Count, data.Count - COMMENT_UNICODE_CODE.Count)); return; } var trimmed = data.ToString().Trim(); if (trimmed.Length == 0 || trimmed == "\0") { Value = String.Empty; return; } // Some programs like e.g. CanonZoomBrowser inserts just the first 0x00-byte // followed by 7-bytes of trash. if (data.StartsWith((byte)0x00) && data.Count >= 8) { // And CanonZoomBrowser fills some trailing bytes of the comment field // with '\0'. So we return only the characters before the first '\0'. int term = data.Find("\0", 8); if (term != -1) { Value = data.ToString(StringType.Latin1, 8, term - 8); } else { Value = data.ToString(StringType.Latin1, 8, data.Count - 8); } return; } if (data.Data.Length == 0) { Value = String.Empty; return; } // Try to parse anyway int offset = 0; int length = data.Count - offset; // Corruption that starts with a Unicode header and a count byte. if (data.StartsWith(COMMENT_BAD_UNICODE_CODE)) { offset = COMMENT_BAD_UNICODE_CODE.Count; length = data.Count - offset; } file.MarkAsCorrupt("UserComment with other encoding than Latin1 or Unicode"); Value = TrimNull(data.ToString(StringType.UTF8, offset, length)); }
//Additional info here http://gabriel.mp3-tech.org/mp3infotag.html //https://www.codeproject.com/Articles/8295/MPEG-Audio-Frame-Header /// <summary>See if the mp3 file is encoded using VBR. Not sure what to do with ABR... /// </summary> private bool IsVBR() { bool bVBR = false; if (currentFile.MimeType != "taglib/mp3") { return(false); } foreach (ICodec codec in currentFile.Properties.Codecs) { TagLib.Mpeg.AudioHeader header = (TagLib.Mpeg.AudioHeader)codec; // if (header == null) // return; if (header.XingHeader.Present) { currentFile.Mode = TagLib.File.AccessMode.Read; long XingHeader = currentFile.Find(TagLib.Mpeg.XingHeader.FileIdentifier); long Offset = TagLib.Mpeg.XingHeader.XingHeaderOffset(header.Version, header.ChannelMode); TagLib.Mpeg.XingHeader xing_header = TagLib.Mpeg.XingHeader.Unknown; currentFile.Seek(XingHeader);// + Offset); ByteVector xing_data = currentFile.ReadBlock(16); if (xing_data.Count == 16 && xing_data.StartsWith( TagLib.Mpeg.XingHeader.FileIdentifier)) { xing_header = new TagLib.Mpeg.XingHeader(xing_data); } int Flags = BitConverter.ToInt32(xing_data.Take(8).ToArray().Reverse().ToArray(), 0); bool FramesPresent = (Flags & 0x0001) > 0; bool BytesPresent = (Flags & 0x0002) > 0; bool TOCPresent = (Flags & 0x0004) > 0; bool QualityPresent = (Flags & 0x0008) > 0; long LameHeader = currentFile.Find(LAME_Identifier); if (QualityPresent) { //Header offset + 8 (XING + flags) + Frames, Bytes and TOC if available currentFile.Seek(XingHeader + 8 + 4 * (FramesPresent ? 1 : 0) + 4 * (BytesPresent ? 1 : 0) + 100 * (TOCPresent ? 1 : 0)); ByteVector Quality_data = currentFile.ReadBlock(4); int VBRQuality = BitConverter.ToInt32(Quality_data.ToArray().Reverse().ToArray(), 0); bVBR = true; } currentFile.Mode = TagLib.File.AccessMode.Closed; // if (xing_header.Present) // return false; // var vector = new TagLib.ByteVector(); // TagLib.ByteVector xing = header.; /* CODE HERE */ /* TagLib.File ref(fileName); * TagLib.Mpeg.File *file = dynamic_cast<TagLib.Mpeg.File *>(ref file()); * * if(!file) * return; * * TagLib.Mpeg.Properties *properties = file->audioProperties(); * const TagLib::MPEG::XingHeader *xingHeader = properties->xingHeader(); * * if(!xingHeader) * return; */ } if (header.VBRIHeader.Present) { /* CODE HERE */ } } return(bVBR); }
/// <summary> /// Constructs and initializes a new instance of /// <see /// cref="StreamHeader" /> /// for a specified header block and /// stream length. /// </summary> /// <param name="data"> /// A <see cref="ByteVector" /> object containing the stream /// header data. /// </param> /// <param name="streamLength"> /// A <see cref="long" /> value containing the length of the /// AIFF Audio stream in bytes. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="data" /> is <see langword="null" />. /// </exception> /// <exception cref="CorruptFileException"> /// <paramref name="data" /> does not begin with /// <see /// cref="FileIdentifier" /> /// </exception> public StreamHeader(ByteVector data, long streamLength) { if (data == null) { throw new ArgumentNullException(nameof(data)); } if (!data.StartsWith(FileIdentifier)) { throw new CorruptFileException( "Data does not begin with identifier."); } stream_length = streamLength; // The first 8 bytes contain the Common chunk identifier "COMM" // And the size of the common chunk, which is always 18 channels = data.Mid(8, 2) .ToUShort(true); total_frames = data.Mid(10, 4) .ToULong(true); bits_per_sample = data.Mid(14, 2) .ToUShort(true); var sample_rate_indicator = data.Mid(17, 1); var sample_rate_tmp = data.Mid(18, 2) .ToULong(true); sample_rate = 44100; // Set 44100 as default sample rate // The following are combinations that iTunes 8 encodes to. // There may be other combinations in the field, but i couldn't test them. switch (sample_rate_tmp) { case 44100: if (sample_rate_indicator == 0x0E) { sample_rate = 44100; } else if (sample_rate_indicator == 0x0D) { sample_rate = 22050; } else if (sample_rate_indicator == 0x0C) { sample_rate = 11025; } break; case 48000: if (sample_rate_indicator == 0x0E) { sample_rate = 48000; } else if (sample_rate_indicator == 0x0D) { sample_rate = 24000; } break; case 64000: if (sample_rate_indicator == 0x0D) { sample_rate = 32000; } else if (sample_rate_indicator == 0x0C) { sample_rate = 16000; } else if (sample_rate_indicator == 0x0B) { sample_rate = 8000; } break; case 44510: if (sample_rate_indicator == 0x0D) { sample_rate = 22255; } break; case 44508: if (sample_rate_indicator == 0x0C) { sample_rate = 11127; } break; } }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="VBRIHeader" /> by reading its raw contents. /// </summary> /// <param name="data"> /// A <see cref="ByteVector" /> object containing the raw /// VBRI header. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="data" /> is <see langword="null" />. /// </exception> /// <exception cref="CorruptFileException"> /// <paramref name="data" /> does not start with <see /// cref="FileIdentifier" />. /// </exception> public VBRIHeader(ByteVector data) { if (data == null) throw new ArgumentNullException ("data"); // Check to see if a valid VBRI header is available. if (!data.StartsWith (FileIdentifier)) throw new CorruptFileException ( "Not a valid VBRI header"); // Size starts at Position 10 int position = 10; size = data.Mid(position, 4).ToUInt(); position += 4; // The number of Frames are found at Posistion 14 frames = data.Mid(position, 4).ToUInt(); position += 4; present = true; }
public StreamHeader(ByteVector data, long streamLength) { if (data == null) { throw new ArgumentNullException("data"); } if (!data.StartsWith(FileIdentifier)) { throw new CorruptFileException("Data does not begin with identifier."); } this.stream_length = streamLength; this.channels = data.Mid(8, 2).ToUShort(true); this.total_frames = data.Mid(10, 4).ToULong(true); this.bits_per_sample = data.Mid(14, 2).ToUShort(true); ByteVector vector = data.Mid(0x11, 1); ulong num = data.Mid(0x12, 2).ToULong(true); this.sample_rate = 0xac44L; ulong num2 = num; if ((num2 >= 0xaddcL) && (num2 <= 0xaddeL)) { switch (((int) (num2 - 0xaddcL))) { case 0: if (vector == 12) { this.sample_rate = 0x2b77L; } return; case 2: if (vector == 13) { this.sample_rate = 0x56efL; } return; } } if (num2 == 0xac44L) { if (vector == 14) { this.sample_rate = 0xac44L; } else if (vector == 13) { this.sample_rate = 0x5622L; } else if (vector == 12) { this.sample_rate = 0x2b11L; } } else if (num2 == 0xbb80L) { if (vector == 14) { this.sample_rate = 0xbb80L; } else if (vector == 13) { this.sample_rate = 0x5dc0L; } } else if (num2 == 0xfa00L) { if (vector == 13) { this.sample_rate = 0x7d00L; } else if (vector == 12) { this.sample_rate = 0x3e80L; } else if (vector == 11) { this.sample_rate = 0x1f40L; } } }
public void StartsWith () { Assert.IsTrue (TestVector.StartsWith ("ABCDE")); Assert.IsFalse (TestVector.StartsWith ("NOOP")); }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="StreamHeader" /> for a specified header block and /// stream length. /// </summary> /// <param name="data"> /// A <see cref="ByteVector" /> object containing the stream /// header data. /// </param> /// <param name="streamLength"> /// A <see cref="long" /> value containing the length of the /// MusePAck stream in bytes. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="data" /> is <see langword="null" />. /// </exception> /// <exception cref="CorruptFileException"> /// <paramref name="data" /> does not begin with <see /// cref="FileIdentifier" /> or is less than <see cref="Size" /// /> bytes long. /// </exception> public StreamHeader (ByteVector data, long streamLength) { if (data == null) throw new ArgumentNullException ("data"); if (!data.StartsWith (FileIdentifier)) throw new CorruptFileException ( "Data does not begin with identifier."); if (data.Count < Size) throw new CorruptFileException ( "Insufficient data in stream header"); stream_length = streamLength; version = data [3] & 15; if (version >= 7) { frames = data.Mid (4, 4).ToUInt (false); uint flags = data.Mid (8, 4).ToUInt (false); sample_rate = sftable [(int) (((flags >> 17) & 1) * 2 + ((flags >> 16) & 1))]; header_data = 0; } else { header_data = data.Mid (0, 4).ToUInt (false); version = (int) ((header_data >> 11) & 0x03ff); sample_rate = 44100; frames = data.Mid (4, version >= 5 ? 4 : 2).ToUInt (false); } }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="XingHeader" /> by reading its raw contents. /// </summary> /// <param name="data"> /// A <see cref="ByteVector" /> object containing the raw /// Xing header. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="data" /> is <see langword="null" />. /// </exception> /// <exception cref="CorruptFileException"> /// <paramref name="data" /> does not start with <see /// cref="FileIdentifier" />. /// </exception> public XingHeader(ByteVector data) { if (data == null) throw new ArgumentNullException ("data"); // Check to see if a valid Xing header is available. if (!data.StartsWith (FileIdentifier)) throw new CorruptFileException ( "Not a valid Xing header"); int position = 8; if ((data [7] & 0x01) != 0) { frames = data.Mid (position, 4).ToUInt (); position += 4; } else frames = 0; if ((data [7] & 0x02) != 0) { size = data.Mid (position, 4).ToUInt (); position += 4; } else size = 0; present = true; }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="StreamHeader" /> for a specified header block and /// stream length. /// </summary> /// <param name="data"> /// A <see cref="ByteVector" /> object containing the stream /// header data. /// </param> /// <param name="streamLength"> /// A <see cref="long" /> value containing the length of the /// AIFF Audio stream in bytes. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="data" /> is <see langword="null" />. /// </exception> /// <exception cref="CorruptFileException"> /// <paramref name="data" /> does not begin with <see /// cref="FileIdentifier" /> /// </exception> public StreamHeader(ByteVector data, long streamLength) { if (data == null) throw new ArgumentNullException("data"); if (!data.StartsWith(FileIdentifier)) throw new CorruptFileException( "Data does not begin with identifier."); stream_length = streamLength; // The first 8 bytes contain the Common chunk identifier "COMM" // And the size of the common chunk, which is always 18 channels = data.Mid(8, 2).ToUShort(true); total_frames = data.Mid(10, 4).ToULong(true); bits_per_sample = data.Mid(14, 2).ToUShort(true); ByteVector sample_rate_indicator = data.Mid(17, 1); ulong sample_rate_tmp = data.Mid(18, 2).ToULong(true); sample_rate = 44100; // Set 44100 as default sample rate // The following are combinations that iTunes 8 encodes to. // There may be other combinations in the field, but i couldn't test them. switch (sample_rate_tmp) { case 44100: if (sample_rate_indicator == 0x0E) { sample_rate = 44100; } else if (sample_rate_indicator == 0x0D) { sample_rate = 22050; } else if (sample_rate_indicator == 0x0C) { sample_rate = 11025; } break; case 48000: if (sample_rate_indicator == 0x0E) { sample_rate = 48000; } else if (sample_rate_indicator == 0x0D) { sample_rate = 24000; } break; case 64000: if (sample_rate_indicator == 0x0D) { sample_rate = 32000; } else if (sample_rate_indicator == 0x0C) { sample_rate = 16000; } else if (sample_rate_indicator == 0x0B) { sample_rate = 8000; } break; case 44510: if (sample_rate_indicator == 0x0D) { sample_rate = 22255; } break; case 44508: if (sample_rate_indicator == 0x0C) { sample_rate = 11127; } break; } }
/// <summary> /// Construcor. /// </summary> /// <param name="tag"> /// A <see cref="System.UInt16"/> with the tag ID of the entry this instance /// represents /// </param> /// <param name="data"> /// A <see cref="ByteVector"/> to be stored /// </param> public UserCommentIFDEntry (ushort tag, ByteVector data) { Tag = tag; if (data.StartsWith (COMMENT_ASCII_CODE)) { Value = data.ToString (StringType.Latin1, COMMENT_ASCII_CODE.Count, data.Count - COMMENT_ASCII_CODE.Count); return; } if (data.StartsWith (COMMENT_UNICODE_CODE)) { Value = data.ToString (StringType.UTF8, COMMENT_UNICODE_CODE.Count, data.Count - COMMENT_UNICODE_CODE.Count); return; } // Some programs like e.g. CanonZoomBrowser inserts just the first 0x00-byte // followed by 7-bytes of trash. if (data.StartsWith ((byte) 0x00) && data.Count >= 8) { // And CanonZoomBrowser fills some trailing bytes of the comment field // with '\0'. So we return only the characters before the first '\0'. int term = data.Find ("\0", 8); if (term != -1) { Value = data.ToString (StringType.Latin1, 8, term - 8); } else { Value = data.ToString (StringType.Latin1, 8, data.Count - 8); } return; } if (data.Data.Length == 0) { Value = String.Empty; return; } throw new NotImplementedException ("UserComment with other encoding than Latin1 or Unicode"); }
/// <summary> /// Reads an iTXt Chunk from file. The current position must be set /// to the start of the Chunk Data. Such a Chunk may contain XMP data /// or translated keywords. /// </summary> /// <param name="data_length"> /// A <see cref="System.Int32"/> with the length of the Chunk Data. /// </param> private void ReadiTXtChunk(int data_length) { long position = Tell; // iTXt Chunk // // N Bytes Keyword // 1 Byte Null Separator // 1 Byte Compression Flag (0 for uncompressed data) // 1 Byte Compression Method // N Bytes Language Tag // 1 Byte Null Separator // N Bytes Translated Keyword // 1 Byte Null Terminator // N Bytes Txt // // Followed by 4 Bytes CRC data ByteVector data = ReadChunkData(data_length); CheckCRC(iTXt_CHUNK_TYPE, data, ReadCRC()); // handle XMP, which has a fixed header if (data.StartsWith(XMP_CHUNK_HEADER)) { ImageTag.AddTag(new XmpTag(data.Mid(XMP_CHUNK_HEADER.Length).ToString(StringType.UTF8), this)); AddMetadataBlock(position - 8, data_length + 8 + 4); return; } int terminator_index; string keyword = ReadKeyword(data, 0, out terminator_index); if (terminator_index + 2 >= data_length) { throw new CorruptFileException("Compression Flag and Compression Method byte expected"); } byte compression_flag = data[terminator_index + 1]; byte compression_method = data[terminator_index + 2]; //string language = ReadTerminatedString (data, terminator_index + 3, out terminator_index); //string translated_keyword = ReadTerminatedString (data, terminator_index + 1, out terminator_index); ByteVector txt_data = data.Mid(terminator_index + 1); if (compression_flag != 0x00) { txt_data = Decompress(compression_method, txt_data); // ignore unknown compression methods if (txt_data == null) { return; } } string value = txt_data.ToString(); PngTag png_tag = GetTag(TagTypes.Png, true) as PngTag; if (png_tag.GetKeyword(keyword) == null) { png_tag.SetKeyword(keyword, value); } AddMetadataBlock(position - 8, data_length + 8 + 4); }
/// <summary> /// Construcor. /// </summary> /// <param name="tag"> /// A <see cref="System.UInt16"/> with the tag ID of the entry this instance /// represents /// </param> /// <param name="data"> /// A <see cref="ByteVector"/> to be stored /// </param> /// <param name="file"> /// The file that's currently being parsed, used for reporting corruptions. /// </param> public UserCommentIFDEntry(ushort tag, ByteVector data, TagLib.File file) { Tag = tag; if (data.StartsWith (COMMENT_ASCII_CODE)) { Value = TrimNull (data.ToString (StringType.Latin1, COMMENT_ASCII_CODE.Count, data.Count - COMMENT_ASCII_CODE.Count)); return; } if (data.StartsWith (COMMENT_UNICODE_CODE)) { Value = TrimNull (data.ToString (StringType.UTF8, COMMENT_UNICODE_CODE.Count, data.Count - COMMENT_UNICODE_CODE.Count)); return; } var trimmed = data.ToString ().Trim (); if (trimmed.Length == 0 || trimmed == "\0") { Value = String.Empty; return; } // Some programs like e.g. CanonZoomBrowser inserts just the first 0x00-byte // followed by 7-bytes of trash. if (data.StartsWith ((byte) 0x00) && data.Count >= 8) { // And CanonZoomBrowser fills some trailing bytes of the comment field // with '\0'. So we return only the characters before the first '\0'. int term = data.Find ("\0", 8); if (term != -1) { Value = data.ToString (StringType.Latin1, 8, term - 8); } else { Value = data.ToString (StringType.Latin1, 8, data.Count - 8); } return; } if (data.Data.Length == 0) { Value = String.Empty; return; } // Try to parse anyway int offset = 0; int length = data.Count - offset; // Corruption that starts with a Unicode header and a count byte. if (data.StartsWith (COMMENT_BAD_UNICODE_CODE)) { offset = COMMENT_BAD_UNICODE_CODE.Count; length = data.Count - offset; } file.MarkAsCorrupt ("UserComment with other encoding than Latin1 or Unicode"); Value = TrimNull (data.ToString (StringType.UTF8, offset, length)); }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="Header" /> by reading it from raw header data. /// </summary> /// <param name="data"> /// A <see cref="ByteVector" /> object containing the raw /// data to build the new instance from. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="data" /> is <see langword="null" />. /// </exception> /// <exception cref="CorruptFileException"> /// <paramref name="data" /> is smaller than <see /// cref="Size" />, does not begin with <see /// cref="FileIdentifier" />, contains invalid flag data, /// or contains invalid size data. /// </exception> public Header (ByteVector data) { if (data == null) throw new ArgumentNullException ("data"); if (data.Count < Size) throw new CorruptFileException ( "Provided data is smaller than object size."); if (!data.StartsWith (FileIdentifier)) throw new CorruptFileException ( "Provided data does not start with the file identifier"); major_version = data [3]; revision_number = data [4]; flags = (HeaderFlags) data [5]; if (major_version == 2 && ((int) flags & 127) != 0) throw new CorruptFileException ( "Invalid flags set on version 2 tag."); if (major_version == 3 && ((int) flags & 15) != 0) throw new CorruptFileException ( "Invalid flags set on version 3 tag."); if (major_version == 4 && ((int) flags & 7) != 0) throw new CorruptFileException ( "Invalid flags set on version 4 tag."); for (int i = 6; i < 10; i ++) if (data [i] >= 128) throw new CorruptFileException ( "One of the bytes in the header was greater than the allowed 128."); tag_size = SynchData.ToUInt (data.Mid (6, 4)); }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="PageHeader" /> by reading a raw Ogg page header /// from a specified position in a specified file. /// </summary> /// <param name="file"> /// A <see cref="File" /> object containing the file from /// which the contents of the new instance are to be read. /// </param> /// <param name="position"> /// A <see cref="long" /> value specify at what position to /// read. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="file" /> is <see langword="null" />. /// </exception> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="position" /> is less than zero or greater /// than the size of the file. /// </exception> /// <exception cref="CorruptFileException"> /// The Ogg identifier could not be found at the correct /// location. /// </exception> public PageHeader(File file, long position) { if (file == null) { throw new ArgumentNullException("file"); } if (position < 0 || position > file.Length - 27) { throw new ArgumentOutOfRangeException( "position"); } file.Seek(position); // An Ogg page header is at least 27 bytes, so we'll go // ahead and read that much and then get the rest when // we're ready for it. ByteVector data = file.ReadBlock(27); if (data.Count < 27 || !data.StartsWith("OggS")) { throw new CorruptFileException( "Error reading page header"); } version = data [4]; this.flags = (PageFlags)data [5]; absolute_granular_position = data.Mid(6, 8).ToULong( false); stream_serial_number = data.Mid(14, 4).ToUInt(false); page_sequence_number = data.Mid(18, 4).ToUInt(false); // Byte number 27 is the number of page segments, which // is the only variable length portion of the page // header. After reading the number of page segments // we'll then read in the coresponding data for this // count. int page_segment_count = data [26]; ByteVector page_segments = file.ReadBlock(page_segment_count); // Another sanity check. if (page_segment_count < 1 || page_segments.Count != page_segment_count) { throw new CorruptFileException( "Incorrect number of page segments"); } // The base size of an Ogg page 27 bytes plus the number // of lacing values. size = (uint)(27 + page_segment_count); packet_sizes = new List <int> (); int packet_size = 0; data_size = 0; for (int i = 0; i < page_segment_count; i++) { data_size += page_segments [i]; packet_size += page_segments [i]; if (page_segments [i] < 255) { packet_sizes.Add(packet_size); packet_size = 0; } } if (packet_size > 0) { packet_sizes.Add(packet_size); } }