Logo Search packages:      
Sourcecode: f-spot version File versions  Download package

Frame.cs

//
// Frame.cs:
//
// Author:
//   Brian Nickel (brian.nickel@gmail.com)
//
// Original Source:
//   id3v2frame.cpp from TagLib
//
// Copyright (C) 2005-2007 Brian Nickel
// Copyright (C) 2002,2003 Scott Wheeler (Original Implementation)
//
// 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.Id3v2 {
      /// <summary>
      ///    This abstract class provides a basic framework for representing
      ///    ID3v2.4 frames.
      /// </summary>
00035       public abstract class Frame : ICloneable
      {
            #region Private Fields
            
            /// <summary>
            ///    Contains the frame's header.
            /// </summary>
00042             private FrameHeader header;
            
            /// <summary>
            ///    Contains the frame's grouping ID.
            /// </summary>
00047             private byte group_id;
            
            /// <summary>
            ///    Contains the frame's encryption ID.
            /// </summary>
00052             private byte encryption_id;
            
            #endregion
            
            
            
            #region Constructors
            
            /// <summary>
            ///    Constructs and initializes a new instance of <see
            ///    cref="Frame" /> by reading the raw header encoded in the
            ///    specified ID3v2 version.
            /// </summary>
            /// <param name="data">
            ///    A <see cref="ByteVector" /> object containing the
            ///    identifier or header data to use for the new instance.
            /// </param>
            /// <param name="version">
            ///    A <see cref="byte" /> value indicating the ID3v2 version
            ///    which <paramref name="data" /> is encoded in.
            /// </param>
            /// <exception cref="ArgumentNullException">
            ///    <paramref name="data" /> is <see langword="null" />.
            /// </exception>
            /// <exception cref="ArgumentException">
            ///    <paramref name="data" /> does not contain a complete
            ///    identifier.
            /// </exception>
00080             protected Frame (ByteVector data, byte version)
            {
                  if (data == null)
                        throw new ArgumentNullException ("data");
                  
                  if (data.Count < ((version < 3) ? 3 : 4))
                        throw new ArgumentException (
                              "Data contains an incomplete identifier.",
                              "data");
                  
                  header = new FrameHeader (data, version);
            }
            
            /// <summary>
            ///    Constructs and initializes a new instance of <see
            ///    cref="Frame" /> with a specified header.
            /// </summary>
            /// <param name="header">
            ///    A <see cref="FrameHeader" /> value containing the header
            ///    to use for the new instance.
            /// </param>
00101             protected Frame (FrameHeader header)
            {
                  this.header = header;
            }
            
            #endregion
            
            
            
            #region Public Properties
            
            /// <summary>
            ///    Gets the frame ID for the current instance.
            /// </summary>
            /// <value>
            ///    A <see cref="ReadOnlyByteVector" /> object containing the
            ///    four-byte ID3v2.4 frame header for the current instance.
            /// </value>
00119             public ReadOnlyByteVector FrameId {
                  get {return header.FrameId;}
            }
            
            /// <summary>
            ///    Gets the size of the current instance as it was last
            ///    stored on disk.
            /// </summary>
            /// <value>
            ///    A <see cref="uint" /> value containing the size of the
            ///    current instance as it was last stored on disk.
            /// </value>
00131             public uint Size {
                  get {return header.FrameSize;}
            }
            
            /// <summary>
            ///    Gets and sets the frame flags applied to the current
            ///    instance.
            /// </summary>
            /// <value>
            ///    A bitwise combined <see cref="FrameFlags" /> value
            ///    containing the frame flags applied to the current
            ///    instance.
            /// </value>
            /// <remarks>
            ///    If the value includes either <see
            ///    cref="FrameFlags.Encryption" /> or <see
            ///    cref="FrameFlags.Compression" />, <see cref="Render" />
            ///    will throw a <see cref="NotImplementedException" />.
            /// </remarks>
00150             public FrameFlags Flags {
                  get {return header.Flags;}
                  set {header.Flags = value;}
            }
            
            /// <summary>
            ///    Gets and sets the grouping ID applied to the current
            ///    instance.
            /// </summary>
            /// <value>
            ///    A <see cref="short" /> value containing the grouping
            ///    identifier for the current instance, or -1 if not set.
            /// </value>
            /// <remarks>
            ///    Grouping identifiers can be between 0 and 255. Setting
            ///    any other value will unset the grouping identity and set
            ///    the value to -1.
            /// </remarks>
00168             public short GroupId {
                  get {
                        return (Flags & FrameFlags.GroupingIdentity)
                              != 0 ? group_id : (short) -1;
                  }
                  set {
                        if (value >= 0x00 && value <= 0xFF) {
                              group_id = (byte) value;
                              Flags |= FrameFlags.GroupingIdentity;
                        } else {
                              Flags &= ~FrameFlags.GroupingIdentity;
                        }
                  }
            }
            
            /// <summary>
            ///    Gets and sets the encryption ID applied to the current
            ///    instance.
            /// </summary>
            /// <value>
            ///    A <see cref="short" /> value containing the encryption
            ///    identifier for the current instance, or -1 if not set.
            /// </value>
            /// <remarks>
            ///    <para>Encryption identifiers can be between 0 and 255.
            ///    Setting any other value will unset the grouping identity
            ///    and set the value to -1.</para>
            ///    <para>If set, <see cref="Render" /> will throw a <see
            ///    cref="NotImplementedException" />.</para>
            /// </remarks>
00198             public short EncryptionId {
                  get {
                        return (Flags & FrameFlags.Encryption) != 0 ?
                              encryption_id : (short) -1;
                  }
                  set {
                        if (value >= 0x00 && value <= 0xFF) {
                              encryption_id = (byte) value;
                              Flags |= FrameFlags.Encryption;
                        } else {
                              Flags &= ~FrameFlags.Encryption;
                        }
                  }
            }
            
            #endregion
            
            
            
            #region Public Methods
            
            /// <summary>
            ///    Renders the current instance, encoded in a specified
            ///    ID3v2 version.
            /// </summary>
            /// <param name="version">
            ///    A <see cref="byte" /> value specifying the version of
            ///    ID3v2 to use when encoding the current instance.
            /// </param>
            /// <returns>
            ///    A <see cref="ByteVector" /> object containing the
            ///    rendered version of the current instance.
            /// </returns>
            /// <exception cref="NotImplementedException">
            ///    The current instance uses some feature that cannot be
            ///    implemented in the specified ID3v2 version, or uses a
            ///    feature, such as encryption or compression, which is not
            ///    yet implemented in the library.
            /// </exception>
00237             public virtual ByteVector Render (byte version)
            {
                  // Remove flags that are not supported by older versions
                  // of ID3v2.
                  if (version < 4)
                        Flags &= ~(FrameFlags.DataLengthIndicator |
                              FrameFlags.Unsynchronisation);
                  
                  if (version < 3)
                        Flags &= ~(FrameFlags.Compression |
                              FrameFlags.Encryption |
                              FrameFlags.FileAlterPreservation |
                              FrameFlags.GroupingIdentity |
                              FrameFlags.ReadOnly |
                              FrameFlags.TagAlterPreservation);
                  
                  ByteVector field_data = RenderFields (version);
                  
                  // If we don't have any content, don't render anything.
                  // This will cause the frame to not be rendered.
                  if (field_data.Count == 0)
                        return new ByteVector ();
                  
                  ByteVector front_data = new ByteVector ();
                  
                  if ((Flags & (FrameFlags.Compression |
                        FrameFlags.DataLengthIndicator)) != 0)
                        front_data.Add (ByteVector.FromUInt ((uint)
                              field_data.Count));
                  
                  if ((Flags & FrameFlags.GroupingIdentity) != 0)
                        front_data.Add (group_id);
                  
                  if ((Flags & FrameFlags.Encryption) != 0)
                        front_data.Add (encryption_id);
                  
                  // FIXME: Implement compression.
                  if ((Flags & FrameFlags.Compression) != 0)
                        throw new NotImplementedException (
                              "Compression not yet supported");
                  
                  // FIXME: Implement encryption.
                  if ((Flags & FrameFlags.Encryption) != 0)
                        throw new NotImplementedException (
                              "Encryption not yet supported");
                  
                  if ((Flags & FrameFlags.Unsynchronisation) != 0)
                        SynchData.UnsynchByteVector (field_data);
                  
                  if (front_data.Count > 0)
                        field_data.Insert (0, front_data);
                  
                  header.FrameSize = (uint) field_data.Count;
                  ByteVector header_data = header.Render (version);
                  header_data.Add (field_data);
                  
                  return header_data;
            }
            
            #endregion
            
            
            
            #region Public Static Methods
            
            /// <summary>
            ///    Gets the text delimiter for a specified encoding.
            /// </summary>
            /// <param name="type">
            ///    A <see cref="StringType" /> value specifying the encoding
            ///    to get the delimiter for.
            /// </param>
            /// <returns>
            ///    A <see cref="ByteVector" /> object containing the
            ///    delimiter for the specified encoding.
            /// </returns>
            [Obsolete("Use ByteVector.TextDelimiter.")]
00314             public static ByteVector TextDelimiter (StringType type)
            {
                  return ByteVector.TextDelimiter (type);
            }
            
            #endregion
            
            
            
            #region Protected Methods
            
            /// <summary>
            ///    Converts an encoding to be a supported encoding for a
            ///    specified tag version.
            /// </summary>
            /// <param name="type">
            ///    A <see cref="StringType" /> value containing the original
            ///    encoding.
            /// </param>
            /// <param name="version">
            ///    A <see cref="byte" /> value containing the ID3v2 version
            ///    to be encoded for.
            /// </param>
            /// <returns>
            ///    A <see cref="StringType" /> value containing the correct
            ///    encoding to use, based on <see
            ///    cref="Tag.ForceDefaultEncoding" /> and what is supported
            ///    by <paramref name="version" />.
            /// </returns>
00343             protected static StringType CorrectEncoding (StringType type,
                                                         byte version)
            {
                  if (Tag.ForceDefaultEncoding)
                        type = Tag.DefaultEncoding;
                  
                  return (version < 4 && type == StringType.UTF8) ?
                        StringType.UTF16 : type;
            }
            
            /// <summary>
            ///    Populates the current instance by reading the raw frame
            ///    from disk, optionally reading the header.
            /// </summary>
            /// <param name="data">
            ///    A <see cref="ByteVector" /> object containing the raw
            ///    ID3v2 frame.
            /// </param>
            /// <param name="offset">
            ///    A <see cref="int" /> value containing the offset in
            ///    <paramref name="data" /> at which the frame begins.
            /// </param>
            /// <param name="version">
            ///    A <see cref="byte" /> value containing the ID3v2 version
            ///    of the raw frame contained in <paramref name="data" />.
            /// </param>
            /// <param name="readHeader">
            ///    A <see cref="bool" /> value indicating whether or not to
            ///    read the header into current instance.
            /// </param>
00373             protected void SetData (ByteVector data, int offset,
                                    byte version, bool readHeader)
            {
                  if (readHeader)
                        header = new FrameHeader (data, version);
                  ParseFields (FieldData (data, offset, version),
                        version);
            }
            
            /// <summary>
            ///    Populates the values in the current instance by parsing
            ///    its field data in a specified version.
            /// </summary>
            /// <param name="data">
            ///    A <see cref="ByteVector" /> object containing the
            ///    extracted field data.
            /// </param>
            /// <param name="version">
            ///    A <see cref="byte" /> indicating the ID3v2 version the
            ///    field data is encoded in.
            /// </param>
            protected abstract void ParseFields (ByteVector data,
                                                 byte version);
            
            /// <summary>
            ///    Renders the values in the current instance into field
            ///    data for a specified version.
            /// </summary>
            /// <param name="version">
            ///    A <see cref="byte" /> indicating the ID3v2 version the
            ///    field data is to be encoded in.
            /// </param>
            /// <returns>
            ///    A <see cref="ByteVector" /> object containing the
            ///    rendered field data.
            /// </returns>
            protected abstract ByteVector RenderFields (byte version);
            
            /// <summary>
            ///    Extracts the field data from the raw data portion of an
            ///    ID3v2 frame.
            /// </summary>
            /// <param name="frameData">
            ///    A <see cref="ByteVector" /> object containing fraw frame
            ///    data.
            /// </param>
            /// <param name="offset">
            ///    A <see cref="int" /> value containing the index at which
            ///    the data is contained.
            /// </param>
            /// <param name="version">
            ///    A <see cref="byte" /> value containing the ID3v2 version
            ///    of the data.
            /// </param>
            /// <returns>
            ///    A <see cref="ByteVector" /> object containing the
            ///    extracted field data.
            /// </returns>
            /// <remarks>
            ///    This method is necessary for extracting extra data
            ///    prepended to the frame such as the grouping ID.
            /// </remarks>
            /// <exception cref="ArgumentNullException">
            ///    <paramref name="frameData" /> is <see langword="null" />.
            /// </exception>
00438             protected ByteVector FieldData (ByteVector frameData,
                                            int offset, byte version)
            {
                  if (frameData == null)
                        throw new ArgumentNullException ("frameData");
                  
                  int data_offset = offset + (int) FrameHeader.Size (version);
                  int data_length = (int) Size;

                  if ((Flags & (FrameFlags.Compression |
                        FrameFlags.DataLengthIndicator)) != 0) {
                        data_offset += 4;
                        data_length -= 4;
                  }
                  
                  if ((Flags & FrameFlags.GroupingIdentity) != 0) {
                        if (frameData.Count >= data_offset)
                              throw new TagLib.CorruptFileException (
                                    "Frame data incomplete.");
                        group_id = frameData [data_offset++];
                        data_length--;
                  }
                  
                  if ((Flags & FrameFlags.Encryption) != 0) {
                        if (frameData.Count >= data_offset)
                              throw new TagLib.CorruptFileException (
                                    "Frame data incomplete.");
                        encryption_id = frameData [data_offset++];
                        data_length--;
                  }

                  data_length = Math.Min (data_length, frameData.Count - data_offset);
                  if (data_length < 0 )
                        throw new CorruptFileException (
                              "Frame size less than zero.");
                  
                  ByteVector data = frameData.Mid (data_offset,
                        data_length);

            if ((Flags & FrameFlags.Unsynchronisation) != 0) {
                int before_length = data.Count;
                        SynchData.ResynchByteVector (data);
                data_length -= (data.Count - before_length);
            }
                  
                  // FIXME: Implement encryption.
                  if ((Flags & FrameFlags.Encryption) != 0)
                        throw new NotImplementedException ();
                  
                  // FIXME: Implement compression.
                  if ((Flags & FrameFlags.Compression) != 0)
                        throw new NotImplementedException ();
                  /*
                  if(d->header->compression()) {
                        ByteVector data(frameDataLength);
                        uLongf uLongTmp = frameDataLength;
                        ::uncompress((Bytef *) data.data(),
                        (uLongf *) &uLongTmp,
                        (Bytef *) frameData.data() + frameDataOffset,
                        size());
                        return data;
                  }
                  */
                  
                  return data;
            }
            
#endregion
            
            
            
#region ICloneable
            
            /// <summary>
            ///    Creates a deep copy of the current instance.
            /// </summary>
            /// <returns>
            ///    A new <see cref="Frame" /> object identical to the
            ///    current instance.
            /// </returns>
            /// <remarks>
            ///    This method is implemented by rendering the current
            ///    instance as an ID3v2.4 frame and using <see
            ///    cref="FrameFactory.CreateFrame" /> to create a new
            ///    frame. As such, this method should be overridden by
            ///    child classes.
            /// </remarks>
00525             public virtual Frame Clone ()
            {
                  int index = 0;
                  return FrameFactory.CreateFrame (Render (4), ref index,
                        4, false);
            }
            
            object ICloneable.Clone ()
            {
                  return Clone ();
            }
            
#endregion
      }
}

Generated by  Doxygen 1.6.0   Back to index