private void Parse(ByteVector data) { String currentKey, currentValue; int keyLen, valueLen; try { do { keyLen = (int)data.ToUInt(true); data.RemoveRange(0, 4); valueLen = (int)data.ToUInt(true); data.RemoveRange(0, 4); currentKey = data.ToString(TagLib.StringType.UTF8, 0, keyLen); data.RemoveRange(0, keyLen); currentValue = data.ToString(TagLib.StringType.UTF8, 0, valueLen); data.RemoveRange(0, valueLen); tags.Add(new KeyValuePair <string, string>(currentKey, currentValue)); if (data.Count != 0) { data.RemoveRange(0, 1); } }while(data.Count >= 4); } catch (Exception) { } if (data.Count != 0) { throw new CorruptFileException(); } }
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); } }
public override int GetHashCode() { unchecked { return((int)(size ^ width ^ height ^ planes ^ bit_count ^ compression_id.ToUInt() ^ size_of_image ^ x_pixels_per_meter ^ y_pixels_per_meter ^ colors_used ^ colors_important)); } }
/// <summary> /// Renders a complete entry together with the data. The entry itself /// is stored in <paramref name="entry_data"/> and the data of the /// entry is stored in <paramref name="offset_data"/> if it cannot be /// stored in the offset. This method is called for every <see /// cref="IFDEntry"/> of this IFD and can be overwritten in subclasses /// to provide special behavior. /// </summary> /// <param name="entry"> /// A <see cref="IFDEntry"/> with the entry to render. /// </param> /// <param name="entry_data"> /// A <see cref="ByteVector"/> to add the entry to. /// </param> /// <param name="offset_data"> /// A <see cref="ByteVector"/> to add the entry data to if it cannot be /// stored in the offset field. /// </param> /// <param name="data_offset"> /// A <see cref="System.UInt32"/> with the offset, were the data of the /// entries starts. It is needed to adjust the offsets of the entries /// itself. /// </param> protected virtual void RenderEntryData(IFDEntry entry, ByteVector entry_data, ByteVector offset_data, uint data_offset) { ushort tag = (ushort)entry.Tag; uint offset = (uint)(data_offset + offset_data.Count); ushort type; uint count; ByteVector data = entry.Render(is_bigendian, offset, out type, out count); // store data in offset, if it is smaller than 4 byte if (data.Count <= 4) { while (data.Count < 4) { data.Add("\0"); } offset = data.ToUInt(is_bigendian); data = null; } // preserve word boundary of offsets if (data != null && data.Count % 2 != 0) { data.Add("\0"); } RenderEntry(entry_data, tag, type, count, offset); offset_data.Add(data); }
private static string GetHeaderError(ByteVector data) { if (data.Count < 4) { return("Insufficient header length."); } if (data[0] != 0xFF) { return("First byte did not match MPEG synch."); } if ((data[1] & 0xE6) <= 0xE0 || (data[1] & 0x18) == 0x08) { return("Second byte did not match MPEG synch."); } uint flags = data.ToUInt(); if (((flags >> 12) & 0x0F) == 0x0F) { return("Header uses invalid bitrate index."); } if (((flags >> 10) & 0x03) == 0x03) { return("Invalid sample rate."); } return(null); }
/// <summary> /// Get a boolean from EBML Element's data section. /// </summary> /// <returns>a bool containing the parsed value.</returns> public bool GetBool() { if (Data == null) { return(false); } return(Data.ToUInt() > 0); }
/// <summary> /// Checks the CRC for a Chunk. /// </summary> /// <param name="chunk_type"> /// A <see cref="ByteVector"/> whith the Chunk type /// </param> /// <param name="chunk_data"> /// A <see cref="ByteVector"/> with the Chunk data. /// </param> /// <param name="crc_data"> /// A <see cref="ByteVector"/> with the read CRC data. /// </param> static void CheckCRC(ByteVector chunk_type, ByteVector chunk_data, ByteVector crc_data) { ByteVector computed_crc = ComputeCRC(chunk_type, chunk_data); if (computed_crc != crc_data) { throw new CorruptFileException( $"CRC check failed for {chunk_type} Chunk (expected: 0x{computed_crc.ToUInt ():X4}, read: 0x{crc_data.ToUInt ():X4}"); } }
/// <summary> /// Checks the CRC for a Chunk. /// </summary> /// <param name="chunk_type"> /// A <see cref="ByteVector"/> whith the Chunk type /// </param> /// <param name="chunk_data"> /// A <see cref="ByteVector"/> with the Chunk data. /// </param> /// <param name="crc_data"> /// A <see cref="ByteVector"/> with the read CRC data. /// </param> private static void CheckCRC(ByteVector chunk_type, ByteVector chunk_data, ByteVector crc_data) { ByteVector computed_crc = ComputeCRC(chunk_type, chunk_data); if (computed_crc != crc_data) { throw new CorruptFileException( String.Format("CRC check failed for {0} Chunk (expected: 0x{1:X4}, read: 0x{2:X4}", chunk_type.ToString(), computed_crc.ToUInt(), crc_data.ToUInt())); } }
public uint ReadUInt() { if (file == null) { return(0); } file.Seek((long)data_offset); ByteVector vector = file.ReadBlock((int)ebml_size); return(vector.ToUInt()); }
public EBMLElement(Matroska.File _file, ulong position) { if (_file == null) { throw new ArgumentNullException("file"); } if (position > (ulong)(_file.Length - 4)) { throw new ArgumentOutOfRangeException("position"); } file = _file; file.Seek((long)position); ByteVector vector = file.ReadBlock(1); Byte header_byte = vector[0]; Byte mask = 0x80, id_length = 1; while (id_length <= 4 && (header_byte & mask) == 0) { id_length++; mask >>= 1; } if (id_length > 4) { throw new CorruptFileException("invalid EBML id size"); } if (id_length > 1) { vector.Add(file.ReadBlock(id_length - 1)); } ebml_id = vector.ToUInt(); vector.Clear(); vector = file.ReadBlock(1); header_byte = vector[0]; mask = 0x80; Byte size_length = 1; while (size_length <= 8 && (header_byte & mask) == 0) { size_length++; mask >>= 1; } if (size_length > 8) { throw new CorruptFileException("invalid EBML element size"); } vector[0] &= (Byte)(mask - 1); if (size_length > 1) { vector.Add(file.ReadBlock(size_length - 1)); } ebml_size = vector.ToULong(); offset = position; data_offset = offset + id_length + size_length; }
/// <summary> /// Populates the current instance by parsing the contents of /// a raw AudibleMetadata tag. /// </summary> /// <param name="data"> /// A <see cref="ByteVector" /> object containing the whole tag /// object /// </param> /// <exception cref="CorruptFileException"> /// <paramref name="data" /> is less than 128 bytes or does /// not start with <see cref="FileIdentifier" />. /// </exception> private void Parse(ByteVector data) { String currentKey, currentValue; int keyLen, valueLen; try { do { keyLen = (int)data.ToUInt(true); data.RemoveRange(0, 4); valueLen = (int)data.ToUInt(true); data.RemoveRange(0, 4); currentKey = data.ToString(TagLib.StringType.UTF8, 0, keyLen); data.RemoveRange(0, keyLen); currentValue = data.ToString(TagLib.StringType.UTF8, 0, valueLen); data.RemoveRange(0, valueLen); tags.Add(new KeyValuePair <string, string>(currentKey, currentValue)); //StringHandle (currentKey, currentValue); // if it is not the last item remove the end byte (null terminated) if (data.Count != 0) { data.RemoveRange(0, 1); } }while (data.Count >= 4); } catch (Exception e) { System.Diagnostics.Debug.WriteLine(e); // } if (data.Count != 0) { throw new CorruptFileException(); } }
/// <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); } }
private int ReadChunkLength() { ByteVector data = ReadBlock(4); if (data.Count != 4) { throw new CorruptFileException("Unexpected end of Chunk Length"); } uint length = data.ToUInt(true); if (length > Int32.MaxValue) { throw new CorruptFileException("PNG limits the Chunk Length to 2^31-1"); } return((int)length); }
public bool ReadBool() { if (file == null) { return(false); } file.Seek((long)data_offset); ByteVector vector = file.ReadBlock((int)ebml_size); if (vector.ToUInt() > 0) { return(true); } else { return(false); } }
private ulong ReadSize(File file, ref uint packetSizeLength, ref bool eof) { uint tmp; ulong size = 0; do { ByteVector b = file.ReadBlock(1); if (b.IsEmpty) { eof = true; break; } tmp = b.ToUInt(); size = (size << 7) | (tmp & 0x7F); packetSizeLength++; }while((tmp & 0x80) == 1); return(size); }
private AudioHeader(ByteVector data, TagLib.File file, long position) { this.duration = TimeSpan.Zero; this.stream_length = 0L; 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] & 230) <= 0xe0) || ((data[1] & 0x18) == 8)) { throw new CorruptFileException("Second byte did not match MPEG synch."); } this.flags = data.ToUInt(); if (((this.flags >> 12) & 15) == 15) { throw new CorruptFileException("Header uses invalid bitrate index."); } if (((this.flags >> 10) & 3) == 3) { throw new CorruptFileException("Invalid sample rate."); } this.xing_header = TagLib.Mpeg.XingHeader.Unknown; this.vbri_header = TagLib.Mpeg.VBRIHeader.Unknown; file.Seek(position + TagLib.Mpeg.XingHeader.XingHeaderOffset(this.Version, this.ChannelMode)); ByteVector vector = file.ReadBlock(0x10); if ((vector.Count == 0x10) && vector.StartsWith(TagLib.Mpeg.XingHeader.FileIdentifier)) { this.xing_header = new TagLib.Mpeg.XingHeader(vector); } if (!this.xing_header.Present) { file.Seek(position + TagLib.Mpeg.VBRIHeader.VBRIHeaderOffset()); ByteVector vector2 = file.ReadBlock(0x18); if ((vector2.Count == 0x18) && vector2.StartsWith(TagLib.Mpeg.VBRIHeader.FileIdentifier)) { this.vbri_header = new TagLib.Mpeg.VBRIHeader(vector2); } } }
private static string GetHeaderError(ByteVector data) { if (data.Count < 4) { return("Insufficient header length."); } if (data [0] != 0xFF) { return("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) { return("Second byte did not match MPEG synch."); } uint flags = data.ToUInt(); if (((flags >> 12) & 0x0F) == 0x0F) { return("Header uses invalid bitrate index."); } if (((flags >> 10) & 0x03) == 0x03) { return("Invalid sample rate."); } return(null); }
protected virtual void RenderEntryData(IFDEntry entry, ByteVector entry_data, ByteVector offset_data, uint data_offset) { ushort tag = (ushort)entry.Tag; uint offset = (uint)(data_offset + offset_data.Count); ushort type; uint count; ByteVector data = entry.Render(is_bigendian, offset, out type, out count); if (data.Count <= 4) { while (data.Count < 4) { data.Add("\0"); } offset = data.ToUInt(is_bigendian); data = null; } if (data != null && data.Count % 2 != 0) { data.Add("\0"); } RenderEntry(entry_data, tag, type, count, offset); offset_data.Add(data); }
/// <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; info_header = XingHeader.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) { if (xing_data.StartsWith(XingHeader.XingFileIdentifier)) { xing_header = new XingHeader(xing_data); if (xing_header.Present) return; } if (xing_data.StartsWith(XingHeader.InfoFileIdentifier)) { info_header = new XingHeader(xing_data); if (info_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> /// Populates the current instance by parsing the contents of /// a raw AudibleMetadata tag. /// </summary> /// <param name="data"> /// A <see cref="ByteVector" /> object containing the whole tag /// object /// </param> /// <exception cref="CorruptFileException"> /// <paramref name="data" /> is less than 128 bytes or does /// not start with <see cref="FileIdentifier" />. /// </exception> private void Parse (ByteVector data) { String currentKey, currentValue; int keyLen, valueLen; try { do { keyLen = (int) data.ToUInt(true); data.RemoveRange (0, 4); valueLen = (int) data.ToUInt(true); data.RemoveRange (0, 4); currentKey = data.ToString ( TagLib.StringType.UTF8, 0, keyLen ); data.RemoveRange (0, keyLen); currentValue = data.ToString ( TagLib.StringType.UTF8, 0, valueLen ); data.RemoveRange (0, valueLen); tags.Add( new KeyValuePair<string, string>(currentKey, currentValue) ); //StringHandle (currentKey, currentValue); // if it is not the last item remove the end byte (null terminated) if (data.Count != 0) data.RemoveRange(0,1); } while (data.Count >= 4); } catch (Exception) { // } if (data.Count != 0) throw new CorruptFileException(); }
/// <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); } }
/// <summary> /// Checks the CRC for a Chunk. /// </summary> /// <param name="chunk_type"> /// A <see cref="ByteVector"/> whith the Chunk type /// </param> /// <param name="chunk_data"> /// A <see cref="ByteVector"/> with the Chunk data. /// </param> /// <param name="crc_data"> /// A <see cref="ByteVector"/> with the read CRC data. /// </param> private static void CheckCRC (ByteVector chunk_type, ByteVector chunk_data, ByteVector crc_data) { ByteVector computed_crc = ComputeCRC (chunk_type, chunk_data); if (computed_crc != crc_data) throw new CorruptFileException ( String.Format ("CRC check failed for {0} Chunk (expected: 0x{1:X4}, read: 0x{2:X4}", chunk_type.ToString (), computed_crc.ToUInt (), crc_data.ToUInt ())); }
private IFDEntry CreateIFDEntry(ushort tag, ushort type, uint count, long base_offset, ByteVector offset_data, uint max_offset) { uint offset = offset_data.ToUInt(is_bigendian); if (tag == (ushort)IFDEntryTag.IPTC && type == (ushort)IFDEntryType.Long) { type = (ushort)IFDEntryType.Byte; } var ifd_entry = ParseIFDEntry(tag, type, count, base_offset, offset); if (ifd_entry != null) { return(ifd_entry); } if (count > 0x10000000) { file.MarkAsCorrupt("Impossibly large item count"); return(null); } if (count == 1) { if (type == (ushort)IFDEntryType.Byte) { return(new ByteIFDEntry(tag, offset_data[0])); } if (type == (ushort)IFDEntryType.SByte) { return(new SByteIFDEntry(tag, (sbyte)offset_data[0])); } if (type == (ushort)IFDEntryType.Short) { return(new ShortIFDEntry(tag, offset_data.Mid(0, 2).ToUShort(is_bigendian))); } if (type == (ushort)IFDEntryType.SShort) { return(new SShortIFDEntry(tag, (ushort)offset_data.Mid(0, 2).ToUShort(is_bigendian))); } if (type == (ushort)IFDEntryType.Long) { return(new LongIFDEntry(tag, offset_data.ToUInt(is_bigendian))); } if (type == (ushort)IFDEntryType.SLong) { return(new SLongIFDEntry(tag, offset_data.ToInt(is_bigendian))); } } if (count == 2) { if (type == (ushort)IFDEntryType.Short) { ushort[] data = new ushort[] { offset_data.Mid(0, 2).ToUShort(is_bigendian), offset_data.Mid(2, 2).ToUShort(is_bigendian) }; return(new ShortArrayIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.SShort) { short[] data = new short[] { (short)offset_data.Mid(0, 2).ToUShort(is_bigendian), (short)offset_data.Mid(2, 2).ToUShort(is_bigendian) }; return(new SShortArrayIFDEntry(tag, data)); } } if (count <= 4) { if (type == (ushort)IFDEntryType.Undefined) { return(new UndefinedIFDEntry(tag, offset_data.Mid(0, (int)count))); } if (type == (ushort)IFDEntryType.Ascii) { string data = offset_data.Mid(0, (int)count).ToString(); int term = data.IndexOf('\0'); if (term > -1) { data = data.Substring(0, term); } return(new StringIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.Byte) { return(new ByteVectorIFDEntry(tag, offset_data.Mid(0, (int)count))); } } if (offset > max_offset) { return(new UndefinedIFDEntry(tag, new ByteVector())); } file.Seek(base_offset + offset, SeekOrigin.Begin); if (count == 1) { if (type == (ushort)IFDEntryType.Rational) { return(new RationalIFDEntry(tag, ReadRational())); } if (type == (ushort)IFDEntryType.SRational) { return(new SRationalIFDEntry(tag, ReadSRational())); } } if (count > 1) { if (type == (ushort)IFDEntryType.Long) { uint[] data = ReadUIntArray(count); return(new LongArrayIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.SLong) { int[] data = ReadIntArray(count); return(new SLongArrayIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.Rational) { Rational[] entries = new Rational[count]; for (int i = 0; i < count; i++) { entries[i] = ReadRational(); } return(new RationalArrayIFDEntry(tag, entries)); } if (type == (ushort)IFDEntryType.SRational) { SRational[] entries = new SRational[count]; for (int i = 0; i < count; i++) { entries[i] = ReadSRational(); } return(new SRationalArrayIFDEntry(tag, entries)); } } if (count > 2) { if (type == (ushort)IFDEntryType.Short) { ushort[] data = ReadUShortArray(count); return(new ShortArrayIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.SShort) { short[] data = ReadShortArray(count); return(new SShortArrayIFDEntry(tag, data)); } } if (count > 4) { if (type == (ushort)IFDEntryType.Long) { uint[] data = ReadUIntArray(count); return(new LongArrayIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.Byte) { ByteVector data = file.ReadBlock((int)count); return(new ByteVectorIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.Ascii) { string data = ReadAsciiString((int)count); return(new StringIFDEntry(tag, data)); } if (tag == (ushort)ExifEntryTag.UserComment) { ByteVector data = file.ReadBlock((int)count); return(new UserCommentIFDEntry(tag, data, file)); } if (type == (ushort)IFDEntryType.Undefined) { ByteVector data = file.ReadBlock((int)count); return(new UndefinedIFDEntry(tag, data)); } } if (type == (ushort)IFDEntryType.Float) { return(null); } if (type == 0 || type > 12) { file.MarkAsCorrupt("Invalid item type"); return(null); } throw new NotImplementedException(String.Format("Unknown type/count {0}/{1} ({2})", type, count, offset)); }
/// <summary> /// Creates an IFDEntry from the given values. This method is used for /// every entry. Custom parsing can be hooked in by overriding the /// <see cref="ParseIFDEntry(ushort,ushort,uint,long,uint)"/> method. /// </summary> /// <param name="tag"> /// A <see cref="System.UInt16"/> with the tag of the entry. /// </param> /// <param name="type"> /// A <see cref="System.UInt16"/> with the type of the entry. /// </param> /// <param name="count"> /// A <see cref="System.UInt32"/> with the data count of the entry. /// </param> /// <param name="base_offset"> /// A <see cref="System.Int64"/> with the base offset which every /// offsets in the IFD are relative to. /// </param> /// <param name="offset_data"> /// A <see cref="ByteVector"/> containing exactly 4 byte with the data /// of the offset of the entry. Since this field isn't interpreted as /// an offset if the data can be directly stored in the 4 byte, we /// pass the <see cref="ByteVector"/> to easier interpret it. /// </param> /// <param name="max_offset"> /// A <see cref="System.UInt32"/> with the maximal offset to consider for /// the IFD. /// </param> /// <returns> /// A <see cref="IFDEntry"/> with the given parameter. /// </returns> private IFDEntry CreateIFDEntry (ushort tag, ushort type, uint count, long base_offset, ByteVector offset_data, uint max_offset) { uint offset = offset_data.ToUInt (is_bigendian); // Fix the type for the IPTC tag. // From http://www.awaresystems.be/imaging/tiff/tifftags/iptc.html // "Often times, the datatype is incorrectly specified as LONG. " if (tag == (ushort) IFDEntryTag.IPTC && type == (ushort) IFDEntryType.Long) { type = (ushort) IFDEntryType.Byte; } var ifd_entry = ParseIFDEntry (tag, type, count, base_offset, offset); if (ifd_entry != null) return ifd_entry; if (count > 0x10000000) { // Some Nikon files are known to exhibit this corruption (or "feature"). file.MarkAsCorrupt ("Impossibly large item count"); return null; } // then handle the values stored in the offset data itself if (count == 1) { if (type == (ushort) IFDEntryType.Byte) return new ByteIFDEntry (tag, offset_data[0]); if (type == (ushort) IFDEntryType.SByte) return new SByteIFDEntry (tag, (sbyte)offset_data[0]); if (type == (ushort) IFDEntryType.Short) return new ShortIFDEntry (tag, offset_data.Mid (0, 2).ToUShort (is_bigendian)); if (type == (ushort) IFDEntryType.SShort) return new SShortIFDEntry (tag, (short) offset_data.Mid (0, 2).ToUShort (is_bigendian)); if (type == (ushort) IFDEntryType.Long) return new LongIFDEntry (tag, offset_data.ToUInt (is_bigendian)); if (type == (ushort) IFDEntryType.SLong) return new SLongIFDEntry (tag, offset_data.ToInt (is_bigendian)); } if (count == 2) { if (type == (ushort) IFDEntryType.Short) { ushort [] data = new ushort [] { offset_data.Mid (0, 2).ToUShort (is_bigendian), offset_data.Mid (2, 2).ToUShort (is_bigendian) }; return new ShortArrayIFDEntry (tag, data); } if (type == (ushort) IFDEntryType.SShort) { short [] data = new short [] { (short) offset_data.Mid (0, 2).ToUShort (is_bigendian), (short) offset_data.Mid (2, 2).ToUShort (is_bigendian) }; return new SShortArrayIFDEntry (tag, data); } } if (count <= 4) { if (type == (ushort) IFDEntryType.Undefined) return new UndefinedIFDEntry (tag, offset_data.Mid (0, (int)count)); if (type == (ushort) IFDEntryType.Ascii) { string data = offset_data.Mid (0, (int)count).ToString (); int term = data.IndexOf ('\0'); if (term > -1) data = data.Substring (0, term); return new StringIFDEntry (tag, data); } if (type == (ushort) IFDEntryType.Byte) return new ByteVectorIFDEntry (tag, offset_data.Mid (0, (int)count)); } // FIXME: create correct type. if (offset > max_offset) return new UndefinedIFDEntry (tag, new ByteVector ()); // then handle data referenced by the offset file.Seek (base_offset + offset, SeekOrigin.Begin); if (count == 1) { if (type == (ushort) IFDEntryType.Rational) return new RationalIFDEntry (tag, ReadRational ()); if (type == (ushort) IFDEntryType.SRational) return new SRationalIFDEntry (tag, ReadSRational ()); } if (count > 1) { if (type == (ushort) IFDEntryType.Long) { uint [] data = ReadUIntArray (count); return new LongArrayIFDEntry (tag, data); } if (type == (ushort) IFDEntryType.SLong) { int [] data = ReadIntArray (count); return new SLongArrayIFDEntry (tag, data); } if (type == (ushort) IFDEntryType.Rational) { Rational[] entries = new Rational [count]; for (int i = 0; i < count; i++) entries[i] = ReadRational (); return new RationalArrayIFDEntry (tag, entries); } if (type == (ushort) IFDEntryType.SRational) { SRational[] entries = new SRational [count]; for (int i = 0; i < count; i++) entries[i] = ReadSRational (); return new SRationalArrayIFDEntry (tag, entries); } } if (count > 2) { if (type == (ushort) IFDEntryType.Short) { ushort [] data = ReadUShortArray (count); return new ShortArrayIFDEntry (tag, data); } if (type == (ushort) IFDEntryType.SShort) { short [] data = ReadShortArray (count); return new SShortArrayIFDEntry (tag, data); } } if (count > 4) { if (type == (ushort) IFDEntryType.Long) { uint [] data = ReadUIntArray (count); return new LongArrayIFDEntry (tag, data); } if (type == (ushort) IFDEntryType.Byte) { ByteVector data = file.ReadBlock ((int) count); return new ByteVectorIFDEntry (tag, data); } if (type == (ushort) IFDEntryType.Ascii) { string data = ReadAsciiString ((int) count); return new StringIFDEntry (tag, data); } if (tag == (ushort) ExifEntryTag.UserComment) { ByteVector data = file.ReadBlock ((int) count); return new UserCommentIFDEntry (tag, data, file); } if (type == (ushort) IFDEntryType.Undefined) { ByteVector data = file.ReadBlock ((int) count); return new UndefinedIFDEntry (tag, data); } } if (type == (ushort) IFDEntryType.Float) return null; if (type == 0 || type > 12) { // Invalid type file.MarkAsCorrupt ("Invalid item type"); return null; } // TODO: We should ignore unreadable values, erroring for now until we have sufficient coverage. throw new NotImplementedException (String.Format ("Unknown type/count {0}/{1} ({2})", type, count, offset)); }
/// <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); }
/// <summary> /// Creates an IFDEntry from the given values. This method is used for /// every entry. Custom parsing can be hooked in by overriding the /// <see cref="ParseIFDEntry(ushort,ushort,uint,long,uint)"/> method. /// </summary> /// <param name="tag"> /// A <see cref="System.UInt16"/> with the tag of the entry. /// </param> /// <param name="type"> /// A <see cref="System.UInt16"/> with the type of the entry. /// </param> /// <param name="count"> /// A <see cref="System.UInt32"/> with the data count of the entry. /// </param> /// <param name="baseOffset"> /// A <see cref="System.Int64"/> with the base offset which every /// offsets in the IFD are relative to. /// </param> /// <param name="offsetData"> /// A <see cref="ByteVector"/> containing exactly 4 byte with the data /// of the offset of the entry. Since this field isn't interpreted as /// an offset if the data can be directly stored in the 4 byte, we /// pass the <see cref="ByteVector"/> to easier interpret it. /// </param> /// <param name="maxOffset"> /// A <see cref="System.UInt32"/> with the maximal offset to consider for /// the IFD. /// </param> /// <returns> /// A <see cref="IFDEntry"/> with the given parameter. /// </returns> IFDEntry CreateIFDEntry(ushort tag, ushort type, uint count, long baseOffset, ByteVector offsetData, uint maxOffset) { uint offset = offsetData.ToUInt(is_bigendian); // Fix the type for the IPTC tag. // From http://www.awaresystems.be/imaging/tiff/tifftags/iptc.html // "Often times, the datatype is incorrectly specified as LONG. " if (tag == (ushort)IFDEntryTag.IPTC && type == (ushort)IFDEntryType.Long) { type = (ushort)IFDEntryType.Byte; } var ifd_entry = ParseIFDEntry(tag, type, count, baseOffset, offset); if (ifd_entry != null) { return(ifd_entry); } if (count > 0x10000000) { // Some Nikon files are known to exhibit this corruption (or "feature"). file.MarkAsCorrupt("Impossibly large item count"); return(null); } // then handle the values stored in the offset data itself if (count == 1) { if (type == (ushort)IFDEntryType.Byte) { return(new ByteIFDEntry(tag, offsetData[0])); } if (type == (ushort)IFDEntryType.SByte) { return(new SByteIFDEntry(tag, (sbyte)offsetData[0])); } if (type == (ushort)IFDEntryType.Short) { return(new ShortIFDEntry(tag, offsetData.Mid(0, 2).ToUShort(is_bigendian))); } if (type == (ushort)IFDEntryType.SShort) { return(new SShortIFDEntry(tag, offsetData.Mid(0, 2).ToUShort(is_bigendian))); } if (type == (ushort)IFDEntryType.Long) { return(new LongIFDEntry(tag, offsetData.ToUInt(is_bigendian))); } if (type == (ushort)IFDEntryType.SLong) { return(new SLongIFDEntry(tag, offsetData.ToInt(is_bigendian))); } } if (count == 2) { if (type == (ushort)IFDEntryType.Short) { ushort[] data = new[] { offsetData.Mid(0, 2).ToUShort(is_bigendian), offsetData.Mid(2, 2).ToUShort(is_bigendian) }; return(new ShortArrayIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.SShort) { short[] data = new[] { (short)offsetData.Mid(0, 2).ToUShort(is_bigendian), (short)offsetData.Mid(2, 2).ToUShort(is_bigendian) }; return(new SShortArrayIFDEntry(tag, data)); } } if (count <= 4) { if (type == (ushort)IFDEntryType.Undefined) { return(new UndefinedIFDEntry(tag, offsetData.Mid(0, (int)count))); } if (type == (ushort)IFDEntryType.Ascii) { string data = offsetData.Mid(0, (int)count).ToString(); int term = data.IndexOf('\0'); if (term > -1) { data = data.Substring(0, term); } return(new StringIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.Byte) { return(new ByteVectorIFDEntry(tag, offsetData.Mid(0, (int)count))); } } // FIXME: create correct type. if (offset > maxOffset) { return(new UndefinedIFDEntry(tag, new ByteVector())); } // then handle data referenced by the offset file.Seek(baseOffset + offset, SeekOrigin.Begin); if (count == 1) { if (type == (ushort)IFDEntryType.Rational) { return(new RationalIFDEntry(tag, ReadRational())); } if (type == (ushort)IFDEntryType.SRational) { return(new SRationalIFDEntry(tag, ReadSRational())); } } if (count > 1) { if (type == (ushort)IFDEntryType.Long) { uint[] data = ReadUIntArray(count); return(new LongArrayIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.SLong) { int[] data = ReadIntArray(count); return(new SLongArrayIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.Rational) { var entries = new Rational[count]; for (int i = 0; i < count; i++) { entries[i] = ReadRational(); } return(new RationalArrayIFDEntry(tag, entries)); } if (type == (ushort)IFDEntryType.SRational) { var entries = new SRational[count]; for (int i = 0; i < count; i++) { entries[i] = ReadSRational(); } return(new SRationalArrayIFDEntry(tag, entries)); } } if (count > 2) { if (type == (ushort)IFDEntryType.Short) { ushort[] data = ReadUShortArray(count); return(new ShortArrayIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.SShort) { short[] data = ReadShortArray(count); return(new SShortArrayIFDEntry(tag, data)); } } if (count > 4) { if (type == (ushort)IFDEntryType.Long) { uint[] data = ReadUIntArray(count); return(new LongArrayIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.Byte) { ByteVector data = file.ReadBlock((int)count); return(new ByteVectorIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.Ascii) { string data = ReadAsciiString((int)count); return(new StringIFDEntry(tag, data)); } if (tag == (ushort)ExifEntryTag.UserComment) { ByteVector data = file.ReadBlock((int)count); return(new UserCommentIFDEntry(tag, data, file)); } if (type == (ushort)IFDEntryType.Undefined) { ByteVector data = file.ReadBlock((int)count); return(new UndefinedIFDEntry(tag, data)); } } if (type == (ushort)IFDEntryType.Float) { return(null); } if (type == 0 || type > 12) { // Invalid type file.MarkAsCorrupt("Invalid item type"); return(null); } throw new NotImplementedException($"Unknown type/count {type}/{count} ({offset})"); }
private static string GetHeaderError(ByteVector data) { if (data.Count < 4) return "Insufficient header length."; if (data [0] != 0xFF) return "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) return "Second byte did not match MPEG synch."; uint flags = data.ToUInt (); if (((flags >> 12) & 0x0F) == 0x0F) return "Header uses invalid bitrate index."; if (((flags >> 10) & 0x03) == 0x03) return "Invalid sample rate."; return null; }
/// <summary> /// Read EBML header and data-size if it is an abstract one. /// It then becomes a non abstract EBML. /// </summary> /// <param name="throwException">Throw exception on invalid EBML read if true (Default: false).</param> /// <returns>True if successful.</returns> public bool Read(bool throwException = false) { if (!Abstract) { return(true); } if (file == null) { throw new ArgumentNullException("file"); } try { var ex = new InvalidOperationException("Invalid EBML format Read"); if (offset >= (ulong)(file.Length) - 1) { throw ex; } // Prepare for Consitency check uint ebml_id_check = ebml_id; ulong ebml_size_check = Size; file.Seek((long)offset); // Get the header byte ByteVector vector = file.ReadBlock(1); byte header_byte = vector[0]; // Define a mask byte mask = 0x80, id_length = 1; // Figure out the size in bytes while (id_length <= 4 && (header_byte & mask) == 0) { id_length++; mask >>= 1; } if (id_length > 4) { throw ex; } // Now read the rest of the EBML ID if (id_length > 1) { vector.Add(file.ReadBlock(id_length - 1)); } ebml_id = vector.ToUInt(); vector.Clear(); // Get the size length vector = file.ReadBlock(1); header_byte = vector[0]; mask = 0x80; Byte size_length = 1; // Iterate through various possibilities while (size_length <= 8 && (header_byte & mask) == 0) { size_length++; mask >>= 1; } if (size_length > 8) { size_length = 1; // Special: Empty element (all zero state) } else { vector[0] &= (Byte)(mask - 1); // Clear the marker bit } // Now read the rest of the EBML element size if (size_length > 1) { vector.Add(file.ReadBlock(size_length - 1)); } ebml_size = vector.ToULong(); // Special: Auto-size (0xFF byte) if (size_length == 1 && ebml_size == 0x7F) { // Resolve auto-size to fill in to its containing element ulong bound = parent == null ? (ulong)file.Length : parent.Offset + parent.Size; ebml_size = bound - offset - (ulong)(id_length + size_length); } data_offset = offset + id_length + size_length; // Consistency check: Detect descrepencies between read data and abstract data if (ebml_id_check != 0 && ebml_id_check != ebml_id) { throw ex; } if (ebml_size_check != 0 && ebml_size_check != Size) { throw ex; } return(true); } catch (Exception ex) { if (throwException) { throw ex; } return(false); } }
/// <summary> /// Constructs a <see cref="EBMLElement" /> parsing from provided /// file data. /// </summary> /// <param name="_file"><see cref="File" /> instance to read from.</param> /// <param name="position">Position to start reading from.</param> public EBMLElement(Matroska.File _file, ulong position) { if (_file == null) { throw new ArgumentNullException("file"); } if (position > (ulong)(_file.Length - 4)) { throw new ArgumentOutOfRangeException("position"); } // Keep a reference to the file file = _file; file.Seek((long)position); // Get the header byte ByteVector vector = file.ReadBlock(1); Byte header_byte = vector [0]; // Define a mask Byte mask = 0x80, id_length = 1; // Figure out the size in bytes while (id_length <= 4 && (header_byte & mask) == 0) { id_length++; mask >>= 1; } if (id_length > 4) { throw new CorruptFileException("invalid EBML id size"); } // Now read the rest of the EBML ID if (id_length > 1) { vector.Add(file.ReadBlock(id_length - 1)); } ebml_id = vector.ToUInt(); vector.Clear(); // Get the size length vector = file.ReadBlock(1); header_byte = vector [0]; mask = 0x80; Byte size_length = 1; // Iterate through various possibilities while (size_length <= 8 && (header_byte & mask) == 0) { size_length++; mask >>= 1; } if (size_length > 8) { throw new CorruptFileException("invalid EBML element size"); } // Clear the marker bit vector [0] &= (Byte)(mask - 1); // Now read the rest of the EBML element size if (size_length > 1) { vector.Add(file.ReadBlock(size_length - 1)); } ebml_size = vector.ToULong(); offset = position; data_offset = offset + id_length + size_length; }