Logo Search packages:      
Sourcecode: taglib-sharp version File versions  Download package

BoxHeader.cs

//
// BoxHeader.cs: Provides support for reading and writing headers for ISO/IEC
// 14496-12 boxes.
//
// Author:
//   Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2006-2007 Brian Nickel
// 
// This library is free software; you can redistribute it and/or modify
// it  under the terms of the GNU Lesser General Public License version
// 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
// USA
//

using System;

namespace TagLib.Mpeg4 {
      /// <summary>
      ///    This structure provides support for reading and writing headers
      ///    for ISO/IEC 14496-12 boxes.
      /// </summary>
00032       public struct BoxHeader
      {
            #region Private Fields
            
            /// <summary>
            ///    Contains the box type.
            /// </summary>
00039             private ByteVector box_type;
            
            /// <summary>
            ///    Contains the extended type.
            /// </summary>
00044             private ByteVector extended_type;
            
            /// <summary>
            ///    Contains the box size.
            /// </summary>
00049             private ulong box_size;
            
            /// <summary>
            ///    Contains the header size.
            /// </summary>
00054             private uint header_size;
            
            /// <summary>
            ///    Contains the position of the header.
            /// </summary>
00059             private long position;
            
            /// <summary>
            ///    Contains the box (temporarily).
            /// </summary>
00064             private Box box;
            
            /// <summary>
            ///    Indicated that the header was read from a file.
            /// </summary>
00069             private bool from_disk;
            
            #endregion
            
            
            
            #region Public Fields
            
            /// <summary>
            ///    An empty box header.
            /// </summary>
00080             public static readonly BoxHeader Empty = new BoxHeader ("xxxx");
            
            #endregion
            
            
            
            #region Constructors
            
            /// <summary>
            ///    Constructs and initializes a new instance of <see
            ///    cref="BoxHeader" /> by reading it from a specified seek
            ///    position in a specified file.
            /// </summary>
            /// <param name="file">
            ///    A <see cref="TagLib.File" /> object to read the new
            ///    instance from.
            /// </param>
            /// <param name="position">
            ///    A <see cref="long" /> value specifiying the seek position
            ///    in <paramref name="file" /> at which to start reading.
            /// </param>
            /// <exception cref="ArgumentNullException">
            ///    <paramref name="file" /> is <see langword="null" />.
            /// </exception>
            /// <exception cref="CorruptFileException">
            ///    There isn't enough data in the file to read the complete
            ///    header.
            /// </exception>
00108             public BoxHeader (TagLib.File file, long position)
            {
                  if (file == null)
                        throw new ArgumentNullException ("file");
                  
                  this.box = null;
                  this.from_disk = true;
                  this.position = position;
                  file.Seek (position);
                  
                  ByteVector data = file.ReadBlock (32);
                  int offset = 0;
                  
                  if (data.Count < 8 + offset)
                        throw new CorruptFileException (
                              "Not enough data in box header.");
                  
                  header_size = 8;
                  box_size = data.Mid (offset, 4).ToUInt ();
                  box_type = data.Mid (offset + 4, 4);
                  
                  // If the size is 1, that just tells us we have a
                  // massive ULONG size waiting for us in the next 8
                  // bytes.
                  if (box_size == 1) {
                        if (data.Count < 8 + offset)
                              throw new CorruptFileException (
                                    "Not enough data in box header.");
                        
                        header_size += 8;
                        box_size = data.Mid (offset, 8).ToULong ();
                        offset += 8;
                  }
                  
                  // UUID has a special header with 16 extra bytes.
                  if (box_type == Mpeg4.BoxType.Uuid) {
                        if (data.Count < 16 + offset)
                              throw new CorruptFileException (
                                    "Not enough data in box header.");
                        
                        header_size += 16;
                        extended_type = data.Mid (offset, 16);
                  } else
                        extended_type = null;
            }
            
            /// <summary>
            ///    Constructs and initializes a new instance of <see
            ///    cref="BoxHeader" /> with a specified box type.
            /// </summary>
            /// <param name="type">
            ///    A <see cref="ByteVector" /> object containing the four
            ///    byte box type.
            /// </param>
            /// <remarks>
            ///    <see cref="BoxHeader(ByteVector,ByteVector)" /> must be
            ///    used to create a header of type "<c>uuid</c>".
            /// </remarks>
            /// <exception cref="ArgumentNullException">
            ///    <paramref name="type" /> is <see langword="null" /> or is
            ///    equal to "<c>uuid</c>".
            /// </exception>
            /// <exception cref="ArgumentException">
            ///    <paramref name="type" /> isn't exactly 4 bytes long.
            /// </exception>
00173             public BoxHeader (ByteVector type) : this (type, null)
            {
            }
            
            /// <summary>
            ///    Constructs and initializes a new instance of <see
            ///    cref="BoxHeader" /> with a specified box type and
            ///    optionally extended type.
            /// </summary>
            /// <param name="type">
            ///    A <see cref="ByteVector" /> object containing the four
            ///    byte box type.
            /// </param>
            /// <param name="extendedType">
            ///    A <see cref="ByteVector" /> object containing the four
            ///    byte box type.
            /// </param>
            /// <exception cref="ArgumentNullException">
            ///    <paramref name="type" /> is <see langword="null" /> - or -
            ///    <paramref name="type" /> is equal to "<c>uuid</c>" and
            ///    <paramref name="extendedType" /> is <see langword="null"
            ///    />.
            /// </exception>
            /// <exception cref="ArgumentException">
            ///    <paramref name="type" /> isn't exactly 4 bytes long - or
            ///    - <paramref name="type" /> isn't "<c>uuid</c>" but
            ///    <paramref name="extendedType" /> isn't <see
            ///    langword="null" /> - or - paramref name="type" /> is
            ///    "<c>uuid</c>" but <paramref name="extendedType" /> isn't
            ///    exactly 16 bytes long.
            /// </exception>
00204             public BoxHeader (ByteVector type, ByteVector extendedType)
            {
                  position = -1;
                  box = null;
                  from_disk = false;
                  box_type = type;
                  
                  if (type == null)
                        throw new ArgumentNullException ("type");
                  
                  if (type.Count != 4)
                        throw new ArgumentException (
                              "Box type must be 4 bytes in length.",
                              "type");
                  
                  box_size = header_size = 8;
                  
                  if (type != "uuid") {
                        if (extendedType != null)
                              throw new ArgumentException (
                                    "Extended type only permitted for 'uuid'.",
                                    "extendedType");
                        
                        this.extended_type = extendedType;
                        return;
                  }
                  
                  if (extendedType == null)
                        throw new ArgumentNullException ("extendedType");
                  
                  if (extendedType.Count != 16)
                        throw new ArgumentException (
                              "Extended type must be 16 bytes in length.",
                              "extendedType");
                  
                  box_size = header_size = 24;
                  this.extended_type = extendedType;
            }
            
            #endregion
            
            
            
            #region Public Properties
            
            /// <summary>
            ///    Gets the type of box represented by the current instance.
            /// </summary>
            /// <value>
            ///    A <see cref="ByteVector" /> object containing the 4 byte
            ///    box type.
            /// </value>
00256             public ByteVector BoxType {
                  get {return box_type;}
            }
            
            /// <summary>
            ///    Gets the extended type of the box represented by the
            ///    current instance.
            /// </summary>
            /// <value>
            ///    A <see cref="ByteVector" /> object containing the 16 byte
            ///    extended type, or <see langword="null" /> if <see
            ///    cref="BoxType" /> is not "<c>uuid</c>".
            /// </value>
00269             public ByteVector ExtendedType {
                  get {return extended_type;}
            }
            
            /// <summary>
            ///    Gets the size of the header represented by the current
            ///    instance.
            /// </summary>
            /// <value>
            ///    A <see cref="long" /> value containing the size of the
            ///    header represented by the current instance.
            /// </value>
00281             public long HeaderSize {
                  get {return header_size;}
            }
            
            /// <summary>
            ///    Gets and sets the size of the data in the box described
            ///    by the current instance.
            /// </summary>
            /// <value>
            ///    A <see cref="long" /> value containing the size of the
            ///    data in the box described by the current instance.
            /// </value>
00293             public long DataSize {
                  get {return (long) (box_size - header_size);}
                  set {box_size = (ulong) value + header_size;}
            }
            
            /// <summary>
            ///    Gets the offset of the box data from the position of the
            ///    header.
            /// </summary>
            /// <value>
            ///    A <see cref="long" /> value containing the offset of the
            ///    box data from the position of the header.
            /// </value>
            [Obsolete("Use HeaderSize")]
00307             public long DataOffset {
                  get {return header_size;}
            }
            
            /// <summary>
            ///    Gets the total size of the box described by the current
            ///    instance.
            /// </summary>
            /// <value>
            ///    A <see cref="long" /> value containing the total size of
            ///    the box described by the current instance.
            /// </value>
00319             public long TotalBoxSize {
                  get {return (long)box_size;}
            }
            
            /// <summary>
            ///    Gets the position box represented by the current instance
            ///    in the file it comes from.
            /// </summary>
            /// <value>
            ///    A <see cref="long" /> value containing the position box
            ///    represented by the current instance in the file it comes
            ///    from.
            /// </value>
00332             public long Position {
                  get {return from_disk ? position : -1;}
            }
            
            #endregion
            
            
            
            #region Public Methods
            
            /// <summary>
            ///    Overwrites the header on disk, updating it to include a
            ///    change in the size of the box.
            /// </summary>
            /// <param name="file">
            ///    A <see cref="TagLib.File" /> object containing the file
            ///    from which the box originates.
            /// </param>
            /// <param name="sizeChange">
            ///    A <see cref="long" /> value indicating the change in the
            ///    size of the box described by the current instance.
            /// </param>
            /// <returns>
            ///    The size change encountered by the box that parents the
            ///    box described the the current instance, equal to the
            ///    size change of the box plus any size change that should
            ///    happen in the header.
            /// </returns>
00360             public long Overwrite (TagLib.File file, long sizeChange)
            {
                  if (file == null)
                        throw new ArgumentNullException ("file");
                  
                  if (!from_disk)
                        throw new InvalidOperationException (
                              "Cannot overwrite headers not on disk.");
                  
                  long old_header_size = HeaderSize;
                  DataSize += sizeChange;
                  file.Insert (Render (), position, old_header_size);
                  return sizeChange + HeaderSize - old_header_size;
            }
            
            /// <summary>
            ///    Renders the header represented by the current instance.
            /// </summary>
            /// <returns>
            ///    A <see cref="ByteVector" /> object containing the
            ///    rendered version of the current instance.
            /// </returns>
00382             public ByteVector Render ()
            {
                  // Enlarge for size if necessary.
                  if ((header_size == 8 || header_size == 24) &&
                        box_size > uint.MaxValue) {
                        header_size += 8;
                        box_size += 8;
                  }
                  
                  // Add the box size and type to the output.
                  ByteVector output = ByteVector.FromUInt (
                        (header_size == 8 || header_size == 24) ?
                        (uint) box_size : 1);
                  output.Add (box_type);
                  
                  // If the box size is 16 or 32, we must have more a
                  // large header to append.
                  if (header_size == 16 || header_size == 32)
                        output.Add (ByteVector.FromULong (box_size));
                  
                  // The only reason for such a big size is an extended
                  // type. Extend!!!
                  if (header_size >= 24)
                        output.Add (extended_type);
                  
                  return output;
            }
            
            #endregion
            
            
            
            #region Internal Properties
            
            /// <summary>
            ///    Gets and sets the box represented by the current instance
            ///    as a means of temporary storage for internal uses.
            /// </summary>
00420             internal Box Box {get {return box;} set {box = value;}}
            
            #endregion
      }
}

Generated by  Doxygen 1.6.0   Back to index