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

StartTag.cs

//
// StartTag.cs: Provides support for accessing and modifying a collection of
// tags appearing at the start of a file.
//
// Author:
//   Brian Nickel (brian.nickel@gmail.com)
//
// Copyright (C) 2007 Brian Nickel
// 
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

using System;

namespace TagLib.NonContainer {
      /// <summary>
      ///    This class extends <see cref="CombinedTag" />, providing support
      ///    for accessing and modifying a collection of tags appearing at the
      ///    start of a file.
      /// </summary>
      /// <remarks>
      ///    <para>This class is used by <see cref="TagLib.NonContainer.File"
      ///    /> to read all the tags appearing at the start of the file but
      ///    could be used by other classes. It currently supports ID3v2
      ///    and APE tags.</para>
      /// </remarks>
00044       public class StartTag : CombinedTag
      {
            #region Private Fields
            
            /// <summary>
            ///    Contains the file to operate on.
            /// </summary>
00051             private TagLib.File file;
            
            /// <summary>
            ///    Contains the number of bytes that must be read to
            ///    hold all applicable indicators.
            /// </summary>
00057             int read_size = (int) Math.Max (TagLib.Ape.Footer.Size,
                  TagLib.Id3v2.Header.Size);
            
            #endregion
            
            
            
            #region Constructors
            
            /// <summary>
            ///    Constructs and initializes a new instance of <see
            ///    cref="StartTag" /> for a specified <see
            ///    cref="TagLib.File" />.
            /// </summary>
            /// <param name="file">
            ///    A <see cref="TagLib.File" /> object on which the new
            ///    instance will perform its operations.
            /// </param>
            /// <remarks>
            ///    Constructing a new instance does not automatically read
            ///    the contents from the disk. <see cref="Read" /> must be
            ///    called to read the tags.
            /// </remarks>
00080             public StartTag (TagLib.File file) : base ()
            {
                  this.file = file;
            }
            
            #endregion
            
            
            
            #region Public Properties
            
            /// <summary>
            ///    Gets the total size of the tags located at the end of the
            ///    file by reading from the file.
            /// </summary>
00095             public long TotalSize {
                  get {
                        long size = 0;
                        
                        while (ReadTagInfo (ref size) != TagTypes.None)
                              ;
                        
                        return size;
                  }
            }
            
            #endregion
            
            
            
            #region Public Methods
            
            /// <summary>
            ///    Reads the tags stored at the start of the file into the
            ///    current instance.
            /// </summary>
            /// <returns>
            ///    A <see cref="long" /> value indicating the seek position
            ///    in the file at which the read tags end. This also
            ///    marks the seek position at which the media begins.
            /// </returns>
00121             public long Read ()
            {
                  TagLib.Tag tag;
                  ClearTags ();
                  long end = 0;
                  
                  while ((tag = ReadTag (ref end)) != null)
                        AddTag (tag);
                  
                  return end;
            }
            
            /// <summary>
            ///    Renders the tags contained in the current instance.
            /// </summary>
            /// <returns>
            ///    A <see cref="ByteVector" /> object containing the
            ///    physical representation of the tags stored in the current
            ///    instance.
            /// </returns>
            /// <remarks>
            ///    The tags are rendered in the order that they are stored
            ///    in the current instance.
            /// </remarks>
00145             public ByteVector Render ()
            {
                  ByteVector data = new ByteVector ();
                  foreach (TagLib.Tag t in Tags) {
                        if (t is TagLib.Ape.Tag)
                              data.Add ((t as TagLib.Ape.Tag).Render ());
                        else if (t is TagLib.Id3v2.Tag)
                              data.Add ((t as TagLib.Id3v2.Tag).Render ());
                  }
                  
                  return data;
            }
            
            /// <summary>
            ///    Writes the tags contained in the current instance to the
            ///    beginning of the file that created it, overwriting the
            ///    existing tags.
            /// </summary>
            /// <returns>
            ///    A <see cref="long" /> value indicating the seek position
            ///    in the file at which the written tags end. This also
            ///    marks the seek position at which the media begins.
            /// </returns>
00168             public long Write ()
            {
                  ByteVector data = Render ();
                  file.Insert (data, 0, TotalSize);
                  return data.Count;
            }
            
            /// <summary>
            ///    Removes a set of tag types from the current instance.
            /// </summary>
            /// <param name="types">
            ///    A bitwise combined <see cref="TagLib.TagTypes" /> value
            ///    containing tag types to be removed from the file.
            /// </param>
            /// <remarks>
            ///    In order to remove all tags from a file, pass <see
            ///    cref="TagTypes.AllTags" /> as <paramref name="types" />.
            /// </remarks>
00186             public void RemoveTags (TagTypes types)
            {
                  for (int i = Tags.Length - 1; i >= 0; i--) {
                        var tag = Tags[i];
                        if (types == TagTypes.AllTags || (tag.TagTypes & types) == tag.TagTypes) {
                              RemoveTag (tag);
                        }
                  }
            }
            
            /// <summary>
            ///    Adds a tag of a specified type to the current instance,
            ///    optionally copying values from an existing type.
            /// </summary>
            /// <param name="type">
            ///    A <see cref="TagTypes" /> value specifying the type of
            ///    tag to add to the current instance. At the time of this
            ///    writing, this is limited to <see cref="TagTypes.Ape" />
            ///    and <see cref="TagTypes.Id3v2" />.
            /// </param>
            /// <param name="copy">
            ///    A <see cref="TagLib.Tag" /> to copy values from using
            ///    <see cref="TagLib.Tag.CopyTo" />, or <see
            ///    langword="null" /> if no tag is to be copied.
            /// </param>
            /// <returns>
            ///    The <see cref="TagLib.Tag" /> object added to the current
            ///    instance, or <see langword="null" /> if it couldn't be
            ///    created.
            /// </returns>
            /// <remarks>
            ///    ID3v2 tags are added at the end of the current instance,
            ///    while other tags are added to the beginning.
            /// </remarks>
00220             public TagLib.Tag AddTag (TagTypes type, TagLib.Tag copy)
            {
                  TagLib.Tag tag = null;
                  
                  if (type == TagTypes.Id3v2) {
                        tag = new TagLib.Id3v2.Tag ();
                  } else if (type == TagTypes.Ape) {
                        tag = new TagLib.Ape.Tag ();
                        (tag as Ape.Tag).HeaderPresent = true;
                  }
                  
                  if (tag != null) {
                        if (copy != null)
                              copy.CopyTo (tag, true);
                        
                        AddTag (tag);
                  }
                  
                  return tag;
            }
            
            #endregion
            
            
            
            #region Private Methods
            
            /// <summary>
            ///    Reads a tag starting at a specified position and moves the
            ///    cursor to its start position.
            /// </summary>
            /// <param name="start">
            ///    A <see cref="long" /> value reference specifying at what
            ///    position the potential tag starts. If a tag is found,
            ///    this value will be updated to the position at which the
            ///    found tag ends.
            /// </param>
            /// <returns>
            ///    A <see cref="TagLib.Tag" /> object representing the tag
            ///    found at the specified position, or <see langword="null"
            ///    /> if no tag was found.
            /// </returns>
00262             private TagLib.Tag ReadTag (ref long start)
            {
                  long end = start;
                  TagTypes type = ReadTagInfo (ref end);
                  TagLib.Tag tag = null;
                  
                  try {
                        switch (type)
                        {
                        case TagTypes.Ape:
                              tag = new TagLib.Ape.Tag (file, start);
                              break;
                        case TagTypes.Id3v2:
                              tag = new TagLib.Id3v2.Tag (file, start);
                              break;
                        }
                  } catch (CorruptFileException e) {
                Console.Error.WriteLine ("taglib-sharp caught exception creating tag: {0}", e);
                  }

                  start = end;
                  return tag;
            }
            
            /// <summary>
            ///    Looks for a tag starting at a specified position and moves
            ///    the cursor to its start position.
            /// </summary>
            /// <param name="position">
            ///    A <see cref="long" /> value reference specifying at what
            ///    position the potential tag starts. If a tag is found,
            ///    this value will be updated to the position at which the
            ///    found tag ends.
            /// </param>
            /// <returns>
            ///    A <see cref="TagLib.TagTypes" /> value specifying the
            ///    type of tag found at the specified position, or <see
            ///    cref="TagTypes.None" /> if no tag was found.
            /// </returns>
00301             private TagTypes ReadTagInfo (ref long position)
            {
                  file.Seek (position);
                  ByteVector data = file.ReadBlock (read_size);
                  
                  try {
                        if (data.StartsWith (TagLib.Ape.Footer.FileIdentifier)) {
                              TagLib.Ape.Footer footer =
                                    new TagLib.Ape.Footer (data);
                              
                              position += footer.CompleteTagSize;
                              return TagTypes.Ape;
                        }
                        
                        if (data.StartsWith (TagLib.Id3v2.Header.FileIdentifier)) {
                              TagLib.Id3v2.Header header =
                                    new TagLib.Id3v2.Header (data);
                              
                              position += header.CompleteTagSize;
                              return TagTypes.Id3v2;
                        }
                  } catch (CorruptFileException) {
                  }
                  
                  return TagTypes.None;
            }
            
            #endregion
      }
}

Generated by  Doxygen 1.6.0   Back to index