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

FrameFactory.cs

//
// FrameFactory.cs:
//
// Author:
//   Brian Nickel (brian.nickel@gmail.com)
//
// Original Source:
//   id3v2framefactory.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.Collections.Generic;
 
namespace TagLib.Id3v2
{
      /// <summary>
      ///    This static class performs the necessary operations to determine
      ///    and create the correct child class of <see cref="Frame" /> for a
      ///    given raw ID3v2 frame.
      /// </summary>
      /// <remarks>
      ///    By default, <see cref="FrameFactory" /> will only load frames
      ///    contained in the library. To add additional frames to the
      ///    process, register a frame creator with <see
      ///    cref="AddFrameCreator" />.
      /// </remarks>
00043       public static class FrameFactory
      {
            /// <summary>
            ///    Creates a frame from a specified block of data, or
            ///    returns <see langword="null" /> if unsupported.
            /// </summary>
            /// <param name="data">
            ///    A <see cref="ByteVector" /> object containing a raw ID3v2
            ///    frame.
            /// </param>
            /// <param name="offset">
            ///    A <see cref="int" /> value specifying the offset in
            ///    <paramref name="data"/> at which the frame data begins.
            /// </param>
            /// <param name="header">
            ///    A <see cref="FrameHeader" /> object for the frame
            ///    contained in <paramref name="data" />.
            /// </param>
            /// <param name="version">
            ///    A <see cref="byte" /> specifying the version of ID3v2 the
            ///    raw frame data is stored in.
            /// </param>
            /// <returns>
            ///     A <see cref="Frame" /> object if the method was able to
            ///     match and create one. Otherwise <see langword="null" />.
            /// </returns>
            /// <remarks>
            ///    <para>Frame creators are used to provide access or
            ///    support for items that are left out of TagLib#.</para>
            /// </remarks>
            /// <example>
            ///    <code lang="C#">
            /// public Frame Creator (TagLib.ByteVector data, TagLib.Id3v2.FrameHeader header)
            /// {
            ///   if (header.FrameId == "RVRB")
            ///         return new ReverbFrame (data, header);
            ///   else
            ///         return null;
            /// }
            /// ...
            /// TagLib.Id3v2.FrameFactor.AddFrameCreator (ReverbFrame.Creator);
            ///   </code>
            /// </example>
            /// <seealso cref="AddFrameCreator" />
            public delegate Frame FrameCreator (ByteVector data, int offset,
                                                FrameHeader header,
                                                byte version);
            
            /// <summary>
            ///    Contains registered frame creators.
            /// </summary>
00094             private static List<FrameCreator> frame_creators =
                  new List<FrameCreator> ();
            
            /// <summary>
            ///    Creates a <see cref="Frame" /> object by reading it from
            ///    raw ID3v2 frame data.
            /// </summary>
            /// <param name="data">
            ///    A <see cref="ByteVector" /> object containing a raw ID3v2
            ///    frame.
            /// </param>
            /// <param name="offset">
            ///    A <see cref="int" /> value reference specifying at what
            ///    index in <paramref name="data" /> at which the frame
            ///    begins. After reading, it contains the offset of the next
            ///    frame to be read.
            /// </param>
            /// <param name="version">
            ///    A <see cref="byte" /> value specifying the ID3v2 version
            ///    the frame in <paramref name="data"/> is encoded in.
            /// </param>
            /// <param name="alreadyUnsynched">
            ///    A <see cref="bool" /> value specifying whether the entire
            ///    tag has already been unsynchronized.
            /// </param>
            /// <returns>
            ///    A <see cref="Frame" /> object read from the data, or <see
            ///    langword="null" /> if none is found.
            /// </returns>
            /// <exception cref="System.NotImplementedException">
            ///    The frame contained in the raw data could not be
            ///    converted to ID3v2 or uses encryption or compression.
            /// </exception>
00127             public static Frame CreateFrame (ByteVector data,
                                             ref int offset, byte version, bool alreadyUnsynched)
            {
                  int position = offset;
                  
                  FrameHeader header = new FrameHeader (data.Mid (position,
                        (int) FrameHeader.Size (version)), version);
                  
                  offset += (int) (header.FrameSize + FrameHeader.Size (
                        version));
                  
                  if (header.FrameId == null)
                        throw new System.NotImplementedException ();
                  
                  foreach (byte b in header.FrameId) {
                        char c = (char) b;
                              if ((c < 'A' || c > 'Z') &&
                                    (c < '1' || c > '9'))
                                    return null;
                  }

            if (alreadyUnsynched) {
                // Mark the frame as not Unsynchronozed because the entire
                // tag has already been Unsynchronized
                header.Flags &= ~FrameFlags.Unsynchronisation;
            }
                  
                  // Windows Media Player may create zero byte frames.
                  // Just send them off as unknown and delete them.
                  if (header.FrameSize == 0) {
                        header.Flags |= FrameFlags.TagAlterPreservation;
                        return new UnknownFrame (data, position, header,
                              version);
                  }
                  
                  // TODO: Support Compression.
                  if ((header.Flags & FrameFlags.Compression) != 0)
                        throw new System.NotImplementedException ();
                  
                  // TODO: Support Encryption.
                  if ((header.Flags & FrameFlags.Encryption) != 0)
                        throw new System.NotImplementedException ();
                  
                  foreach (FrameCreator creator in frame_creators) {
                        Frame frame = creator (data, position, header,
                              version);
                        
                        if (frame != null)
                              return frame;
                  }
                  
                  // This is where things get necissarily nasty.  Here we
                  // determine which Frame subclass (or if none is found
                  // simply an Frame) based on the frame ID. Since there
                  // are a lot of possibilities, that means a lot of if
                  // blocks.
                  
                  // Text Identification (frames 4.2)
                  if (header.FrameId == FrameType.TXXX)
                        return new UserTextInformationFrame (data,
                              position, header, version);
                  
                  if (header.FrameId [0] == (byte) 'T')
                        return new TextInformationFrame (data, position,
                              header, version);
                  
                  // Unique File Identifier (frames 4.1)
                  if (header.FrameId == FrameType.UFID)
                        return new UniqueFileIdentifierFrame (data,
                              position, header, version);
                  
                  // Music CD Identifier (frames 4.5)
                  if (header.FrameId == FrameType.MCDI)
                        return new MusicCdIdentifierFrame (data,
                              position, header, version);
                  
                  // Unsynchronized Lyrics (frames 4.8)
                  if (header.FrameId == FrameType.USLT)
                        return new UnsynchronisedLyricsFrame (data,
                              position, header, version);
                  
                  // Synchronized Lyrics (frames 4.9)
                  if (header.FrameId == FrameType.SYLT)
                        return new SynchronisedLyricsFrame (data,
                              position, header, version);
                  
                  // Comments (frames 4.10)
                  if (header.FrameId == FrameType.COMM)
                        return new CommentsFrame (data, position,
                              header, version);
                  
                  // Relative Volume Adjustment (frames 4.11)
                  if (header.FrameId == FrameType.RVA2)
                        return new RelativeVolumeFrame (data, position,
                              header, version);
                  
                  // Attached Picture (frames 4.14)
                  if (header.FrameId == FrameType.APIC)
                        return new AttachedPictureFrame (data, position,
                              header, version);
                  
                  // General Encapsulated Object (frames 4.15)
                  if(header.FrameId == FrameType.GEOB)
                        return new GeneralEncapsulatedObjectFrame (data,
                              position, header, version);
                  
                  // Play Count (frames 4.16)
                  if(header.FrameId == FrameType.PCNT)
                        return new PlayCountFrame (data, position,
                              header, version);
                  
                  // Play Count (frames 4.17)
                  if(header.FrameId == FrameType.POPM)
                        return new PopularimeterFrame (data, position,
                              header, version);
                  
                  // Terms of Use (frames 4.22)
                  if(header.FrameId == FrameType.USER)
                        return new TermsOfUseFrame (data, position,
                              header, version);
                  
                  // Private (frames 4.27)
                  if (header.FrameId == FrameType.PRIV)
                        return new PrivateFrame (data, position, header,
                              version);
                  
                  return new UnknownFrame (data, position, header,
                        version);
            }

            /// <summary>
            ///    Adds a curstom frame creator to try before using standard
            ///    frame creation methods.
            /// </summary>
            /// <param name="creator">
            ///    A <see cref="FrameCreator" /> delegate to be used by the
            ///    frame factory.
            /// </param>
            /// <remarks>
            ///    Frame creators are used before standard methods so custom
            ///    checking can be used and new formats can be added. They
            ///    are executed in the reverse order in which they are
            ///    added.
            /// </remarks>
            /// <exception cref="System.ArgumentNullException">
            ///    <paramref name="creator" /> is <see langword="null" />.
            /// </exception>
00274             public static void AddFrameCreator (FrameCreator creator)
            {
                  if (creator == null)
                        throw new System.ArgumentNullException (
                              "creator");
                  
                  frame_creators.Insert (0, creator);
            }
      }
}

Generated by  Doxygen 1.6.0   Back to index