예제 #1
0
        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();
            }
        }
예제 #2
0
        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);
            }
        }
예제 #3
0
 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));
     }
 }
예제 #4
0
        /// <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);
        }
예제 #5
0
        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);
        }
예제 #6
0
 /// <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);
 }
예제 #7
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}");
            }
        }
예제 #8
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>
        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()));
            }
        }
예제 #9
0
        public uint ReadUInt()
        {
            if (file == null)
            {
                return(0);
            }
            file.Seek((long)data_offset);
            ByteVector vector = file.ReadBlock((int)ebml_size);

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

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

            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);
        }
예제 #20
0
파일: Tag.cs 프로젝트: hoeness2/mcebuddy2
		/// <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();
		}
예제 #21
0
        /// <summary>
        ///    Constructs and initializes a new instance of <see
        ///    cref="AudioHeader" /> by reading its contents from a
        ///    <see cref="ByteVector" /> object and its Xing Header from
        ///    the appropriate location in the specified file.
        /// </summary>
        /// <param name="data">
        ///    A <see cref="ByteVector" /> object containing the header
        ///    to read.
        /// </param>
        /// <param name="file">
        ///    A <see cref="TagLib.File" /> object to read the Xing
        ///    header from.
        /// </param>
        /// <param name="position">
        ///    A <see cref="long" /> value indicating the position in
        ///    <paramref name="file" /> at which the header begins.
        /// </param>
        /// <exception cref="CorruptFileException">
        ///    <paramref name="data" /> is less than 4 bytes long,
        ///    does not begin with a MPEG audio synch, has a negative
        ///    bitrate, or has a sample rate of zero.
        /// </exception>
        private AudioHeader(ByteVector data, TagLib.File file,
                            long position)
        {
            this.duration = TimeSpan.Zero;
            stream_length = 0;

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

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

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

            flags = data.ToUInt();

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

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

            xing_header = XingHeader.Unknown;

            vbri_header = VBRIHeader.Unknown;

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

            ByteVector xing_data = file.ReadBlock(16);

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

            if (xing_header.Present)
            {
                return;
            }

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

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

            if (vbri_data.Count == 24 &&
                vbri_data.StartsWith(VBRIHeader.FileIdentifier))
            {
                vbri_header = new VBRIHeader(vbri_data);
            }
        }
예제 #22
0
파일: File.cs 프로젝트: rygos/iTagger
		/// <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 ()));
		}
예제 #23
0
        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));
        }
예제 #24
0
		/// <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));
		}
예제 #25
0
		/// <summary>
		///    Constructs and initializes a new instance of <see
		///    cref="AudioHeader" /> by reading its contents from a
		///    <see cref="ByteVector" /> object and its Xing Header from
		///    the appropriate location in the specified file.
		/// </summary>
		/// <param name="data">
		///    A <see cref="ByteVector" /> object containing the header
		///    to read.
		/// </param>
		/// <param name="file">
		///    A <see cref="TagLib.File" /> object to read the Xing
		///    header from.
		/// </param>
		/// <param name="position">
		///    A <see cref="long" /> value indicating the position in
		///    <paramref name="file" /> at which the header begins.
		/// </param>
		/// <exception cref="CorruptFileException">
		///    <paramref name="data" /> is less than 4 bytes long,
		///    does not begin with a MPEG audio synch, has a negative
		///    bitrate, or has a sample rate of zero.
		/// </exception>
		private AudioHeader (ByteVector data, TagLib.File file,
		                     long position)
		{
			this.duration = TimeSpan.Zero;
			stream_length = 0;
			
			if (data.Count < 4)
				throw new CorruptFileException (
					"Insufficient header length.");
			
			if (data [0] != 0xFF)
				throw new CorruptFileException (
					"First byte did not match MPEG synch.");
			
			if (data [1] < 0xE0)
				throw new CorruptFileException (
					"Second byte did not match MPEG synch.");
			
			flags = data.ToUInt ();
			
			if (((flags >> 12) & 0x0F) == 0x0F)
				throw new CorruptFileException (
					"Header uses invalid bitrate index.");
			
			if (((flags >> 10) & 0x03) == 0x03)
				throw new CorruptFileException (
					"Invalid sample rate.");

			xing_header = XingHeader.Unknown;
			
			vbri_header = VBRIHeader.Unknown;
			
			// Check for a Xing header that will help us in
			// gathering information about a VBR stream.
			file.Seek (position + XingHeader.XingHeaderOffset (
				Version, ChannelMode));
				
			ByteVector xing_data = file.ReadBlock (16);
			if (xing_data.Count == 16 && xing_data.StartsWith (
				XingHeader.FileIdentifier))
				xing_header = new XingHeader (xing_data);

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

			// Only get the first 24 bytes of the Header.
			// We're not interested in the TOC entries.
			ByteVector vbri_data = file.ReadBlock (24);
			if (vbri_data.Count == 24 &&
				vbri_data.StartsWith(VBRIHeader.FileIdentifier))
			vbri_header = new VBRIHeader (vbri_data);
		}
예제 #26
0
        /// <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})");
        }
예제 #27
0
        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;
        }
예제 #28
0
        /// <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);
            }
        }
예제 #29
0
        /// <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;
        }