예제 #1
0
		private void Parse(ByteVector data)
		{
			// Check to see if a valid Xing header is available.

			if (!data.StartsWith("Xing"))
				return;

			// If the XingHeader doesn'type contain the number of frames and the total stream
			// info it'field invalid.

			if ((data[7] & 0x02) == 0)
			{
				TagLibDebugger.Debug("MPEG::XingHeader::parse() -- Xing header doesn't contain the total number of frames.");
				return;
			}

			if ((data[7] & 0x04) == 0)
			{
				TagLibDebugger.Debug("MPEG::XingHeader::parse() -- Xing header doesn't contain the total stream size.");
				return;
			}

			frames = data.Mid(8, 4).ToUInt();
			size = data.Mid(12, 4).ToUInt();

			valid = true;
		}
예제 #2
0
 public static AviStream ParseStreamList (ByteVector data)
 {
    if (data == null)
       throw new ArgumentNullException ("data");
    
    AviStream stream = null;
    int pos = 4;
    
    if (data.StartsWith ("strl"))
       while (pos + 8 < data.Count)
       {
          ByteVector id = data.Mid (pos, 4);
          int block_length = (int) data.Mid (pos + 4, 4).ToUInt (false);
          
          if (id == "strh" && stream == null)
          {
             AviStreamHeader stream_header = new AviStreamHeader (data, pos + 8);
             if (stream_header.Type == "vids")
                stream = new AviVideoStream (stream_header);
             else if (stream_header.Type == "auds")
                stream = new AviAudioStream (stream_header);
          }
          else if (stream != null)
             stream.ParseItem (id, data, pos + 8, block_length);
          
          pos += block_length + 8;
       }
    
    return stream;
 }
예제 #3
0
		//private void Read(ByteVector data, long stream_length, ReadStyle style)
		private void Read(ByteVector data, long streamLength)
		{
			if (data.StartsWith("MP+"))
				return;

			version = data[3] & 15;

			uint frames;

			if (version >= 7)
			{
				frames = data.Mid(4, 4).ToUInt(false);
				uint flags = data.Mid(8, 4).ToUInt(false);
				sampleRate = sfTable[(int)(((flags >> 17) & 1) * 2 + ((flags >> 16) & 1))];
				channels = 2;
			}
			else
			{
				uint headerData = data.Mid(0, 4).ToUInt(false);
				bitrate = (int)((headerData >> 23) & 0x01ff);
				version = (int)((headerData >> 11) & 0x03ff);
				sampleRate = 44100;
				channels = 2;
				if (version >= 5)
					frames = data.Mid(4, 4).ToUInt(false);
				else
					frames = data.Mid(4, 2).ToUInt(false);
			}

			uint samples = frames * 1152 - 576;
			duration = sampleRate > 0 ? TimeSpan.FromSeconds((double)samples / (double)sampleRate + 0.5) : TimeSpan.Zero;

			if (bitrate == 0)
				bitrate = (int)(duration > TimeSpan.Zero ? ((streamLength * 8L) / duration.TotalSeconds) / 1000 : 0);
		}		
예제 #4
0
 public XingHeader(ByteVector data)
 {
     if (data == null)
     {
         throw new ArgumentNullException("data");
     }
     if (!data.StartsWith(FileIdentifier))
     {
         throw new CorruptFileException("Not a valid Xing header");
     }
     int startIndex = 8;
     if ((data[7] & 1) != 0)
     {
         this.frames = data.Mid(startIndex, 4).ToUInt();
         startIndex += 4;
     }
     else
     {
         this.frames = 0;
     }
     if ((data[7] & 2) != 0)
     {
         this.size = data.Mid(startIndex, 4).ToUInt();
         startIndex += 4;
     }
     else
     {
         this.size = 0;
     }
     this.present = true;
 }
예제 #5
0
      public Footer (ByteVector data)
      {
         if (data.Count < Size)
            throw new CorruptFileException ("Provided data is smaller than object size.");
         
         if (!data.StartsWith (FileIdentifier))
            throw new CorruptFileException ("Provided data does not start with File Identifier");
         
         major_version   = data [3];
         revision_number = data [4];
         flags           = (HeaderFlags) data [5];
         
         
         if (major_version == 2 && (flags & (HeaderFlags) 127) != 0)
            throw new CorruptFileException ("Invalid flags set on version 2 tag.");
         
         if (major_version == 3 && (flags & (HeaderFlags) 15) != 0)
            throw new CorruptFileException ("Invalid flags set on version 3 tag.");
         
         if (major_version == 4 && (flags & (HeaderFlags) 7) != 0)
            throw new CorruptFileException ("Invalid flags set on version 4 tag.");
         
         
         ByteVector size_data = data.Mid (6, 4);
         
         foreach (byte b in size_data)
            if (b >= 128)
               throw new CorruptFileException ("One of the bytes in the header was greater than the allowed 128.");

         tag_size = SynchData.ToUInt (size_data);
      }
예제 #6
0
 public static AviStream ParseStreamList(ByteVector data)
 {
     int num2;
     if (data == null)
     {
         throw new ArgumentNullException("data");
     }
     if (!data.StartsWith("strl"))
     {
         return null;
     }
     AviStream stream = null;
     for (int i = 4; (i + 8) < data.Count; i += num2 + 8)
     {
         ByteVector id = data.Mid(i, 4);
         num2 = (int) data.Mid(i + 4, 4).ToUInt(false);
         if ((id == "strh") && (stream == null))
         {
             AviStreamHeader header = new AviStreamHeader(data, i + 8);
             if (header.Type == "vids")
             {
                 stream = new AviVideoStream(header);
             }
             else if (header.Type == "auds")
             {
                 stream = new AviAudioStream(header);
             }
         }
         else if (stream != null)
         {
             stream.ParseItem(id, data, i + 8, num2);
         }
     }
     return stream;
 }
 public StreamHeader(ByteVector data, long streamLength)
 {
     if (data == null)
     {
         throw new ArgumentNullException("data");
     }
     if (!data.StartsWith(FileIdentifier))
     {
         throw new CorruptFileException("Data does not begin with identifier.");
     }
     if (data.Count < 0x38L)
     {
         throw new CorruptFileException("Insufficient data in stream header");
     }
     this.stream_length = streamLength;
     this.version = data[3] & 15;
     if (this.version >= 7)
     {
         this.frames = data.Mid(4, 4).ToUInt(false);
         uint num = data.Mid(8, 4).ToUInt(false);
         this.sample_rate = sftable[(((num >> 0x11) & 1) * 2) + ((num >> 0x10) & 1)];
         this.header_data = 0;
     }
     else
     {
         this.header_data = data.Mid(0, 4).ToUInt(false);
         this.version = ((int) (this.header_data >> 11)) & 0x3ff;
         this.sample_rate = 0xac44;
         this.frames = data.Mid(4, (this.version < 5) ? 2 : 4).ToUInt(false);
     }
 }
예제 #8
0
 public Tag(ByteVector data)
 {
     if (data == null)
     {
         throw new ArgumentNullException("data");
     }
     if (data.Count < 0x80L)
     {
         throw new CorruptFileException("ID3v1 data is less than 128 bytes long.");
     }
     if (!data.StartsWith(FileIdentifier))
     {
         throw new CorruptFileException("ID3v1 data does not start with identifier.");
     }
     this.Parse(data);
 }
예제 #9
0
 public VBRIHeader(ByteVector data)
 {
     if (data == null)
     {
         throw new ArgumentNullException("data");
     }
     if (!data.StartsWith(FileIdentifier))
     {
         throw new CorruptFileException("Not a valid VBRI header");
     }
     int startIndex = 10;
     this.size = data.Mid(startIndex, 4).ToUInt();
     startIndex += 4;
     this.frames = data.Mid(startIndex, 4).ToUInt();
     startIndex += 4;
     this.present = true;
 }
예제 #10
0
 public Footer(ByteVector data)
 {
     if (data == null)
     {
         throw new ArgumentNullException("data");
     }
     if (data.Count < 10L)
     {
         throw new CorruptFileException("Provided data is smaller than object size.");
     }
     if (!data.StartsWith(FileIdentifier))
     {
         throw new CorruptFileException("Provided data does not start with the file identifier");
     }
     this.major_version = data[3];
     this.revision_number = data[4];
     this.flags = (HeaderFlags) data[5];
     if ((this.major_version == 2) && ((((int) this.flags) & 0x7f) != 0))
     {
         throw new CorruptFileException("Invalid flags set on version 2 tag.");
     }
     if ((this.major_version == 3) && ((((int) this.flags) & 15) != 0))
     {
         throw new CorruptFileException("Invalid flags set on version 3 tag.");
     }
     if ((this.major_version == 4) && ((((int) this.flags) & 7) != 0))
     {
         throw new CorruptFileException("Invalid flags set on version 4 tag.");
     }
     for (int i = 6; i < 10; i++)
     {
         if (data[i] >= 0x80)
         {
             throw new CorruptFileException("One of the bytes in the header was greater than the allowed 128.");
         }
     }
     this.tag_size = SynchData.ToUInt(data.Mid(6, 4));
 }
예제 #11
0
 public StreamHeader(ByteVector data, long streamLength)
 {
     if (data == null)
     {
         throw new ArgumentNullException("data");
     }
     if (!data.StartsWith(FileIdentifier))
     {
         throw new CorruptFileException("Data does not begin with identifier.");
     }
     if (data.Count < 0x4cL)
     {
         throw new CorruptFileException("Insufficient data in stream header");
     }
     this.stream_length = streamLength;
     this.version = data.Mid(4, 2).ToUShort(false);
     this.compression_level = (CompressionLevel) data.Mid(0x34, 2).ToUShort(false);
     this.blocks_per_frame = data.Mid(0x38, 4).ToUInt(false);
     this.final_frame_blocks = data.Mid(60, 4).ToUInt(false);
     this.total_frames = data.Mid(0x40, 4).ToUInt(false);
     this.bits_per_sample = data.Mid(0x44, 2).ToUShort(false);
     this.channels = data.Mid(70, 2).ToUShort(false);
     this.sample_rate = data.Mid(0x48, 4).ToUInt(false);
 }
예제 #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;

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

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

            // Checking bits from high to low:
            //
            // First 3 bits MUST be set. Bits 4 and 5 can
            // be 00, 10, or 11 but not 01. One or more of
            // bits 6 and 7 must be set. Bit 8 can be
            // anything.
            if ((data [1] & 0xE6) <= 0xE0 || (data [1] & 0x18) == 0x08)
            {
                throw new CorruptFileException(
                          "Second byte did not match MPEG synch.");
            }

            flags = data.ToUInt();

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

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

            xing_header = XingHeader.Unknown;

            vbri_header = VBRIHeader.Unknown;

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

            ByteVector xing_data = file.ReadBlock(16);

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

            if (xing_header.Present)
            {
                return;
            }

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

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

            if (vbri_data.Count == 24 &&
                vbri_data.StartsWith(VBRIHeader.FileIdentifier))
            {
                vbri_header = new VBRIHeader(vbri_data);
            }
        }
예제 #13
0
        private IFDEntry ParseMakernote(ushort tag, ushort type, uint count, long base_offset, uint offset)
        {
            long         makernote_offset = base_offset + offset;
            IFDStructure ifd_structure    = new IFDStructure();

            // This is the minimum size a makernote should have
            // The shortest header is PENTAX_HEADER (4)
            // + IFD entry count (2)
            // + at least one IFD etry (12)
            // + next IFD pointer (4)
            // = 22 ....
            // we use this number to read a header which is big used
            // to identify the makernote types
            int header_size = 18;

            long length = 0;

            try {
                length = file.Length;
            } catch (Exception) {
                // Use a safety-value of 4 gigabyte.
                length = 1073741824L * 4;
            }

            if (makernote_offset > length)
            {
                throw new Exception("offset to makernote is beyond file size");
            }

            if (makernote_offset + header_size > length)
            {
                throw new Exception("data is to short to contain a maker note ifd");
            }

            // read header
            file.Seek(makernote_offset, SeekOrigin.Begin);
            ByteVector header = file.ReadBlock(header_size);

            if (header.StartsWith(PANASONIC_HEADER))
            {
                IFDReader reader =
                    new IFDReader(file, is_bigendian, ifd_structure, base_offset, offset + 12, max_offset);

                reader.ReadIFD(base_offset, offset + 12, max_offset);
                return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Panasonic, PANASONIC_HEADER, 12, true, null));
            }

            if (header.StartsWith(PENTAX_HEADER))
            {
                IFDReader reader =
                    new IFDReader(file, is_bigendian, ifd_structure, base_offset, offset + 6, max_offset);

                reader.ReadIFD(base_offset, offset + 6, max_offset);
                return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Pentax, header.Mid(0, 6), 6, true, null));
            }

            if (header.StartsWith(OLYMPUS1_HEADER))
            {
                IFDReader reader =
                    new IFDReader(file, is_bigendian, ifd_structure, base_offset, offset + 8, max_offset);

                reader.Read();
                return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Olympus1, header.Mid(0, 8), 8, true, null));
            }

            if (header.StartsWith(OLYMPUS2_HEADER))
            {
                IFDReader reader =
                    new IFDReader(file, is_bigendian, ifd_structure, makernote_offset, 12, count);

                reader.Read();
                return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Olympus2, header.Mid(0, 12), 12, false, null));
            }

            if (header.StartsWith(SONY_HEADER))
            {
                IFDReader reader =
                    new IFDReader(file, is_bigendian, ifd_structure, base_offset, offset + 12, max_offset);

                reader.ReadIFD(base_offset, offset + 12, max_offset);
                return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Sony, SONY_HEADER, 12, true, null));
            }

            if (header.StartsWith(NIKON_HEADER))
            {
                ByteVector endian_bytes = header.Mid(10, 2);

                if (endian_bytes.ToString() == "II" || endian_bytes.ToString() == "MM")
                {
                    bool   makernote_endian = endian_bytes.ToString().Equals("MM");
                    ushort magic            = header.Mid(12, 2).ToUShort(is_bigendian);

                    if (magic == 42)
                    {
                        // TODO: the max_offset value is not correct here. However, some nikon files have offsets to a sub-ifd
                        // (preview image) which are not stored with the other makernote data. Therfore, we keep the max_offset
                        // for now. (It is just an upper bound for some checks. So if it is too big, it doesn't matter)
                        var reader =
                            new Nikon3MakernoteReader(file, makernote_endian, ifd_structure, makernote_offset + 10, 8, max_offset - offset - 10);

                        reader.Read();
                        return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Nikon3, header.Mid(0, 18), 8, false, makernote_endian));
                    }
                }
            }

            if (header.StartsWith(LEICA_HEADER))
            {
                IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, makernote_offset, 8, count);

                reader.Read();
                return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Leica, header.Mid(0, 8), 10, false, null));
            }

            try {
                IFDReader reader =
                    new IFDReader(file, is_bigendian, ifd_structure, base_offset, offset, max_offset);

                reader.Read();
                return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Canon));
            } catch {
                return(null);
            }
        }
예제 #14
0
		/// <summary>
		///    Constructs and initializes a new instance of <see
		///    cref="StreamHeader" /> for a specified header block and
		///    stream length.
		/// </summary>
		/// <param name="data">
		///    A <see cref="ByteVector" /> object containing the stream
		///    header data.
		/// </param>
		/// <param name="streamLength">
		///    A <see cref="long" /> value containing the length of the
		///    Monkey Audio stream in bytes.
		/// </param>
		/// <exception cref="ArgumentNullException">
		///    <paramref name="data" /> is <see langword="null" />.
		/// </exception>
		/// <exception cref="CorruptFileException">
		///    <paramref name="data" /> does not begin with <see
		///    cref="FileIdentifier" /> or is less than <see cref="Size"
		///    /> bytes long.
		/// </exception>
		public StreamHeader(ByteVector data, long streamLength)
		{
			if (data == null)
				throw new ArgumentNullException("data");
			
			if (!data.StartsWith(FileIdentifier))
				throw new CorruptFileException(
					"Data does not begin with identifier.");
			
			if (data.Count < Size)
				throw new CorruptFileException(
					"Insufficient data in stream header");
			
			stream_length = streamLength;
			version = data.Mid (4, 2).ToUShort(false);
			compression_level = (CompressionLevel) data.Mid(52, 2)
				.ToUShort(false);
			// format_flags = data.Mid(54, 2).ToUShort(false);
			blocks_per_frame = data.Mid(56, 4).ToUInt(false);
			final_frame_blocks = data.Mid(60, 4).ToUInt(false);
			total_frames = data.Mid(64, 4).ToUInt(false);
			bits_per_sample = data.Mid(68, 2).ToUShort(false);
			channels = data.Mid(70, 2).ToUShort(false);
			sample_rate = data.Mid(72, 4).ToUInt(false);
		}
예제 #15
0
        private IFDEntry ParseMakernote(ushort tag, ushort type, uint count, long base_offset, uint offset)
        {
            long         makernote_offset = base_offset + offset;
            IFDStructure ifd_structure    = new IFDStructure();
            int          header_size      = 18;
            long         length           = 0;

            try
            {
                length = file.Length;
            }
            catch (Exception)
            {
                length = 1073741824L * 4;
            }
            if (makernote_offset > length)
            {
                file.MarkAsCorrupt("offset to makernote is beyond file size");
                return(null);
            }
            if (makernote_offset + header_size > length)
            {
                file.MarkAsCorrupt("data is to short to contain a maker note ifd");
                return(null);
            }
            file.Seek(makernote_offset, SeekOrigin.Begin);
            ByteVector header = file.ReadBlock(header_size);

            if (header.StartsWith(PANASONIC_HEADER))
            {
                IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, base_offset, offset + 12, max_offset);
                reader.ReadIFD(base_offset, offset + 12, max_offset);
                return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Panasonic, PANASONIC_HEADER, 12, true, null));
            }
            if (header.StartsWith(PENTAX_HEADER))
            {
                IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, base_offset, offset + 6, max_offset);
                reader.ReadIFD(base_offset, offset + 6, max_offset);
                return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Pentax, header.Mid(0, 6), 6, true, null));
            }
            if (header.StartsWith(OLYMPUS1_HEADER))
            {
                IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, base_offset, offset + 8, max_offset);
                reader.Read();
                return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Olympus1, header.Mid(0, 8), 8, true, null));
            }
            if (header.StartsWith(OLYMPUS2_HEADER))
            {
                IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, makernote_offset, 12, count);
                reader.Read();
                return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Olympus2, header.Mid(0, 12), 12, false, null));
            }
            if (header.StartsWith(SONY_HEADER))
            {
                IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, base_offset, offset + 12, max_offset);
                reader.ReadIFD(base_offset, offset + 12, max_offset);
                return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Sony, SONY_HEADER, 12, true, null));
            }
            if (header.StartsWith(NIKON_HEADER))
            {
                ByteVector endian_bytes = header.Mid(10, 2);
                if (endian_bytes.ToString() == "II" || endian_bytes.ToString() == "MM")
                {
                    bool   makernote_endian = endian_bytes.ToString().Equals("MM");
                    ushort magic            = header.Mid(12, 2).ToUShort(is_bigendian);
                    if (magic == 42)
                    {
                        var reader = new Nikon3MakernoteReader(file, makernote_endian, ifd_structure, makernote_offset + 10, 8, max_offset - offset - 10);
                        reader.Read();
                        return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Nikon3, header.Mid(0, 18), 8, false, makernote_endian));
                    }
                }
            }
            if (header.StartsWith(LEICA_HEADER))
            {
                IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, makernote_offset, 8, count);
                reader.Read();
                return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Leica, header.Mid(0, 8), 10, false, null));
            }
            try
            {
                IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, base_offset, offset, max_offset);
                reader.Read();
                return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Canon));
            }
            catch
            {
                return(null);
            }
        }
예제 #16
0
		/// <summary>
		///    Constructs and initializes a new instance of <see
		///    cref="StreamHeader" /> for a specified header block and
		///    stream length.
		/// </summary>
		/// <param name="data">
		///    A <see cref="ByteVector" /> object containing the stream
		///    header data.
		/// </param>
		/// <param name="streamLength">
		///    A <see cref="long" /> value containing the length of the
		///    DSF Audio stream in bytes.
		/// </param>
		/// <exception cref="ArgumentNullException">
		///    <paramref name="data" /> is <see langword="null" />.
		/// </exception>
		/// <exception cref="CorruptFileException">
		///    <paramref name="data" /> does not begin with <see
		///    cref="FileIdentifier" /> 
		/// </exception>
		public StreamHeader(ByteVector data, long streamLength)
		{
			if (data == null)
				throw new ArgumentNullException("data");


			if (!data.StartsWith(FileIdentifier))
				throw new CorruptFileException(
					"Data does not begin with identifier.");

			stream_length = streamLength;

			// The first 12 bytes contain the Format chunk identifier "fmt "
			// And the size of the format chunk, which is always 52
			version = data.Mid(12, 4).ToUShort(false);
			format_id = data.Mid(16, 4).ToUShort(false);
			channel_type = data.Mid(20, 4).ToUShort(false);
			channels = data.Mid(24, 4).ToUShort(false);
			sample_rate = data.Mid(28, 4).ToULong(false);
			bits_per_sample = data.Mid(32, 4).ToUShort(false);
			sample_count = data.Mid(36, 8).ToULong(false);
			channel_blksize = data.Mid(44, 4).ToUShort(false);
		}
        /// <summary>
        ///    Construcor.
        /// </summary>
        /// <param name="tag">
        ///    A <see cref="System.UInt16"/> with the tag ID of the entry this instance
        ///    represents
        /// </param>
        /// <param name="data">
        ///    A <see cref="ByteVector"/> to be stored
        /// </param>
        /// <param name="file">
        ///    The file that's currently being parsed, used for reporting corruptions.
        /// </param>
        public UserCommentIFDEntry(ushort tag, ByteVector data, TagLib.File file)
        {
            Tag = tag;

            if (data.StartsWith(COMMENT_ASCII_CODE))
            {
                Value = TrimNull(data.ToString(StringType.Latin1, COMMENT_ASCII_CODE.Count, data.Count - COMMENT_ASCII_CODE.Count));
                return;
            }

            if (data.StartsWith(COMMENT_UNICODE_CODE))
            {
                Value = TrimNull(data.ToString(StringType.UTF8, COMMENT_UNICODE_CODE.Count, data.Count - COMMENT_UNICODE_CODE.Count));
                return;
            }

            var trimmed = data.ToString().Trim();

            if (trimmed.Length == 0 || trimmed == "\0")
            {
                Value = String.Empty;
                return;
            }

            // Some programs like e.g. CanonZoomBrowser inserts just the first 0x00-byte
            // followed by 7-bytes of trash.
            if (data.StartsWith((byte)0x00) && data.Count >= 8)
            {
                // And CanonZoomBrowser fills some trailing bytes of the comment field
                // with '\0'. So we return only the characters before the first '\0'.
                int term = data.Find("\0", 8);
                if (term != -1)
                {
                    Value = data.ToString(StringType.Latin1, 8, term - 8);
                }
                else
                {
                    Value = data.ToString(StringType.Latin1, 8, data.Count - 8);
                }
                return;
            }

            if (data.Data.Length == 0)
            {
                Value = String.Empty;
                return;
            }

            // Try to parse anyway
            int offset = 0;
            int length = data.Count - offset;

            // Corruption that starts with a Unicode header and a count byte.
            if (data.StartsWith(COMMENT_BAD_UNICODE_CODE))
            {
                offset = COMMENT_BAD_UNICODE_CODE.Count;
                length = data.Count - offset;
            }

            file.MarkAsCorrupt("UserComment with other encoding than Latin1 or Unicode");
            Value = TrimNull(data.ToString(StringType.UTF8, offset, length));
        }
예제 #18
0
        //Additional info here http://gabriel.mp3-tech.org/mp3infotag.html
        //https://www.codeproject.com/Articles/8295/MPEG-Audio-Frame-Header

        /// <summary>See if the mp3 file is encoded using VBR. Not sure what to do with ABR...
        /// </summary>
        private bool IsVBR()
        {
            bool bVBR = false;

            if (currentFile.MimeType != "taglib/mp3")
            {
                return(false);
            }

            foreach (ICodec codec in currentFile.Properties.Codecs)
            {
                TagLib.Mpeg.AudioHeader header = (TagLib.Mpeg.AudioHeader)codec;
                //                if (header == null)
                //                    return;

                if (header.XingHeader.Present)
                {
                    currentFile.Mode = TagLib.File.AccessMode.Read;
                    long XingHeader = currentFile.Find(TagLib.Mpeg.XingHeader.FileIdentifier);
                    long Offset     = TagLib.Mpeg.XingHeader.XingHeaderOffset(header.Version, header.ChannelMode);
                    TagLib.Mpeg.XingHeader xing_header = TagLib.Mpeg.XingHeader.Unknown;
                    currentFile.Seek(XingHeader);// + Offset);
                    ByteVector xing_data = currentFile.ReadBlock(16);
                    if (xing_data.Count == 16 && xing_data.StartsWith(
                            TagLib.Mpeg.XingHeader.FileIdentifier))
                    {
                        xing_header = new TagLib.Mpeg.XingHeader(xing_data);
                    }

                    int  Flags          = BitConverter.ToInt32(xing_data.Take(8).ToArray().Reverse().ToArray(), 0);
                    bool FramesPresent  = (Flags & 0x0001) > 0;
                    bool BytesPresent   = (Flags & 0x0002) > 0;
                    bool TOCPresent     = (Flags & 0x0004) > 0;
                    bool QualityPresent = (Flags & 0x0008) > 0;
                    long LameHeader     = currentFile.Find(LAME_Identifier);

                    if (QualityPresent)
                    {
                        //Header offset + 8 (XING + flags) + Frames, Bytes and TOC if available
                        currentFile.Seek(XingHeader + 8 + 4 * (FramesPresent ? 1 : 0) + 4 * (BytesPresent ? 1 : 0) + 100 * (TOCPresent ? 1 : 0));
                        ByteVector Quality_data = currentFile.ReadBlock(4);
                        int        VBRQuality   = BitConverter.ToInt32(Quality_data.ToArray().Reverse().ToArray(), 0);
                        bVBR = true;
                    }
                    currentFile.Mode = TagLib.File.AccessMode.Closed;

                    //                    if (xing_header.Present)
                    //                        return false;
                    //                    var vector = new TagLib.ByteVector();
                    //                    TagLib.ByteVector xing = header.;
                    /* CODE HERE */

                    /*                    TagLib.File ref(fileName);
                     *                  TagLib.Mpeg.File *file = dynamic_cast<TagLib.Mpeg.File *>(ref file());
                     *
                     *                  if(!file)
                     *                      return;
                     *
                     *                  TagLib.Mpeg.Properties *properties = file->audioProperties();
                     *                  const TagLib::MPEG::XingHeader *xingHeader = properties->xingHeader();
                     *
                     *                  if(!xingHeader)
                     *                      return;
                     */
                }

                if (header.VBRIHeader.Present)
                {
                    /* CODE HERE */
                }
            }
            return(bVBR);
        }
예제 #19
0
        /// <summary>
        ///     Constructs and initializes a new instance of
        ///     <see
        ///         cref="StreamHeader" />
        ///     for a specified header block and
        ///     stream length.
        /// </summary>
        /// <param name="data">
        ///     A <see cref="ByteVector" /> object containing the stream
        ///     header data.
        /// </param>
        /// <param name="streamLength">
        ///     A <see cref="long" /> value containing the length of the
        ///     AIFF Audio stream in bytes.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="data" /> is <see langword="null" />.
        /// </exception>
        /// <exception cref="CorruptFileException">
        ///     <paramref name="data" /> does not begin with
        ///     <see
        ///         cref="FileIdentifier" />
        /// </exception>
        public StreamHeader(ByteVector data, long streamLength)
        {
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }

            if (!data.StartsWith(FileIdentifier))
            {
                throw new CorruptFileException(
                          "Data does not begin with identifier.");
            }

            stream_length = streamLength;

            // The first 8 bytes contain the Common chunk identifier "COMM"
            // And the size of the common chunk, which is always 18
            channels = data.Mid(8, 2)
                       .ToUShort(true);

            total_frames = data.Mid(10, 4)
                           .ToULong(true);

            bits_per_sample = data.Mid(14, 2)
                              .ToUShort(true);

            var sample_rate_indicator = data.Mid(17, 1);
            var sample_rate_tmp       = data.Mid(18, 2)
                                        .ToULong(true);

            sample_rate = 44100;             // Set 44100 as default sample rate

            // The following are combinations that iTunes 8 encodes to.
            // There may be other combinations in the field, but i couldn't test them.
            switch (sample_rate_tmp)
            {
            case 44100:
                if (sample_rate_indicator == 0x0E)
                {
                    sample_rate = 44100;
                }
                else if (sample_rate_indicator == 0x0D)
                {
                    sample_rate = 22050;
                }
                else if (sample_rate_indicator == 0x0C)
                {
                    sample_rate = 11025;
                }

                break;

            case 48000:
                if (sample_rate_indicator == 0x0E)
                {
                    sample_rate = 48000;
                }
                else if (sample_rate_indicator == 0x0D)
                {
                    sample_rate = 24000;
                }

                break;

            case 64000:
                if (sample_rate_indicator == 0x0D)
                {
                    sample_rate = 32000;
                }
                else if (sample_rate_indicator == 0x0C)
                {
                    sample_rate = 16000;
                }
                else if (sample_rate_indicator == 0x0B)
                {
                    sample_rate = 8000;
                }

                break;

            case 44510:
                if (sample_rate_indicator == 0x0D)
                {
                    sample_rate = 22255;
                }

                break;

            case 44508:
                if (sample_rate_indicator == 0x0C)
                {
                    sample_rate = 11127;
                }

                break;
            }
        }
        /// <summary>
        ///    Constructs and initializes a new instance of <see
        ///    cref="VBRIHeader" /> by reading its raw contents.
        /// </summary>
        /// <param name="data">
        ///    A <see cref="ByteVector" /> object containing the raw
        ///    VBRI header.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///    <paramref name="data" /> is <see langword="null" />.
        /// </exception>
        /// <exception cref="CorruptFileException">
        ///    <paramref name="data" /> does not start with <see
        ///    cref="FileIdentifier" />.
        /// </exception>
        public VBRIHeader(ByteVector data)
        {
            if (data == null)
                throw new ArgumentNullException ("data");

            // Check to see if a valid VBRI header is available.
            if (!data.StartsWith (FileIdentifier))
                throw new CorruptFileException (
                    "Not a valid VBRI header");

            // Size starts at Position 10
            int position = 10;

            size = data.Mid(position, 4).ToUInt();
            position += 4;

            // The number of Frames are found at Posistion 14
            frames = data.Mid(position, 4).ToUInt();
            position += 4;

            present = true;
        }
예제 #21
0
        public StreamHeader(ByteVector data, long streamLength)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }
            if (!data.StartsWith(FileIdentifier))
            {
                throw new CorruptFileException("Data does not begin with identifier.");
            }
            this.stream_length = streamLength;
            this.channels = data.Mid(8, 2).ToUShort(true);
            this.total_frames = data.Mid(10, 4).ToULong(true);
            this.bits_per_sample = data.Mid(14, 2).ToUShort(true);
            ByteVector vector = data.Mid(0x11, 1);
            ulong num = data.Mid(0x12, 2).ToULong(true);
            this.sample_rate = 0xac44L;
            ulong num2 = num;
            if ((num2 >= 0xaddcL) && (num2 <= 0xaddeL))
            {
                switch (((int) (num2 - 0xaddcL)))
                {
                    case 0:
                        if (vector == 12)
                        {
                            this.sample_rate = 0x2b77L;
                        }
                        return;

                    case 2:
                        if (vector == 13)
                        {
                            this.sample_rate = 0x56efL;
                        }
                        return;
                }
            }
            if (num2 == 0xac44L)
            {
                if (vector == 14)
                {
                    this.sample_rate = 0xac44L;
                }
                else if (vector == 13)
                {
                    this.sample_rate = 0x5622L;
                }
                else if (vector == 12)
                {
                    this.sample_rate = 0x2b11L;
                }
            }
            else if (num2 == 0xbb80L)
            {
                if (vector == 14)
                {
                    this.sample_rate = 0xbb80L;
                }
                else if (vector == 13)
                {
                    this.sample_rate = 0x5dc0L;
                }
            }
            else if (num2 == 0xfa00L)
            {
                if (vector == 13)
                {
                    this.sample_rate = 0x7d00L;
                }
                else if (vector == 12)
                {
                    this.sample_rate = 0x3e80L;
                }
                else if (vector == 11)
                {
                    this.sample_rate = 0x1f40L;
                }
            }
        }
		public void StartsWith ()
		{
			Assert.IsTrue (TestVector.StartsWith ("ABCDE"));
			Assert.IsFalse (TestVector.StartsWith ("NOOP"));
		}
예제 #23
0
		/// <summary>
		///    Constructs and initializes a new instance of <see
		///    cref="StreamHeader" /> for a specified header block and
		///    stream length.
		/// </summary>
		/// <param name="data">
		///    A <see cref="ByteVector" /> object containing the stream
		///    header data.
		/// </param>
		/// <param name="streamLength">
		///    A <see cref="long" /> value containing the length of the
		///    MusePAck stream in bytes.
		/// </param>
		/// <exception cref="ArgumentNullException">
		///    <paramref name="data" /> is <see langword="null" />.
		/// </exception>
		/// <exception cref="CorruptFileException">
		///    <paramref name="data" /> does not begin with <see
		///    cref="FileIdentifier" /> or is less than <see cref="Size"
		///    /> bytes long.
		/// </exception>
		public StreamHeader (ByteVector data, long streamLength)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
			
			if (!data.StartsWith (FileIdentifier))
				throw new CorruptFileException (
					"Data does not begin with identifier.");
			
			if (data.Count < Size)
				throw new CorruptFileException (
					"Insufficient data in stream header");
			
			stream_length = streamLength;
			version = data [3] & 15;
			
			if (version >= 7) {
				frames = data.Mid (4, 4).ToUInt (false);
				uint flags = data.Mid (8, 4).ToUInt (false);
				sample_rate = sftable [(int) (((flags >> 17) &
					1) * 2 + ((flags >> 16) & 1))];
				header_data = 0;
			} else {
				header_data = data.Mid (0, 4).ToUInt (false);
				version = (int) ((header_data >> 11) & 0x03ff);
				sample_rate = 44100;
				frames = data.Mid (4,
					version >= 5 ? 4 : 2).ToUInt (false);
			}
		}
        /// <summary>
        ///    Constructs and initializes a new instance of <see
        ///    cref="XingHeader" /> by reading its raw contents.
        /// </summary>
        /// <param name="data">
        ///    A <see cref="ByteVector" /> object containing the raw
        ///    Xing header.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///    <paramref name="data" /> is <see langword="null" />.
        /// </exception>
        /// <exception cref="CorruptFileException">
        ///    <paramref name="data" /> does not start with <see
        ///    cref="FileIdentifier" />.
        /// </exception>
        public XingHeader(ByteVector data)
        {
            if (data == null)
                throw new ArgumentNullException ("data");

            // Check to see if a valid Xing header is available.
            if (!data.StartsWith (FileIdentifier))
                throw new CorruptFileException (
                    "Not a valid Xing header");

            int position = 8;

            if ((data [7] & 0x01) != 0) {
                frames = data.Mid (position, 4).ToUInt ();
                position += 4;
            } else
                frames = 0;

            if ((data [7] & 0x02) != 0) {
                size = data.Mid (position, 4).ToUInt ();
                position += 4;
            } else
                size = 0;

            present = true;
        }
예제 #25
0
		/// <summary>
		///    Constructs and initializes a new instance of <see
		///    cref="StreamHeader" /> for a specified header block and
		///    stream length.
		/// </summary>
		/// <param name="data">
		///    A <see cref="ByteVector" /> object containing the stream
		///    header data.
		/// </param>
		/// <param name="streamLength">
		///    A <see cref="long" /> value containing the length of the
		///    AIFF Audio stream in bytes.
		/// </param>
		/// <exception cref="ArgumentNullException">
		///    <paramref name="data" /> is <see langword="null" />.
		/// </exception>
		/// <exception cref="CorruptFileException">
		///    <paramref name="data" /> does not begin with <see
		///    cref="FileIdentifier" /> 
		/// </exception>
		public StreamHeader(ByteVector data, long streamLength)
		{
			if (data == null)
				throw new ArgumentNullException("data");


			if (!data.StartsWith(FileIdentifier))
				throw new CorruptFileException(
					"Data does not begin with identifier.");

			stream_length = streamLength;

			// The first 8 bytes contain the Common chunk identifier "COMM"
			// And the size of the common chunk, which is always 18
			channels = data.Mid(8, 2).ToUShort(true);
			total_frames = data.Mid(10, 4).ToULong(true);
			bits_per_sample = data.Mid(14, 2).ToUShort(true);

			ByteVector sample_rate_indicator = data.Mid(17, 1);
			ulong sample_rate_tmp = data.Mid(18, 2).ToULong(true);
			sample_rate = 44100; // Set 44100 as default sample rate

			// The following are combinations that iTunes 8 encodes to.
			// There may be other combinations in the field, but i couldn't test them.
			switch (sample_rate_tmp)
			{
				case 44100:
					if (sample_rate_indicator == 0x0E)
					{
						sample_rate = 44100;
					}
					else if (sample_rate_indicator == 0x0D)
					{
						sample_rate = 22050;
					}
					else if (sample_rate_indicator == 0x0C)
					{
						sample_rate = 11025;
					}
					break;

				case 48000:
					if (sample_rate_indicator == 0x0E)
					{
						sample_rate = 48000;
					}
					else if (sample_rate_indicator == 0x0D)
					{
						sample_rate = 24000;
					}
					break;

				case 64000:
					if (sample_rate_indicator == 0x0D)
					{
						sample_rate = 32000;
					}
					else if (sample_rate_indicator == 0x0C)
					{
						sample_rate = 16000;
					}
					else if (sample_rate_indicator == 0x0B)
					{
						sample_rate = 8000;
					}
					break;

				case 44510:
					if (sample_rate_indicator == 0x0D)
					{
						sample_rate = 22255;
					}
					break;

				case 44508:
					if (sample_rate_indicator == 0x0C)
					{
						sample_rate = 11127;
					}
					break;
			}
		}
예제 #26
0
		/// <summary>
		///    Construcor.
		/// </summary>
		/// <param name="tag">
		///    A <see cref="System.UInt16"/> with the tag ID of the entry this instance
		///    represents
		/// </param>
		/// <param name="data">
		///    A <see cref="ByteVector"/> to be stored
		/// </param>
		public UserCommentIFDEntry (ushort tag, ByteVector data)
		{
			Tag = tag;

			if (data.StartsWith (COMMENT_ASCII_CODE)) {
				Value = data.ToString (StringType.Latin1, COMMENT_ASCII_CODE.Count, data.Count - COMMENT_ASCII_CODE.Count);
				return;
			}

			if (data.StartsWith (COMMENT_UNICODE_CODE)) {
				Value = data.ToString (StringType.UTF8, COMMENT_UNICODE_CODE.Count, data.Count - COMMENT_UNICODE_CODE.Count);
				return;
			}
				
			// Some programs like e.g. CanonZoomBrowser inserts just the first 0x00-byte
			// followed by 7-bytes of trash.
			if (data.StartsWith ((byte) 0x00) && data.Count >= 8) {
					
				// And CanonZoomBrowser fills some trailing bytes of the comment field
				// with '\0'. So we return only the characters before the first '\0'.
				int term = data.Find ("\0", 8);
				if (term != -1) {
					Value = data.ToString (StringType.Latin1, 8, term - 8);
				} else {
					Value = data.ToString (StringType.Latin1, 8, data.Count - 8);
				}
				return;
			}

			if (data.Data.Length == 0) {
				Value = String.Empty;
				return;
			}
			
			throw new NotImplementedException ("UserComment with other encoding than Latin1 or Unicode");
		}
예제 #27
0
파일: File.cs 프로젝트: rygos/iTagger
        /// <summary>
        ///    Reads an iTXt Chunk from file. The current position must be set
        ///    to the start of the Chunk Data. Such a Chunk may contain XMP data
        ///    or translated keywords.
        /// </summary>
        /// <param name="data_length">
        ///    A <see cref="System.Int32"/> with the length of the Chunk Data.
        /// </param>
        private void ReadiTXtChunk(int data_length)
        {
            long position = Tell;

            // iTXt Chunk
            //
            // N Bytes     Keyword
            // 1 Byte      Null Separator
            // 1 Byte      Compression Flag (0 for uncompressed data)
            // 1 Byte      Compression Method
            // N Bytes     Language Tag
            // 1 Byte      Null Separator
            // N Bytes     Translated Keyword
            // 1 Byte      Null Terminator
            // N Bytes     Txt
            //
            // Followed by 4 Bytes CRC data

            ByteVector data = ReadChunkData(data_length);

            CheckCRC(iTXt_CHUNK_TYPE, data, ReadCRC());

            // handle XMP, which has a fixed header
            if (data.StartsWith(XMP_CHUNK_HEADER))
            {
                ImageTag.AddTag(new XmpTag(data.Mid(XMP_CHUNK_HEADER.Length).ToString(StringType.UTF8), this));

                AddMetadataBlock(position - 8, data_length + 8 + 4);

                return;
            }

            int    terminator_index;
            string keyword = ReadKeyword(data, 0, out terminator_index);

            if (terminator_index + 2 >= data_length)
            {
                throw new CorruptFileException("Compression Flag and Compression Method byte expected");
            }

            byte compression_flag   = data[terminator_index + 1];
            byte compression_method = data[terminator_index + 2];

            //string language = ReadTerminatedString (data, terminator_index + 3, out terminator_index);
            //string translated_keyword = ReadTerminatedString (data, terminator_index + 1, out terminator_index);

            ByteVector txt_data = data.Mid(terminator_index + 1);

            if (compression_flag != 0x00)
            {
                txt_data = Decompress(compression_method, txt_data);

                // ignore unknown compression methods
                if (txt_data == null)
                {
                    return;
                }
            }

            string value   = txt_data.ToString();
            PngTag png_tag = GetTag(TagTypes.Png, true) as PngTag;

            if (png_tag.GetKeyword(keyword) == null)
            {
                png_tag.SetKeyword(keyword, value);
            }

            AddMetadataBlock(position - 8, data_length + 8 + 4);
        }
        /// <summary>
        ///    Construcor.
        /// </summary>
        /// <param name="tag">
        ///    A <see cref="System.UInt16"/> with the tag ID of the entry this instance
        ///    represents
        /// </param>
        /// <param name="data">
        ///    A <see cref="ByteVector"/> to be stored
        /// </param>
        /// <param name="file">
        ///    The file that's currently being parsed, used for reporting corruptions.
        /// </param>
        public UserCommentIFDEntry(ushort tag, ByteVector data, TagLib.File file)
        {
            Tag = tag;

            if (data.StartsWith (COMMENT_ASCII_CODE)) {
                Value = TrimNull (data.ToString (StringType.Latin1, COMMENT_ASCII_CODE.Count, data.Count - COMMENT_ASCII_CODE.Count));
                return;
            }

            if (data.StartsWith (COMMENT_UNICODE_CODE)) {
                Value = TrimNull (data.ToString (StringType.UTF8, COMMENT_UNICODE_CODE.Count, data.Count - COMMENT_UNICODE_CODE.Count));
                return;
            }

            var trimmed = data.ToString ().Trim ();
            if (trimmed.Length == 0 || trimmed == "\0") {
                Value = String.Empty;
                return;
            }

            // Some programs like e.g. CanonZoomBrowser inserts just the first 0x00-byte
            // followed by 7-bytes of trash.
            if (data.StartsWith ((byte) 0x00) && data.Count >= 8) {

                // And CanonZoomBrowser fills some trailing bytes of the comment field
                // with '\0'. So we return only the characters before the first '\0'.
                int term = data.Find ("\0", 8);
                if (term != -1) {
                    Value = data.ToString (StringType.Latin1, 8, term - 8);
                } else {
                    Value = data.ToString (StringType.Latin1, 8, data.Count - 8);
                }
                return;
            }

            if (data.Data.Length == 0) {
                Value = String.Empty;
                return;
            }

            // Try to parse anyway
            int offset = 0;
            int length = data.Count - offset;

            // Corruption that starts with a Unicode header and a count byte.
            if (data.StartsWith (COMMENT_BAD_UNICODE_CODE)) {
                offset = COMMENT_BAD_UNICODE_CODE.Count;
                length = data.Count - offset;
            }

            file.MarkAsCorrupt ("UserComment with other encoding than Latin1 or Unicode");
            Value = TrimNull (data.ToString (StringType.UTF8, offset, length));
        }
예제 #29
0
		/// <summary>
		///    Constructs and initializes a new instance of <see
		///    cref="Header" /> by reading it from raw header data.
		/// </summary>
		/// <param name="data">
		///    A <see cref="ByteVector" /> object containing the raw
		///    data to build the new instance from.
		/// </param>
		/// <exception cref="ArgumentNullException">
		///    <paramref name="data" /> is <see langword="null" />.
		/// </exception>
		/// <exception cref="CorruptFileException">
		///    <paramref name="data" /> is smaller than <see
		///    cref="Size" />, does not begin with <see
		///    cref="FileIdentifier" />, contains invalid flag data,
		///    or contains invalid size data.
		/// </exception>
		public Header (ByteVector data)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
			
			if (data.Count < Size)
				throw new CorruptFileException (
					"Provided data is smaller than object size.");
			
			if (!data.StartsWith (FileIdentifier))
				throw new CorruptFileException (
					"Provided data does not start with the file identifier");
			
			major_version = data [3];
			revision_number = data [4];
			flags = (HeaderFlags) data [5];
			
			if (major_version == 2 && ((int) flags & 127) != 0)
				throw new CorruptFileException (
					"Invalid flags set on version 2 tag.");
			
			if (major_version == 3 && ((int) flags & 15) != 0)
				throw new CorruptFileException (
					"Invalid flags set on version 3 tag.");
			
			if (major_version == 4 && ((int) flags & 7) != 0)
				throw new CorruptFileException (
					"Invalid flags set on version 4 tag.");
			
			for (int i = 6; i < 10; i ++)
				if (data [i] >= 128)
					throw new CorruptFileException (
						"One of the bytes in the header was greater than the allowed 128.");
			
			tag_size = SynchData.ToUInt (data.Mid (6, 4));
		}
예제 #30
0
        /// <summary>
        ///    Constructs and initializes a new instance of <see
        ///    cref="PageHeader" /> by reading a raw Ogg page header
        ///    from a specified position in a specified file.
        /// </summary>
        /// <param name="file">
        ///    A <see cref="File" /> object containing the file from
        ///    which the contents of the new instance are to be read.
        /// </param>
        /// <param name="position">
        ///    A <see cref="long" /> value specify at what position to
        ///    read.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///    <paramref name="file" /> is <see langword="null" />.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        ///    <paramref name="position" /> is less than zero or greater
        ///    than the size of the file.
        /// </exception>
        /// <exception cref="CorruptFileException">
        ///    The Ogg identifier could not be found at the correct
        ///    location.
        /// </exception>
        public PageHeader(File file, long position)
        {
            if (file == null)
            {
                throw new ArgumentNullException("file");
            }

            if (position < 0 || position > file.Length - 27)
            {
                throw new ArgumentOutOfRangeException(
                          "position");
            }

            file.Seek(position);

            // An Ogg page header is at least 27 bytes, so we'll go
            // ahead and read that much and then get the rest when
            // we're ready for it.

            ByteVector data = file.ReadBlock(27);

            if (data.Count < 27 || !data.StartsWith("OggS"))
            {
                throw new CorruptFileException(
                          "Error reading page header");
            }

            version    = data [4];
            this.flags = (PageFlags)data [5];
            absolute_granular_position = data.Mid(6, 8).ToULong(
                false);
            stream_serial_number = data.Mid(14, 4).ToUInt(false);
            page_sequence_number = data.Mid(18, 4).ToUInt(false);

            // Byte number 27 is the number of page segments, which
            // is the only variable length portion of the page
            // header. After reading the number of page segments
            // we'll then read in the coresponding data for this
            // count.
            int        page_segment_count = data [26];
            ByteVector page_segments      =
                file.ReadBlock(page_segment_count);

            // Another sanity check.
            if (page_segment_count < 1 ||
                page_segments.Count != page_segment_count)
            {
                throw new CorruptFileException(
                          "Incorrect number of page segments");
            }

            // The base size of an Ogg page 27 bytes plus the number
            // of lacing values.
            size         = (uint)(27 + page_segment_count);
            packet_sizes = new List <int> ();

            int packet_size = 0;

            data_size = 0;

            for (int i = 0; i < page_segment_count; i++)
            {
                data_size   += page_segments [i];
                packet_size += page_segments [i];

                if (page_segments [i] < 255)
                {
                    packet_sizes.Add(packet_size);
                    packet_size = 0;
                }
            }

            if (packet_size > 0)
            {
                packet_sizes.Add(packet_size);
            }
        }