Initial commit
This commit is contained in:
commit
262601edb8
2025 files changed
+218754
No files matched your search
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
|
||||
namespace TagLib.Id3v2
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class EventTimeCode : ICloneable
|
||||
{
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public EventType TypeOfEvent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public int Time { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Constructors
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="typeOfEvent"></param>
|
||||
/// <param name="time"></param>
|
||||
public EventTimeCode (EventType typeOfEvent, int time)
|
||||
{
|
||||
TypeOfEvent = typeOfEvent;
|
||||
Time = time;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Static Methods
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static EventTimeCode CreateEmpty ()
|
||||
{
|
||||
return new EventTimeCode (EventType.Padding, 0);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ICloneable
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns><see cref="EventTimeCode" /></returns>
|
||||
public object Clone ()
|
||||
{
|
||||
return new EventTimeCode (TypeOfEvent, Time);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a0cb155fb8d1460389d700d6dcb4d686
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,134 @@
|
||||
namespace TagLib.Id3v2
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the event type used by a <see
|
||||
/// cref="EventTimeCode" /> and <see cref="EventTimeCodesFrame"/>.
|
||||
/// </summary>
|
||||
public enum EventType
|
||||
{
|
||||
/// <summary>
|
||||
/// The padding - no meaning
|
||||
/// </summary>
|
||||
Padding = 0x00,
|
||||
|
||||
/// <summary>
|
||||
/// The end of initial silence
|
||||
/// </summary>
|
||||
EndOfInitialSilence = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// The intro start
|
||||
/// </summary>
|
||||
IntroStart = 0x02,
|
||||
|
||||
/// <summary>
|
||||
/// The main part start
|
||||
/// </summary>
|
||||
MainPartStart = 0x03,
|
||||
|
||||
/// <summary>
|
||||
/// The outro start
|
||||
/// </summary>
|
||||
OutroStart = 0x04,
|
||||
|
||||
/// <summary>
|
||||
/// The outro end
|
||||
/// </summary>
|
||||
OutroEnd = 0x05,
|
||||
|
||||
/// <summary>
|
||||
/// The verse start
|
||||
/// </summary>
|
||||
VerseStart = 0x06,
|
||||
|
||||
/// <summary>
|
||||
/// The refrain start
|
||||
/// </summary>
|
||||
RefrainStart = 0x07,
|
||||
|
||||
/// <summary>
|
||||
/// The interlude start
|
||||
/// </summary>
|
||||
InterludeStart = 0x08,
|
||||
|
||||
/// <summary>
|
||||
/// The theme start
|
||||
/// </summary>
|
||||
ThemeStart = 0x09,
|
||||
|
||||
/// <summary>
|
||||
/// The variation start
|
||||
/// </summary>
|
||||
VariationStart = 0x0A,
|
||||
|
||||
/// <summary>
|
||||
/// The key change
|
||||
/// </summary>
|
||||
KeyChange = 0x0B,
|
||||
|
||||
/// <summary>
|
||||
/// The time change
|
||||
/// </summary>
|
||||
TimeChange = 0x0C,
|
||||
|
||||
/// <summary>
|
||||
/// momentary unwanted noise (Snap, Crackle, and Pop)
|
||||
/// </summary>
|
||||
MomentaryUnwantedNoise = 0x0D,
|
||||
|
||||
/// <summary>
|
||||
/// The sustained noise
|
||||
/// </summary>
|
||||
SustainedNoise = 0x0E,
|
||||
|
||||
/// <summary>
|
||||
/// The sustained noise end
|
||||
/// </summary>
|
||||
SustainedNoiseEnd = 0x0F,
|
||||
|
||||
/// <summary>
|
||||
/// The intro end
|
||||
/// </summary>
|
||||
IntroEnd = 0x10,
|
||||
|
||||
/// <summary>
|
||||
/// The main part end
|
||||
/// </summary>
|
||||
MainPartEnd = 0x11,
|
||||
|
||||
/// <summary>
|
||||
/// The verse end
|
||||
/// </summary>
|
||||
VerseEnd = 0x12,
|
||||
|
||||
/// <summary>
|
||||
/// The refrain end
|
||||
/// </summary>
|
||||
RefrainEnd = 0x13,
|
||||
|
||||
/// <summary>
|
||||
/// The theme end
|
||||
/// </summary>
|
||||
ThemeEnd = 0x14,
|
||||
|
||||
/// <summary>
|
||||
/// Profanity starts
|
||||
/// </summary>
|
||||
Profanity = 0x15,
|
||||
|
||||
/// <summary>
|
||||
/// The profanity end
|
||||
/// </summary>
|
||||
ProfanityEnd = 0x16,
|
||||
|
||||
/// <summary>
|
||||
/// The audio end
|
||||
/// </summary>
|
||||
AudioEnd = 0xFD,
|
||||
|
||||
/// <summary>
|
||||
/// The audio file end
|
||||
/// </summary>
|
||||
AudioFileEnd = 0xFE,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 62b14a01cf4dc300e958ebe67e89f8c6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,122 @@
|
||||
//
|
||||
// ExtendedHeader.cs:
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Original Source:
|
||||
// id3v2extendedheader.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 class is a filler until support for reading and writing the
|
||||
/// ID3v2 extended header is implemented.
|
||||
/// </summary>
|
||||
public class ExtendedHeader : ICloneable
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains the size of the read header.
|
||||
/// </summary>
|
||||
uint size;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ExtendedHeader"/> with no contents.
|
||||
/// </summary>
|
||||
public ExtendedHeader ()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ExtendedHeader" /> by reading the raw contents from
|
||||
/// a <see cref="ByteVector" /> object.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the raw
|
||||
/// extended header structure.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> value indicating the ID3v2 version.
|
||||
/// </param>
|
||||
public ExtendedHeader (ByteVector data, byte version)
|
||||
{
|
||||
Parse (data, version);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the data on disk in bytes.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the size of the
|
||||
/// data on disk.
|
||||
/// </value>
|
||||
public uint Size {
|
||||
get { return size; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populates the current instance with the contents of the
|
||||
/// raw ID3v2 frame.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the raw
|
||||
/// extended header structure.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> value indicating the ID3v2 version.
|
||||
/// </param>
|
||||
protected void Parse (ByteVector data, byte version)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
size = (version == 3 ? 4u : 0u) + SynchData.ToUInt (data.Mid (0, 4));
|
||||
}
|
||||
|
||||
#region ICloneable
|
||||
|
||||
/// <summary>
|
||||
/// Creates a deep copy of the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A new <see cref="ExtendedHeader" /> object identical to
|
||||
/// the current instance.
|
||||
/// </returns>
|
||||
public ExtendedHeader Clone ()
|
||||
{
|
||||
var header = new ExtendedHeader {
|
||||
size = size
|
||||
};
|
||||
return header;
|
||||
}
|
||||
|
||||
object ICloneable.Clone ()
|
||||
{
|
||||
return Clone ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b73c2cc5b276fbab79595b026897de03
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,266 @@
|
||||
//
|
||||
// Footer.cs:
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Original Source:
|
||||
// id3v2header.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 structure provides a representation of an ID3v2 tag footer
|
||||
/// which can be read from and written to disk.
|
||||
/// </summary>
|
||||
public struct Footer
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the tag's major version.
|
||||
/// </summary>
|
||||
byte major_version;
|
||||
|
||||
/// <summary>
|
||||
/// Contains tag's flags.
|
||||
/// </summary>
|
||||
HeaderFlags flags;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Fields
|
||||
|
||||
/// <summary>
|
||||
/// The size of a ID3v2 footer.
|
||||
/// </summary>
|
||||
public const uint Size = 10;
|
||||
|
||||
/// <summary>
|
||||
/// The identifier used to recognize a ID3v2 footer.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "3DI"
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector FileIdentifier = "3DI";
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Footer" /> by reading it from raw footer 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 Footer (ByteVector data)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (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];
|
||||
RevisionNumber = 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.");
|
||||
|
||||
TagSize = SynchData.ToUInt (data.Mid (6, 4));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and intializes a new instance of <see
|
||||
/// cref="Footer" /> by reading in the contents of the header
|
||||
/// object used for the same tag.
|
||||
/// </summary>
|
||||
/// <param name="header">
|
||||
/// A <see cref="Header" /> object to base the new instance
|
||||
/// off of.
|
||||
/// </param>
|
||||
public Footer (Header header)
|
||||
{
|
||||
major_version = header.MajorVersion;
|
||||
RevisionNumber = header.RevisionNumber;
|
||||
flags = header.Flags | HeaderFlags.FooterPresent;
|
||||
TagSize = header.TagSize;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the major version of the tag described by
|
||||
/// the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="byte" /> value specifying the ID3v2 version
|
||||
/// of tag described by the current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// When the version is set, unsupported header flags will
|
||||
/// automatically be removed from the tag.
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="value" /> is not 4.
|
||||
/// </exception>
|
||||
public byte MajorVersion {
|
||||
get {
|
||||
return major_version == 0 ? Tag.DefaultVersion : major_version;
|
||||
}
|
||||
set {
|
||||
if (value != 4)
|
||||
throw new ArgumentException ("Version unsupported.");
|
||||
|
||||
major_version = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the version revision number of the tag
|
||||
/// represented by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="byte" /> value containing the version
|
||||
/// revision number of the tag represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// This value should always be zeroed. A non-zero value
|
||||
/// indicates an experimental or new version of the format
|
||||
/// which may not be completely understood by the current
|
||||
/// implementation. Some software may refuse to read tags
|
||||
/// with a non-zero value.
|
||||
/// </remarks>
|
||||
public byte RevisionNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the flags applied to the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A bitwise combined <see cref="HeaderFlags" /> value
|
||||
/// containing the flags applied to the current instance.
|
||||
/// </value>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// <paramref name="value" /> contains a flag not supported
|
||||
/// by the the ID3v2 version of the current instance.
|
||||
/// </exception>
|
||||
public HeaderFlags Flags {
|
||||
get { return flags; }
|
||||
set {
|
||||
if (0 != (value & (HeaderFlags.ExtendedHeader |
|
||||
HeaderFlags.ExperimentalIndicator)) && MajorVersion < 3)
|
||||
throw new ArgumentException ("Feature only supported in version 2.3+", nameof (value));
|
||||
|
||||
if (0 != (value & HeaderFlags.FooterPresent) && MajorVersion < 3)
|
||||
throw new ArgumentException ("Feature only supported in version 2.4+", nameof (value));
|
||||
|
||||
flags = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the size of the tag described by the
|
||||
/// current instance, minus the header and footer.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the size of the
|
||||
/// tag described by the current instance.
|
||||
/// </value>
|
||||
public uint TagSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the complete size of the tag described by the
|
||||
/// current instance, including the header and footer.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the complete size
|
||||
/// of the tag described by the current instance.
|
||||
/// </value>
|
||||
public uint CompleteTagSize {
|
||||
get { return TagSize + Header.Size + Size; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ID3v2 header.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered header.
|
||||
/// </returns>
|
||||
public ByteVector Render ()
|
||||
{
|
||||
var v = new ByteVector {
|
||||
FileIdentifier,
|
||||
MajorVersion,
|
||||
RevisionNumber,
|
||||
(byte)flags,
|
||||
SynchData.FromUInt (TagSize)
|
||||
};
|
||||
return v;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bfdbe7a70ab09bb3daa3e27b704445ce
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,528 @@
|
||||
//
|
||||
// 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>
|
||||
public abstract class Frame : ICloneable
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the frame's header.
|
||||
/// </summary>
|
||||
protected FrameHeader header;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the frame's grouping ID.
|
||||
/// </summary>
|
||||
byte group_id;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the frame's encryption ID.
|
||||
/// </summary>
|
||||
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>
|
||||
protected Frame (ByteVector data, byte version)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
if (data.Count < ((version < 3) ? 3 : 4))
|
||||
throw new ArgumentException ("Data contains an incomplete identifier.",
|
||||
nameof (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>
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
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.")]
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
protected ByteVector FieldData (ByteVector frameData, int offset, byte version)
|
||||
{
|
||||
if (frameData == null)
|
||||
throw new ArgumentNullException (nameof (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 CorruptFileException ("Frame data incomplete.");
|
||||
group_id = frameData[data_offset++];
|
||||
data_length--;
|
||||
}
|
||||
|
||||
if ((Flags & FrameFlags.Encryption) != 0) {
|
||||
if (frameData.Count >= data_offset)
|
||||
throw new 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>
|
||||
public virtual Frame Clone ()
|
||||
{
|
||||
int index = 0;
|
||||
return FrameFactory.CreateFrame (Render (4), null, ref index,
|
||||
4, false);
|
||||
}
|
||||
|
||||
object ICloneable.Clone ()
|
||||
{
|
||||
return Clone ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 31daa4361de4d5095a1f4665213fe581
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,321 @@
|
||||
//
|
||||
// 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>
|
||||
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>
|
||||
static readonly 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="file">
|
||||
/// A <see cref="File"/> object containing
|
||||
/// abstraction of the file to read.
|
||||
/// Ignored if <paramref name="data"/> is not null.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// A <see cref="int" /> value reference specifying at what
|
||||
/// index in <paramref name="file" />, or in
|
||||
/// <paramref name="data" /> if not null,
|
||||
/// 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>
|
||||
public static Frame CreateFrame (ByteVector data, File file, ref int offset, byte version, bool alreadyUnsynched)
|
||||
{
|
||||
int position = 0;
|
||||
|
||||
if (data == null) {
|
||||
file.Seek (offset);
|
||||
data = file.ReadBlock ((int)FrameHeader.Size (version));
|
||||
} else {
|
||||
file = null;
|
||||
position = offset;
|
||||
}
|
||||
|
||||
// If the next data in position is 0, assume
|
||||
// that we've hit the padding portion of the
|
||||
// frame data.
|
||||
|
||||
if (data[position] == 0)
|
||||
return null;
|
||||
|
||||
FrameHeader header = new FrameHeader (data.Mid (position, (int)FrameHeader.Size (version)), version);
|
||||
|
||||
int fileposition = offset + (int)FrameHeader.Size (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 < '0' || c > '9'))
|
||||
return null;
|
||||
}
|
||||
|
||||
if (alreadyUnsynched) {
|
||||
// Mark the frame as not unsynchronized 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 necessarily 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.
|
||||
|
||||
|
||||
// Lazy objects loading handling
|
||||
|
||||
if (file != null) {
|
||||
|
||||
// Attached Picture (frames 4.14)
|
||||
// General Encapsulated Object (frames 4.15)
|
||||
if (header.FrameId == FrameType.APIC ||
|
||||
header.FrameId == FrameType.GEOB)
|
||||
return new AttachmentFrame (file.FileAbstraction, fileposition, offset - fileposition, header, version);
|
||||
|
||||
// Read remaining part of the frame for the non lazy Frames
|
||||
file.Seek (fileposition);
|
||||
data.Add (file.ReadBlock (offset - fileposition));
|
||||
}
|
||||
|
||||
|
||||
// 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);
|
||||
|
||||
// Involved People List (frames 4.4 in 2.3. in 2.4 this is a TIPL frame)
|
||||
if (header.FrameId == FrameType.IPLS)
|
||||
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)
|
||||
// General Encapsulated Object (frames 4.15)
|
||||
if (header.FrameId == FrameType.APIC ||
|
||||
header.FrameId == FrameType.GEOB)
|
||||
return new AttachmentFrame (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);
|
||||
|
||||
// User Url Link (frames 4.3.2)
|
||||
if (header.FrameId == FrameType.WXXX)
|
||||
return new UserUrlLinkFrame (data, position, header, version);
|
||||
|
||||
// Url Link (frames 4.3.1)
|
||||
if (header.FrameId[0] == (byte)'W')
|
||||
return new UrlLinkFrame (data, position, header, version);
|
||||
|
||||
// Event timing codes (frames 4.6)
|
||||
if (header.FrameId == FrameType.ETCO)
|
||||
return new EventTimeCodesFrame (data, position, header, version);
|
||||
|
||||
// Chapter (ID3v2 Chapter Frame Addendum)
|
||||
if (header.FrameId == FrameType.CHAP)
|
||||
return new ChapterFrame (data, position, header, version);
|
||||
|
||||
// Table of Contents (ID3v2 Chapter Frame Addendum)
|
||||
if (header.FrameId == FrameType.CTOC)
|
||||
return new TableOfContentsFrame (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>
|
||||
public static void AddFrameCreator (FrameCreator creator)
|
||||
{
|
||||
if (creator == null)
|
||||
throw new System.ArgumentNullException (nameof (creator));
|
||||
|
||||
frame_creators.Insert (0, creator);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f37ea4e21ef0b145e9533852fd49aaac
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,456 @@
|
||||
//
|
||||
// FrameHeader.cs:
|
||||
//
|
||||
// Authors:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
// Gabriel BUrt (gabriel.burt@gmail.com)
|
||||
//
|
||||
// Original Source:
|
||||
// id3v2frame.cpp from TagLib
|
||||
//
|
||||
// Copyright (C) 2010 Novell, Inc.
|
||||
// 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>
|
||||
/// Indicates the flags applied to a <see cref="FrameHeader" />
|
||||
/// object.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum FrameFlags : ushort
|
||||
{
|
||||
/// <summary>
|
||||
/// The header contains no flags.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the frame is to be deleted if the tag is
|
||||
/// altered.
|
||||
/// </summary>
|
||||
TagAlterPreservation = 0x4000,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the frame is to be deleted if the file is
|
||||
/// altered.
|
||||
/// </summary>
|
||||
FileAlterPreservation = 0x2000,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the frame is read-only and should not be
|
||||
/// altered.
|
||||
/// </summary>
|
||||
ReadOnly = 0x1000,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the frame has a grouping identity.
|
||||
/// </summary>
|
||||
GroupingIdentity = 0x0040,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the frame data is compressed.
|
||||
/// </summary>
|
||||
Compression = 0x0008,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the frame data is encrypted.
|
||||
/// </summary>
|
||||
Encryption = 0x0004,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the frame data has been unsynchronized.
|
||||
/// </summary>
|
||||
Unsynchronisation = 0x0002,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the frame has a data length indicator.
|
||||
/// </summary>
|
||||
DataLengthIndicator = 0x0001
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This structure provides a representation of an ID3v2 frame header
|
||||
/// which can be read from and written to disk.
|
||||
/// </summary>
|
||||
public struct FrameHeader
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains frame's ID.
|
||||
/// </summary>
|
||||
ReadOnlyByteVector frame_id;
|
||||
|
||||
/// <summary>
|
||||
/// Contains frame's flags.
|
||||
/// </summary>
|
||||
FrameFlags flags;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="FrameHeader" /> by reading it from raw header data
|
||||
/// of a specified version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the raw
|
||||
/// data to build the new instance from.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> value containing the ID3v2 version
|
||||
/// with which the data in <paramref name="data" /> was
|
||||
/// encoded.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// If the data size is smaller than the size of a full
|
||||
/// header, the data is just treated as a frame identifier
|
||||
/// and the remaining values are zeroed.
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="data" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// <paramref name="data" /> is smaller than the size of a
|
||||
/// frame identifier or <paramref name="version" /> is less
|
||||
/// than 2 or more than 4.
|
||||
/// </exception>
|
||||
public FrameHeader (ByteVector data, byte version)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
flags = 0;
|
||||
FrameSize = 0;
|
||||
|
||||
if (version < 2 || version > 4)
|
||||
throw new CorruptFileException ("Unsupported tag version.");
|
||||
|
||||
if (data.Count < (version == 2 ? 3 : 4))
|
||||
throw new CorruptFileException ("Data must contain at least a frame ID.");
|
||||
|
||||
switch (version) {
|
||||
case 2:
|
||||
// Set the frame ID -- the first three bytes
|
||||
frame_id = ConvertId (data.Mid (0, 3), version, false);
|
||||
|
||||
// If the full header information was not passed
|
||||
// in, do not continue to the steps to parse the
|
||||
// frame size and flags.
|
||||
if (data.Count < 6)
|
||||
return;
|
||||
|
||||
FrameSize = data.Mid (3, 3).ToUInt ();
|
||||
return;
|
||||
|
||||
case 3:
|
||||
// Set the frame ID -- the first four bytes
|
||||
frame_id = ConvertId (data.Mid (0, 4), version, false);
|
||||
|
||||
// If the full header information was not passed
|
||||
// in, do not continue to the steps to parse the
|
||||
// frame size and flags.
|
||||
if (data.Count < 10)
|
||||
return;
|
||||
|
||||
// Store the flags internally as version 2.4.
|
||||
FrameSize = data.Mid (4, 4).ToUInt ();
|
||||
flags = (FrameFlags)(
|
||||
((data[8] << 7) & 0x7000) |
|
||||
((data[9] >> 4) & 0x000C) |
|
||||
((data[9] << 1) & 0x0040));
|
||||
|
||||
return;
|
||||
|
||||
case 4:
|
||||
// Set the frame ID -- the first four bytes
|
||||
frame_id = new ReadOnlyByteVector (data.Mid (0, 4));
|
||||
|
||||
// If the full header information was not passed
|
||||
// in, do not continue to the steps to parse the
|
||||
// frame size and flags.
|
||||
if (data.Count < 10)
|
||||
return;
|
||||
|
||||
FrameSize = SynchData.ToUInt (data.Mid (4, 4));
|
||||
flags = (FrameFlags)data.Mid (8, 2).ToUShort ();
|
||||
|
||||
return;
|
||||
|
||||
default:
|
||||
throw new CorruptFileException ("Unsupported tag version.");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the identifier of the frame described by
|
||||
/// the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ReadOnlyByteVector" /> object containing the
|
||||
/// identifier of the frame described by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="value" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public ReadOnlyByteVector FrameId {
|
||||
get { return frame_id; }
|
||||
set {
|
||||
if (value == null)
|
||||
throw new ArgumentNullException (nameof (value));
|
||||
|
||||
frame_id = value.Count == 4 ? value : new ReadOnlyByteVector (value.Mid (0, 4));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the size of the frame described by the
|
||||
/// current instance, minus the header.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the size of the
|
||||
/// frame described by the current instance.
|
||||
/// </value>
|
||||
public uint FrameSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the flags applied to the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A bitwise combined <see cref="HeaderFlags" /> value
|
||||
/// containing the flags applied to the current instance.
|
||||
/// </value>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// <paramref name="value" /> contains a either compression
|
||||
/// or encryption, neither of which are supported by the
|
||||
/// library.
|
||||
/// </exception>
|
||||
public FrameFlags Flags {
|
||||
get { return flags; }
|
||||
set {
|
||||
if ((value & (FrameFlags.Compression | FrameFlags.Encryption)) != 0)
|
||||
throw new ArgumentException ("Encryption and compression are not supported.", nameof (value));
|
||||
|
||||
flags = value;
|
||||
}
|
||||
}
|
||||
|
||||
#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 version specified in the current instance is
|
||||
/// unsupported.
|
||||
/// </exception>
|
||||
public ByteVector Render (byte version)
|
||||
{
|
||||
ByteVector data = new ByteVector ();
|
||||
ByteVector id = ConvertId (frame_id, version, true);
|
||||
|
||||
if (id == null)
|
||||
throw new NotImplementedException ();
|
||||
|
||||
switch (version) {
|
||||
case 2:
|
||||
data.Add (id);
|
||||
data.Add (ByteVector.FromUInt (FrameSize).Mid (1, 3));
|
||||
|
||||
return data;
|
||||
|
||||
case 3:
|
||||
ushort new_flags = (ushort)(
|
||||
(((ushort)flags << 1) & 0xE000) |
|
||||
(((ushort)flags << 4) & 0x00C0) |
|
||||
(((ushort)flags >> 1) & 0x0020));
|
||||
|
||||
data.Add (id);
|
||||
data.Add (ByteVector.FromUInt (FrameSize));
|
||||
data.Add (ByteVector.FromUShort (new_flags));
|
||||
|
||||
return data;
|
||||
|
||||
case 4:
|
||||
data.Add (id);
|
||||
data.Add (SynchData.FromUInt (FrameSize));
|
||||
data.Add (ByteVector.FromUShort ((ushort)flags));
|
||||
|
||||
return data;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException ("Unsupported tag version.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of a header for a specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> value specifying the version of
|
||||
/// ID3v2 to get the size for.
|
||||
/// </param>
|
||||
public static uint Size (byte version)
|
||||
{
|
||||
return (uint)(version < 3 ? 6 : 10);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Private Methods
|
||||
|
||||
static ReadOnlyByteVector ConvertId (ByteVector id, byte version, bool toVersion)
|
||||
{
|
||||
if (version >= 4) {
|
||||
var outid = id as ReadOnlyByteVector;
|
||||
|
||||
return outid ?? new ReadOnlyByteVector (id);
|
||||
}
|
||||
|
||||
if (id == null || version < 2)
|
||||
return null;
|
||||
|
||||
if (!toVersion && (id == FrameType.EQUA ||
|
||||
id == FrameType.RVAD || id == FrameType.TRDA ||
|
||||
id == FrameType.TSIZ))
|
||||
return null;
|
||||
|
||||
if (version == 2)
|
||||
for (int i = 0; i < version2_frames.GetLength (0); i++) {
|
||||
if (!version2_frames[i, toVersion ? 1 : 0].Equals (id))
|
||||
continue;
|
||||
|
||||
return version2_frames[i, toVersion ? 0 : 1];
|
||||
}
|
||||
|
||||
if (version == 3)
|
||||
for (int i = 0; i < version3_frames.GetLength (0); i++) {
|
||||
if (!version3_frames[i, toVersion ? 1 : 0].Equals (id))
|
||||
continue;
|
||||
|
||||
return version3_frames[i, toVersion ? 0 : 1];
|
||||
}
|
||||
|
||||
if ((id.Count != 4 && version > 2) || (id.Count != 3 && version == 2))
|
||||
return null;
|
||||
|
||||
return id is ReadOnlyByteVector ? id as ReadOnlyByteVector : new ReadOnlyByteVector (id);
|
||||
}
|
||||
|
||||
static readonly ReadOnlyByteVector[,] version2_frames =
|
||||
new ReadOnlyByteVector[59, 2] {
|
||||
{ "BUF", "RBUF" },
|
||||
{ "CNT", "PCNT" },
|
||||
{ "COM", "COMM" },
|
||||
{ "CRA", "AENC" },
|
||||
{ "ETC", "ETCO" },
|
||||
{ "GEO", "GEOB" },
|
||||
{ "IPL", "TIPL" },
|
||||
{ "MCI", "MCDI" },
|
||||
{ "MLL", "MLLT" },
|
||||
{ "PIC", "APIC" },
|
||||
{ "POP", "POPM" },
|
||||
{ "REV", "RVRB" },
|
||||
{ "SLT", "SYLT" },
|
||||
{ "STC", "SYTC" },
|
||||
{ "TAL", "TALB" },
|
||||
{ "TBP", "TBPM" },
|
||||
{ "TCM", "TCOM" },
|
||||
{ "TCO", "TCON" },
|
||||
{ "TCP", "TCMP" },
|
||||
{ "TCR", "TCOP" },
|
||||
{ "TDA", "TDAT" },
|
||||
{ "TIM", "TIME" },
|
||||
{ "TDY", "TDLY" },
|
||||
{ "TEN", "TENC" },
|
||||
{ "TFT", "TFLT" },
|
||||
{ "TKE", "TKEY" },
|
||||
{ "TLA", "TLAN" },
|
||||
{ "TLE", "TLEN" },
|
||||
{ "TMT", "TMED" },
|
||||
{ "TOA", "TOAL" },
|
||||
{ "TOF", "TOFN" },
|
||||
{ "TOL", "TOLY" },
|
||||
{ "TOR", "TDOR" },
|
||||
{ "TOT", "TOAL" },
|
||||
{ "TP1", "TPE1" },
|
||||
{ "TP2", "TPE2" },
|
||||
{ "TP3", "TPE3" },
|
||||
{ "TP4", "TPE4" },
|
||||
{ "TPA", "TPOS" },
|
||||
{ "TPB", "TPUB" },
|
||||
{ "TRC", "TSRC" },
|
||||
{ "TRK", "TRCK" },
|
||||
{ "TSS", "TSSE" },
|
||||
{ "TT1", "TIT1" },
|
||||
{ "TT2", "TIT2" },
|
||||
{ "TT3", "TIT3" },
|
||||
{ "TXT", "TOLY" },
|
||||
{ "TXX", "TXXX" },
|
||||
{ "TYE", "TDRC" },
|
||||
{ "UFI", "UFID" },
|
||||
{ "ULT", "USLT" },
|
||||
{ "WAF", "WOAF" },
|
||||
{ "WAR", "WOAR" },
|
||||
{ "WAS", "WOAS" },
|
||||
{ "WCM", "WCOM" },
|
||||
{ "WCP", "WCOP" },
|
||||
{ "WPB", "WPUB" },
|
||||
{ "WXX", "WXXX" },
|
||||
{ "XRV", "RVA2" }
|
||||
};
|
||||
|
||||
static readonly ReadOnlyByteVector[,] version3_frames =
|
||||
new ReadOnlyByteVector[3, 2] {
|
||||
{ "TORY", "TDOR" },
|
||||
{ "TYER", "TDRC" },
|
||||
{ "XRVA", "RVA2" }
|
||||
|
||||
};
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aa1e0a3b834984f3a8d7f5302dd1dcd9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,105 @@
|
||||
//
|
||||
// FrameTypes.cs:
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 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
|
||||
//
|
||||
|
||||
namespace TagLib.Id3v2
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="FrameType" /> provides references to different frame
|
||||
/// types used by the library.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>This class is used to severely reduce the number of times
|
||||
/// these types are created in <see cref="TagLib.Id3v2.Tag" />,
|
||||
/// greatly improving the speed at which warm files are read. It is,
|
||||
/// however, not necessary for external users to use this class. While
|
||||
/// the library may use <c>GetTextAsString (FrameType.TIT2);</c> an
|
||||
/// external user could use <c>tag.GetTextAsString ("TIT2");</c> with
|
||||
/// the same result.</para>
|
||||
/// </remarks>
|
||||
static class FrameType
|
||||
{
|
||||
public static readonly ReadOnlyByteVector APIC = "APIC";
|
||||
public static readonly ReadOnlyByteVector COMM = "COMM";
|
||||
public static readonly ReadOnlyByteVector CHAP = "CHAP"; // Chapter Frame
|
||||
public static readonly ReadOnlyByteVector CTOC = "CTOC"; // Table of Contents Frame
|
||||
public static readonly ReadOnlyByteVector EQUA = "EQUA";
|
||||
public static readonly ReadOnlyByteVector GEOB = "GEOB";
|
||||
public static readonly ReadOnlyByteVector IPLS = "IPLS";
|
||||
public static readonly ReadOnlyByteVector MCDI = "MCDI";
|
||||
public static readonly ReadOnlyByteVector PCNT = "PCNT";
|
||||
public static readonly ReadOnlyByteVector POPM = "POPM";
|
||||
public static readonly ReadOnlyByteVector PRIV = "PRIV";
|
||||
public static readonly ReadOnlyByteVector RVA2 = "RVA2";
|
||||
public static readonly ReadOnlyByteVector RVAD = "RVAD";
|
||||
public static readonly ReadOnlyByteVector SYLT = "SYLT";
|
||||
public static readonly ReadOnlyByteVector TALB = "TALB";
|
||||
public static readonly ReadOnlyByteVector TBPM = "TBPM";
|
||||
public static readonly ReadOnlyByteVector TCOM = "TCOM";
|
||||
public static readonly ReadOnlyByteVector TCON = "TCON";
|
||||
public static readonly ReadOnlyByteVector TCOP = "TCOP";
|
||||
public static readonly ReadOnlyByteVector TCMP = "TCMP";
|
||||
public static readonly ReadOnlyByteVector TDRC = "TDRC";
|
||||
public static readonly ReadOnlyByteVector TDAT = "TDAT";
|
||||
public static readonly ReadOnlyByteVector TDTG = "TDTG";
|
||||
public static readonly ReadOnlyByteVector TEXT = "TEXT";
|
||||
public static readonly ReadOnlyByteVector TIT1 = "TIT1";
|
||||
public static readonly ReadOnlyByteVector TIT2 = "TIT2";
|
||||
public static readonly ReadOnlyByteVector TIT3 = "TIT3";
|
||||
public static readonly ReadOnlyByteVector TIME = "TIME";
|
||||
public static readonly ReadOnlyByteVector TKEY = "TKEY";
|
||||
public static readonly ReadOnlyByteVector TLEN = "TLEN"; // audio length
|
||||
public static readonly ReadOnlyByteVector TMCL = "TMCL";
|
||||
public static readonly ReadOnlyByteVector TOLY = "TOLY";
|
||||
public static readonly ReadOnlyByteVector TOPE = "TOPE";
|
||||
public static readonly ReadOnlyByteVector TPE1 = "TPE1";
|
||||
public static readonly ReadOnlyByteVector TPE2 = "TPE2";
|
||||
public static readonly ReadOnlyByteVector TPE3 = "TPE3";
|
||||
public static readonly ReadOnlyByteVector TPE4 = "TPE4";
|
||||
public static readonly ReadOnlyByteVector TPOS = "TPOS";
|
||||
public static readonly ReadOnlyByteVector TPUB = "TPUB";
|
||||
public static readonly ReadOnlyByteVector TRCK = "TRCK";
|
||||
public static readonly ReadOnlyByteVector TRDA = "TRDA";
|
||||
public static readonly ReadOnlyByteVector TSIZ = "TSIZ";
|
||||
public static readonly ReadOnlyByteVector TSOA = "TSOA"; // Album Title Sort Frame
|
||||
public static readonly ReadOnlyByteVector TSO2 = "TSO2"; // Album Artist Sort Frame
|
||||
public static readonly ReadOnlyByteVector TSOC = "TSOC"; // Composer Sort Frame
|
||||
public static readonly ReadOnlyByteVector TSOP = "TSOP"; // Performer Sort Frame
|
||||
public static readonly ReadOnlyByteVector TSOT = "TSOT"; // Track Title Sort Frame
|
||||
public static readonly ReadOnlyByteVector TSRC = "TSRC";
|
||||
public static readonly ReadOnlyByteVector TXXX = "TXXX";
|
||||
public static readonly ReadOnlyByteVector TYER = "TYER";
|
||||
public static readonly ReadOnlyByteVector UFID = "UFID";
|
||||
public static readonly ReadOnlyByteVector USER = "USER";
|
||||
public static readonly ReadOnlyByteVector USLT = "USLT";
|
||||
public static readonly ReadOnlyByteVector WCOM = "WCOM";
|
||||
public static readonly ReadOnlyByteVector WCOP = "WCOP";
|
||||
public static readonly ReadOnlyByteVector WOAF = "WOAF";
|
||||
public static readonly ReadOnlyByteVector WOAR = "WOAR";
|
||||
public static readonly ReadOnlyByteVector WOAS = "WOAS";
|
||||
public static readonly ReadOnlyByteVector WORS = "WORS";
|
||||
public static readonly ReadOnlyByteVector WPAY = "WPAY";
|
||||
public static readonly ReadOnlyByteVector WPUB = "WPUB";
|
||||
public static readonly ReadOnlyByteVector WXXX = "WXXX";
|
||||
public static readonly ReadOnlyByteVector ETCO = "ETCO";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7bbd99690e21ca8deb1a85b6c4a571bb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 07214d9262aa642598a390aa7518fdf5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e4f5116d038c161b7a7795252019f21f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,278 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TagLib.Id3v2
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Frame" /> to provide support for
|
||||
/// Chapter Frames, i.e. "<c>CHAP</c>", (ID3v2 Chapter Frame Addendum 1.0,
|
||||
/// https://id3.org/id3v2-chapters-1.0).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The Chapter Frame is special in that it can hold an arbitrary amount
|
||||
/// of sub-frames, which are made available here in the SubFrames list.
|
||||
///
|
||||
/// Each Chapter Frame must have an identifying string that is unique across
|
||||
/// all <see cref="ChapterFrame"/>s and <see cref="TableOfContentsFrame"/>s
|
||||
/// in the tag. This is the property <see cref="Id"/>. It is not intended
|
||||
/// for humans consumption and players will not display it. A chapter can
|
||||
/// be titled by adding a "<c>TIT2</c>" <see cref="TextInformationFrame"/>.
|
||||
///
|
||||
/// There are two ways the Chapter Frame can state a chapter’s beginning
|
||||
/// and end: by milliseconds or by byte offset, accessible here as
|
||||
/// StartMilliseconds/EndMilliseconds and StartByteOffset/EndByteOffset
|
||||
/// respectively. The byte offsets are the zero-based byte positions of
|
||||
/// the first audio frame in the chapter or the first audio frame folliwing
|
||||
/// the chapter, counted from the beginning of the file. The byte offsets
|
||||
/// are to be ignored according to the spec if they are FF FF FF FF. This
|
||||
/// class does not synchronize the two ways in any way, so make sure to set
|
||||
/// both appropriately. The byte offsets are however initialized to be
|
||||
/// ignored, so with blank frames, you can focus on the milliseconds.
|
||||
///
|
||||
/// According to the spec, chapters may overlap and have gaps.
|
||||
/// </remarks>
|
||||
public class ChapterFrame : Frame
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new empty instance of <see
|
||||
/// cref="ChapterFrame" />.
|
||||
/// </summary>
|
||||
public ChapterFrame ()
|
||||
: base(FrameType.CHAP, 4)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new empty instance of <see
|
||||
/// cref="ChapterFrame" /> with the given chapter ID.
|
||||
/// </summary>
|
||||
public ChapterFrame (string id)
|
||||
: this()
|
||||
{
|
||||
Id = id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see cref="ChapterFrame" />
|
||||
/// with the given chapter ID and adds a <see cref="TextInformationFrame"/>
|
||||
/// "<c>TIT2</c>" with the given title.
|
||||
/// </summary>
|
||||
public ChapterFrame (string id, string title)
|
||||
: this(id)
|
||||
{
|
||||
SubFrames.Add(new TextInformationFrame("TIT2") { Text = new[] { title } });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ChapterFrame" /> by reading its raw data in a
|
||||
/// specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object starting with the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
public ChapterFrame (ByteVector data, byte version)
|
||||
: base (data, version)
|
||||
{
|
||||
SetData (data, 0, version, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ChapterFrame" /> by reading its raw data in a
|
||||
/// specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// A <see cref="int" /> indicating at what offset in
|
||||
/// <paramref name="data" /> the frame actually begins.
|
||||
/// </param>
|
||||
/// <param name="header">
|
||||
/// A <see cref="FrameHeader" /> containing the header of the
|
||||
/// frame found at <paramref name="offset" /> in the data.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
protected internal ChapterFrame (ByteVector data, int offset, FrameHeader header, byte version)
|
||||
: base (header)
|
||||
{
|
||||
SetData (data, offset, version, false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the internal chapter id. This should be
|
||||
/// <see cref="StringType.Latin1" /> .
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the start time of the chapter in milliseconds.
|
||||
/// </summary>
|
||||
public uint StartMilliseconds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the end time of the chapter in milliseconds.
|
||||
/// </summary>
|
||||
public uint EndMilliseconds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the chapter’s first audio frame’s byte position
|
||||
/// from the beginning of the file.
|
||||
/// The spec makes this ignorable if it is FF FF FF FF, which is
|
||||
/// the initial value.
|
||||
/// </summary>
|
||||
public uint StartByteOffset { get; set; } = 0xFFFFFFFF;
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the byte position of the first audio frame following
|
||||
/// the chapter from the beginning of the file.
|
||||
/// The spec makes this ignorable if it is FF FF FF FF, which is
|
||||
/// the initial value.
|
||||
/// </summary>
|
||||
public uint EndByteOffset { get; set; } = 0xFFFFFFFF;
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the descriptive sub-fields for this chapter. It
|
||||
/// is recommended by the spec to have at least a "<c>TIT2</c>"
|
||||
/// <see cref="TextInformationFrame"/> with the chapter title, but
|
||||
/// it can contain anything. Particularly, players like to display
|
||||
/// per-chapter "<c>APIC</c>" <see cref="AttachmentFrame"/>s and
|
||||
/// <see cref="UrlLinkFrame"/>s.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A List of arbitrary <see cref="Frame" />s.
|
||||
/// </value>
|
||||
public List<Frame> SubFrames { get; set; } = new List<Frame>();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <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 override void ParseFields (ByteVector data, byte version)
|
||||
{
|
||||
// https://id3.org/id3v2-chapters-1.0
|
||||
|
||||
int idLength = data.IndexOf((byte)0) + 1;
|
||||
|
||||
Id = data.ToString(StringType.Latin1, 0, idLength - 1); //Always Latin1, at least there is no mention of encoding in the spec
|
||||
StartMilliseconds = data.Mid(idLength, 4).ToUInt();
|
||||
EndMilliseconds = data.Mid(idLength + 4, 4).ToUInt();
|
||||
StartByteOffset = data.Mid(idLength + 8, 4).ToUInt(); //I don’t really know why one would use the offsets.
|
||||
EndByteOffset = data.Mid(idLength + 12, 4).ToUInt(); //They are to be ignored if all 4 Bytes are FF, i.e. 4,294,967,295.
|
||||
|
||||
SubFrames = new List<Frame>();
|
||||
int frame_data_position = idLength + 16;
|
||||
int frame_data_endposition = data.Count;
|
||||
while (frame_data_position < frame_data_endposition)
|
||||
{
|
||||
Frame frame;
|
||||
try
|
||||
{
|
||||
frame = FrameFactory.CreateFrame(data, null, ref frame_data_position, version, true /* ? */);
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
catch (CorruptFileException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
if (frame == null)
|
||||
break;
|
||||
|
||||
// Only add frames that contain data.
|
||||
if (frame.Size == 0)
|
||||
continue;
|
||||
|
||||
SubFrames.Add(frame);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 override ByteVector RenderFields (byte version)
|
||||
{
|
||||
var data = ByteVector.FromString(Id, StringType.Latin1);
|
||||
data.Add((byte)0); //it would be neat if Add were chainable…
|
||||
data.Add(ByteVector.FromUInt(StartMilliseconds));
|
||||
data.Add(ByteVector.FromUInt(EndMilliseconds));
|
||||
data.Add(ByteVector.FromUInt(StartByteOffset));
|
||||
data.Add(ByteVector.FromUInt(EndByteOffset));
|
||||
|
||||
foreach (var f in SubFrames)
|
||||
data.Add(f.Render(version));
|
||||
|
||||
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>
|
||||
public override Frame Clone()
|
||||
{
|
||||
var frame = new ChapterFrame(Id);
|
||||
frame.StartMilliseconds = StartMilliseconds;
|
||||
frame.EndMilliseconds = EndMilliseconds;
|
||||
frame.StartByteOffset = StartByteOffset;
|
||||
frame.EndByteOffset = EndByteOffset;
|
||||
|
||||
foreach(var f in SubFrames)
|
||||
frame.SubFrames.Add(f.Clone());
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 64b489dad86370215ab9e7b894ca4560
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,522 @@
|
||||
//
|
||||
// CommentsFrame.cs:
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Original Source:
|
||||
// id3v2commentsframe.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
|
||||
//
|
||||
|
||||
namespace TagLib.Id3v2
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Frame" />, implementing support for
|
||||
/// ID3v2 Comments (COMM) Frames.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>A <see cref="CommentsFrame" /> should be used for storing
|
||||
/// user readable comments on the media file.</para>
|
||||
/// <para>When reading comments from a file, <see cref="GetPreferred"
|
||||
/// /> should be used as it gracefully falls back to comments that
|
||||
/// you, as a developer, may not be expecting. When writing comments,
|
||||
/// however, it is best to use <see cref="Get" /> as it forces it to
|
||||
/// be written in the exact version you are expecting.</para>
|
||||
/// </remarks>
|
||||
public class CommentsFrame : Frame
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the text encoding to use when rendering the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
|
||||
/// <summary>
|
||||
/// Contains the ISO-639-2 language code of the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
string language;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the description of the current instance.
|
||||
/// </summary>
|
||||
string description;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the comment text of the current instance.
|
||||
/// </summary>
|
||||
string text;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="CommentsFrame" /> with a specified description,
|
||||
/// ISO-639-2 language code, and text encoding.
|
||||
/// </summary>
|
||||
/// <param name="description">
|
||||
/// A <see cref="string" /> containing the description of the
|
||||
/// new frame.
|
||||
/// </param>
|
||||
/// <param name="language">
|
||||
/// A <see cref="string" /> containing the ISO-639-2 language
|
||||
/// code of the new frame.
|
||||
/// </param>
|
||||
/// <param name="encoding">
|
||||
/// A <see cref="StringType" /> containing the text encoding
|
||||
/// to use when rendering the new frame.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// When a frame is created, it is not automatically added to
|
||||
/// the tag. Consider using <see cref="Get" /> for more
|
||||
/// integrated frame creation.
|
||||
/// </remarks>
|
||||
public CommentsFrame (string description, string language, StringType encoding)
|
||||
: base (FrameType.COMM, 4)
|
||||
{
|
||||
TextEncoding = encoding;
|
||||
this.language = language;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="CommentsFrame" /> with a specified description and
|
||||
/// ISO-639-2 language code.
|
||||
/// </summary>
|
||||
/// <param name="description">
|
||||
/// A <see cref="string" /> containing the description of the
|
||||
/// new frame.
|
||||
/// </param>
|
||||
/// <param name="language">
|
||||
/// A <see cref="string" /> containing the ISO-639-2 language
|
||||
/// code of the new frame.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// When a frame is created, it is not automatically added to
|
||||
/// the tag. Consider using <see cref="Get" /> for more
|
||||
/// integrated frame creation.
|
||||
/// </remarks>
|
||||
public CommentsFrame (string description, string language)
|
||||
: this (description, language, Tag.DefaultEncoding)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="CommentsFrame" /> with a specified description.
|
||||
/// </summary>
|
||||
/// <param name="description">
|
||||
/// A <see cref="string" /> containing the description of the
|
||||
/// new frame.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// When a frame is created, it is not automatically added to
|
||||
/// the tag. Consider using <see cref="Get" /> for more
|
||||
/// integrated frame creation.
|
||||
/// </remarks>
|
||||
public CommentsFrame (string description)
|
||||
: this (description, null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="CommentsFrame" /> by reading its raw data in a
|
||||
/// specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object starting with the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
public CommentsFrame (ByteVector data, byte version)
|
||||
: base (data, version)
|
||||
{
|
||||
SetData (data, 0, version, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="CommentsFrame" /> by reading its raw data in a
|
||||
/// specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// A <see cref="int" /> indicating at what offset in
|
||||
/// <paramref name="data" /> the frame actually begins.
|
||||
/// </param>
|
||||
/// <param name="header">
|
||||
/// A <see cref="FrameHeader" /> containing the header of the
|
||||
/// frame found at <paramref name="offset" /> in the data.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
protected internal CommentsFrame (ByteVector data, int offset, FrameHeader header, byte version)
|
||||
: base (header)
|
||||
{
|
||||
SetData (data, offset, version, false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the text encoding to use when storing the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> containing the text encoding to
|
||||
/// use when storing the current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// This encoding is overridden when rendering if <see
|
||||
/// cref="Tag.ForceDefaultEncoding" /> is <see
|
||||
/// langword="true" /> or the render version does not support
|
||||
/// it.
|
||||
/// </remarks>
|
||||
public StringType TextEncoding { get; set; } = Tag.DefaultEncoding;
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the ISO-639-2 language code stored in the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> containing the ISO-639-2 language
|
||||
/// code stored in the current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// There should only be one file with a matching description
|
||||
/// and ISO-639-2 language code per tag.
|
||||
/// </remarks>
|
||||
public string Language {
|
||||
get {
|
||||
if (language != null && language.Length > 2)
|
||||
return language.Substring (0, 3);
|
||||
|
||||
return "XXX";
|
||||
}
|
||||
set { language = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the description stored in the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> containing the description
|
||||
/// stored in the current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// There should only be one frame with a matching
|
||||
/// description and ISO-639-2 language code per tag.
|
||||
/// </remarks>
|
||||
public string Description {
|
||||
get {
|
||||
if (description != null)
|
||||
return description;
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
set { description = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the comment text stored in the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> containing the comment text
|
||||
/// stored in the current instance.
|
||||
/// </value>
|
||||
public string Text {
|
||||
get {
|
||||
if (text != null)
|
||||
return text;
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
set { text = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string representation of the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="string" /> containing the comment text.
|
||||
/// </returns>
|
||||
public override string ToString ()
|
||||
{
|
||||
return Text;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Static Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a specified comments frame from the specified tag,
|
||||
/// optionally creating it if it does not exist.
|
||||
/// </summary>
|
||||
/// <param name="tag">
|
||||
/// A <see cref="Tag" /> object to search in.
|
||||
/// </param>
|
||||
/// <param name="description">
|
||||
/// A <see cref="string" /> specifying the description to
|
||||
/// match.
|
||||
/// </param>
|
||||
/// <param name="language">
|
||||
/// A <see cref="string" /> specifying the ISO-639-2 language
|
||||
/// code to match.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> specifying whether or not to create
|
||||
/// and add a new frame to the tag if a match is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="CommentsFrame" /> object containing the
|
||||
/// matching frame, or <see langword="null" /> if a match
|
||||
/// wasn't found and <paramref name="create" /> is <see
|
||||
/// langword="false" />.
|
||||
/// </returns>
|
||||
public static CommentsFrame Get (Tag tag, string description, string language, bool create)
|
||||
{
|
||||
CommentsFrame comm;
|
||||
foreach (Frame frame in tag.GetFrames (FrameType.COMM)) {
|
||||
comm = frame as CommentsFrame;
|
||||
|
||||
if (comm == null)
|
||||
continue;
|
||||
|
||||
if (comm.Description != description)
|
||||
continue;
|
||||
|
||||
if (language != null && language != comm.Language)
|
||||
continue;
|
||||
|
||||
return comm;
|
||||
}
|
||||
|
||||
if (!create)
|
||||
return null;
|
||||
|
||||
comm = new CommentsFrame (description, language);
|
||||
tag.AddFrame (comm);
|
||||
return comm;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a specified comments frame from the specified tag,
|
||||
/// trying to to match the description and language but
|
||||
/// accepting an incomplete match.
|
||||
/// </summary>
|
||||
/// <param name="tag">
|
||||
/// A <see cref="Tag" /> object to search in.
|
||||
/// </param>
|
||||
/// <param name="description">
|
||||
/// A <see cref="string" /> specifying the description to
|
||||
/// match.
|
||||
/// </param>
|
||||
/// <param name="language">
|
||||
/// A <see cref="string" /> specifying the ISO-639-2 language
|
||||
/// code to match.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="CommentsFrame" /> object containing the
|
||||
/// matching frame, or <see langword="null" /> if a match
|
||||
/// wasn't found.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// <para>The method tries matching with the following order
|
||||
/// of precidence:</para>
|
||||
/// <list type="number">
|
||||
/// <item><term>The first frame with a matching
|
||||
/// description and language.</term></item>
|
||||
/// <item><term>The first frame with a matching
|
||||
/// language.</term></item>
|
||||
/// <item><term>The first frame with a matching
|
||||
/// description.</term></item>
|
||||
/// <item><term>The first frame.</term></item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
public static CommentsFrame GetPreferred (Tag tag, string description, string language)
|
||||
{
|
||||
// This is weird, so bear with me. The best thing we can
|
||||
// have is something straightforward and in our own
|
||||
// language. If it has a description, then it is
|
||||
// probably used for something other than an actual
|
||||
// comment. If that doesn't work, we'd still rather have
|
||||
// something in our language than something in another.
|
||||
// After that all we have left are things in other
|
||||
// languages, so we'd rather have one with actual
|
||||
// content, so we try to get one with no description
|
||||
// first.
|
||||
|
||||
bool skip_itunes = description == null || !description.StartsWith ("iTun");
|
||||
|
||||
int best_value = -1;
|
||||
CommentsFrame best_frame = null;
|
||||
|
||||
foreach (Frame frame in tag.GetFrames (FrameType.COMM)) {
|
||||
if (!(frame is CommentsFrame comm))
|
||||
continue;
|
||||
|
||||
if (skip_itunes &&
|
||||
comm.Description.StartsWith ("iTun"))
|
||||
continue;
|
||||
|
||||
bool same_name = comm.Description == description;
|
||||
bool same_lang = comm.Language == language;
|
||||
|
||||
if (same_name && same_lang)
|
||||
return comm;
|
||||
|
||||
int value = same_lang ? 2 : same_name ? 1 : 0;
|
||||
|
||||
if (value <= best_value)
|
||||
continue;
|
||||
|
||||
best_value = value;
|
||||
best_frame = comm;
|
||||
}
|
||||
|
||||
return best_frame;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <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 override void ParseFields (ByteVector data, byte version)
|
||||
{
|
||||
if (data.Count < 4)
|
||||
throw new CorruptFileException ("Not enough bytes in field.");
|
||||
|
||||
TextEncoding = (StringType)data[0];
|
||||
language = data.ToString (StringType.Latin1, 1, 3);
|
||||
|
||||
// Instead of splitting into two string, in the format
|
||||
// [{desc}\0{value}], try splitting into three strings
|
||||
// in case of a misformatted [{desc}\0{value}\0].
|
||||
string[] split = data.ToStrings (TextEncoding, 4, 3);
|
||||
|
||||
if (split.Length == 0) {
|
||||
// No data in the frame.
|
||||
description = string.Empty;
|
||||
text = string.Empty;
|
||||
} else if (split.Length == 1) {
|
||||
// Bad comment frame. Assume that it lacks a
|
||||
// description.
|
||||
description = string.Empty;
|
||||
text = split[0];
|
||||
} else {
|
||||
description = split[0];
|
||||
text = split[1];
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 override ByteVector RenderFields (byte version)
|
||||
{
|
||||
StringType encoding = CorrectEncoding (TextEncoding, version);
|
||||
var v = new ByteVector {
|
||||
(byte)encoding,
|
||||
ByteVector.FromString (Language, StringType.Latin1),
|
||||
ByteVector.FromString (description, encoding),
|
||||
ByteVector.TextDelimiter (encoding),
|
||||
ByteVector.FromString (text, encoding)
|
||||
};
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
#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>
|
||||
public override Frame Clone ()
|
||||
{
|
||||
var frame = new CommentsFrame (description, language, TextEncoding) {
|
||||
text = text
|
||||
};
|
||||
return frame;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eb519f96255f162488dedbd3218382e9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,344 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TagLib.Id3v2
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Frame" />, implementing support for
|
||||
/// ID3v2 Event Time Codes (ETCO) Frames.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Event time codes Frames should contain a list of events occurring
|
||||
/// throughout the track such as the start of the main part and the end of it.
|
||||
/// To see all available event types see <see cref="EventType"/>.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <para>Reading the Event Time Codes from a tag.</para>
|
||||
/// <code lang="C#">
|
||||
/// using TagLib;
|
||||
/// using TagLib.Id3v2;
|
||||
///
|
||||
/// public static class LookupUtil
|
||||
/// {
|
||||
/// public static ByteVector GetTrackEvents(string filename)
|
||||
/// {
|
||||
/// File file = File.Create (filename, ReadStyle.None);
|
||||
/// Id3v2.Tag tag = file.GetTag (TagTypes.Id3v2, false) as Id3v2.Tag;
|
||||
/// if (tag == null)
|
||||
/// return new ByteVector ();
|
||||
///
|
||||
/// EventTimeCodesFrame frame = EventTimeCodesFrame.Get (tag, false);
|
||||
/// if (frame == null)
|
||||
/// return new ByteVector ();
|
||||
///
|
||||
/// return frame.Data;
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// <code lang="C++">
|
||||
/// #using <System.dll>
|
||||
/// #using <taglib-sharp.dll>
|
||||
///
|
||||
/// using System;
|
||||
/// using TagLib;
|
||||
/// using TagLib::Id3v2;
|
||||
///
|
||||
/// public ref class LookupUtil abstract sealed
|
||||
/// {
|
||||
/// public:
|
||||
/// static ByteVector^ GetTrackEvents (String^ filename)
|
||||
/// {
|
||||
/// File^ file = File::Create (filename, ReadStyle::None);
|
||||
/// Id3v2::Tag^ tag = dynamic_cast<Id3v2::Tag^> (file.GetTag (TagTypes::Id3v2, false));
|
||||
/// if (tag == null)
|
||||
/// return gcnew ByteVector;
|
||||
///
|
||||
/// EventTimeCodesFrame^ frame = EventTimeCodesFrame::Get (tag, false);
|
||||
/// if (frame == null)
|
||||
/// return gcnew ByteVector;
|
||||
///
|
||||
/// return frame->Data;
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// <code lang="VB">
|
||||
/// Imports TagLib
|
||||
/// Imports TagLib.Id3v2
|
||||
///
|
||||
/// Public Shared Class LookupUtil
|
||||
/// Public Shared Sub GetTrackEvents (filename As String) As TagLib.ByteVector
|
||||
/// Dim file As File = File.Create (filename, ReadStyle.None)
|
||||
/// Dim tag As Id3v2.Tag = file.GetTag (TagTypes.Id3v2, False)
|
||||
/// If tag Is Nothing Return New ByteVector ()
|
||||
///
|
||||
/// Dim frame As EventTimeCodesFrame = EventTimeCodesFrame.Get (tag, False)
|
||||
/// If frame Is Nothing Return New ByteVector ()
|
||||
///
|
||||
/// Return frame.Data
|
||||
/// End Sub
|
||||
/// End Class
|
||||
/// </code>
|
||||
/// <code lang="Boo">
|
||||
/// import TagLib
|
||||
/// import TagLib.Id3v2
|
||||
///
|
||||
/// public static class LookupUtil:
|
||||
/// static def GetTrackEvents (filename as string) as TagLib.ByteVector:
|
||||
/// file as File = File.Create (filename, ReadStyle.None)
|
||||
/// tag as Id3v2.Tag = file.GetTag (TagTypes.Id3v2, false)
|
||||
/// if tag == null:
|
||||
/// return ByteVector ()
|
||||
///
|
||||
/// frame as EventTimeCodesFrame = EventTimeCodesFrame.Get (tag, false)
|
||||
/// if frame == null:
|
||||
/// return ByteVector ()
|
||||
///
|
||||
/// return frame.Data
|
||||
/// </code>
|
||||
/// </example>
|
||||
public class EventTimeCodesFrame : Frame
|
||||
{
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="EventTimeCodesFrame" /> with empty
|
||||
/// identifier data.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When a frame is created, it is not automatically added to
|
||||
/// the tag. Consider using <see cref="Get" /> for more
|
||||
/// integrated frame creation.
|
||||
/// </remarks>
|
||||
public EventTimeCodesFrame ()
|
||||
: base (FrameType.ETCO, 4)
|
||||
{
|
||||
Flags = FrameFlags.FileAlterPreservation;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="EventTimeCodesFrame" /> by reading its raw data
|
||||
/// in a specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="timestampFormat">
|
||||
/// A <see cref="TimestampFormat" /> Specifies the time unit to use in this frame.
|
||||
/// </param>
|
||||
public EventTimeCodesFrame (TimestampFormat timestampFormat)
|
||||
: base (FrameType.ETCO, 4)
|
||||
{
|
||||
TimestampFormat = timestampFormat;
|
||||
Flags = FrameFlags.FileAlterPreservation;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="EventTimeCodesFrame" /> by reading its raw data
|
||||
/// in a specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object starting with the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
public EventTimeCodesFrame (ByteVector data, byte version)
|
||||
: base (data, version)
|
||||
{
|
||||
SetData (data, 0, version, true);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="EventTimeCodesFrame" /> by reading its raw data
|
||||
/// in a specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="frameHeader">
|
||||
/// A <see cref="FrameHeader" /> containing the header of the frame
|
||||
/// </param>
|
||||
public EventTimeCodesFrame (FrameHeader frameHeader)
|
||||
: base (frameHeader)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="EventTimeCodesFrame" /> by reading its raw data
|
||||
/// in a specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// A <see cref="int" /> indicating at what offset in
|
||||
/// <paramref name="data" /> the frame actually begins.
|
||||
/// </param>
|
||||
/// <param name="header">
|
||||
/// A <see cref="FrameHeader" /> containing the header of the
|
||||
/// frame found at <paramref name="offset" /> in the data.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
public EventTimeCodesFrame (ByteVector data, int offset, FrameHeader header, byte version)
|
||||
: base (header)
|
||||
{
|
||||
SetData (data, offset, version, false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the timestamp format for this frame instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TimestampFormat"/> that will be used in this frame instance.
|
||||
/// </value>
|
||||
public TimestampFormat TimestampFormat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the events this frame contains.
|
||||
/// Each <see cref="EventTimeCode"/> represents a single event at a certain point in time.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="List{EventTimeCode}"/> that are stored in this frame instance.
|
||||
/// </value>
|
||||
public List<EventTimeCode> Events { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Static Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a play count frame from a specified tag, optionally
|
||||
/// creating it if it does not exist.
|
||||
/// </summary>
|
||||
/// <param name="tag">
|
||||
/// A <see cref="Tag" /> object to search in.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> specifying whether or not to create
|
||||
/// and add a new frame to the tag if a match is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="EventTimeCodesFrame" /> object containing the
|
||||
/// matching frame, or <see langword="null" /> if a match
|
||||
/// wasn't found and <paramref name="create" /> is <see
|
||||
/// langword="false" />.
|
||||
/// </returns>
|
||||
public static EventTimeCodesFrame Get (Tag tag, bool create)
|
||||
{
|
||||
EventTimeCodesFrame etco;
|
||||
foreach (Frame frame in tag) {
|
||||
etco = frame as EventTimeCodesFrame;
|
||||
|
||||
if (etco != null)
|
||||
return etco;
|
||||
}
|
||||
|
||||
if (!create)
|
||||
return null;
|
||||
|
||||
etco = new EventTimeCodesFrame ();
|
||||
tag.AddFrame (etco);
|
||||
return etco;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <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 override void ParseFields (ByteVector data, byte version)
|
||||
{
|
||||
Events = new List<EventTimeCode> ();
|
||||
TimestampFormat = (TimestampFormat)data.Data[0];
|
||||
|
||||
var incomingEventsData = data.Mid (1);
|
||||
for (var i = 0; i < incomingEventsData.Count - 1; i++) {
|
||||
var eventType = (EventType)incomingEventsData.Data[i];
|
||||
i++;
|
||||
|
||||
var timestampData = new ByteVector (incomingEventsData.Data[i],
|
||||
incomingEventsData.Data[i + 1],
|
||||
incomingEventsData.Data[i + 2],
|
||||
incomingEventsData.Data[i + 3]);
|
||||
|
||||
i += 3;
|
||||
|
||||
var timestamp = timestampData.ToInt ();
|
||||
|
||||
Events.Add (new EventTimeCode (eventType, timestamp));
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 override ByteVector RenderFields (byte version)
|
||||
{
|
||||
var data = new List<byte> {
|
||||
(byte) TimestampFormat
|
||||
};
|
||||
|
||||
foreach (var @event in Events) {
|
||||
data.Add ((byte)@event.TypeOfEvent);
|
||||
|
||||
var timeData = ByteVector.FromInt (@event.Time);
|
||||
data.AddRange (timeData.Data);
|
||||
}
|
||||
|
||||
return new ByteVector (data.ToArray ());
|
||||
}
|
||||
|
||||
#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>
|
||||
public override Frame Clone ()
|
||||
{
|
||||
var frame = new EventTimeCodesFrame (header) {
|
||||
TimestampFormat = TimestampFormat,
|
||||
Events = Events.ConvertAll (item => (EventTimeCode)item.Clone ())
|
||||
};
|
||||
return frame;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c8a9ddf30433b527ea54c50af111b6f7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,308 @@
|
||||
//
|
||||
// MusicCdIdentifierFrame.cs:
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
namespace TagLib.Id3v2
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Frame" />, implementing support for
|
||||
/// ID3v2 Music CD Identifier (MCDI) Frames.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Music CD Identifier Frames should contain the table of
|
||||
/// contents data as stored on the physical CD. It is primarily used
|
||||
/// for track information lookup by through web sources like CDDB.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <para>Reading the music CD identifier from a tag.</para>
|
||||
/// <code lang="C#">
|
||||
/// using TagLib;
|
||||
/// using TagLib.Id3v2;
|
||||
///
|
||||
/// public static class LookupUtil
|
||||
/// {
|
||||
/// public static ByteVector GetCdIdentifier (string filename)
|
||||
/// {
|
||||
/// File file = File.Create (filename, ReadStyle.None);
|
||||
/// Id3v2.Tag tag = file.GetTag (TagTypes.Id3v2, false) as Id3v2.Tag;
|
||||
/// if (tag == null)
|
||||
/// return new ByteVector ();
|
||||
///
|
||||
/// MusicCdIdentifierFrame frame = MusicCdIdentifierFrame.Get (tag, false);
|
||||
/// if (frame == null)
|
||||
/// return new ByteVector ();
|
||||
///
|
||||
/// return frame.Data;
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// <code lang="C++">
|
||||
/// #using <System.dll>
|
||||
/// #using <taglib-sharp.dll>
|
||||
///
|
||||
/// using System;
|
||||
/// using TagLib;
|
||||
/// using TagLib::Id3v2;
|
||||
///
|
||||
/// public ref class LookupUtil abstract sealed
|
||||
/// {
|
||||
/// public:
|
||||
/// static ByteVector^ GetCdIdentifier (String^ filename)
|
||||
/// {
|
||||
/// File^ file = File::Create (filename, ReadStyle::None);
|
||||
/// Id3v2::Tag^ tag = dynamic_cast<Id3v2::Tag^> (file.GetTag (TagTypes::Id3v2, false));
|
||||
/// if (tag == null)
|
||||
/// return gcnew ByteVector;
|
||||
///
|
||||
/// MusicCdIdentifierFrame^ frame = MusicCdIdentifierFrame::Get (tag, false);
|
||||
/// if (frame == null)
|
||||
/// return gcnew ByteVector;
|
||||
///
|
||||
/// return frame->Data;
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// <code lang="VB">
|
||||
/// Imports TagLib
|
||||
/// Imports TagLib.Id3v2
|
||||
///
|
||||
/// Public Shared Class LookupUtil
|
||||
/// Public Shared Sub GetCdIdentifier (filename As String) As TagLib.ByteVector
|
||||
/// Dim file As File = File.Create (filename, ReadStyle.None)
|
||||
/// Dim tag As Id3v2.Tag = file.GetTag (TagTypes.Id3v2, False)
|
||||
/// If tag Is Nothing Return New ByteVector ()
|
||||
///
|
||||
/// Dim frame As MusicCdIdentifierFrame = MusicCdIdentifierFrame.Get (tag, False)
|
||||
/// If frame Is Nothing Return New ByteVector ()
|
||||
///
|
||||
/// Return frame.Data
|
||||
/// End Sub
|
||||
/// End Class
|
||||
/// </code>
|
||||
/// <code lang="Boo">
|
||||
/// import TagLib
|
||||
/// import TagLib.Id3v2
|
||||
///
|
||||
/// public static class LookupUtil:
|
||||
/// static def GetCdIdentifier (filename as string) as TagLib.ByteVector:
|
||||
/// file as File = File.Create (filename, ReadStyle.None)
|
||||
/// tag as Id3v2.Tag = file.GetTag (TagTypes.Id3v2, false)
|
||||
/// if tag == null:
|
||||
/// return ByteVector ()
|
||||
///
|
||||
/// frame as MusicCdIdentifierFrame = MusicCdIdentifierFrame.Get (tag, false)
|
||||
/// if frame == null:
|
||||
/// return ByteVector ()
|
||||
///
|
||||
/// return frame.Data
|
||||
/// </code>
|
||||
/// </example>
|
||||
public class MusicCdIdentifierFrame : Frame
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="MusicCdIdentifierFrame" /> with empty
|
||||
/// identifier data.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When a frame is created, it is not automatically added to
|
||||
/// the tag. Consider using <see cref="Get" /> for more
|
||||
/// integrated frame creation.
|
||||
/// </remarks>
|
||||
public MusicCdIdentifierFrame ()
|
||||
: base (FrameType.MCDI, 4)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="MusicCdIdentifierFrame" /> by reading its raw data
|
||||
/// in a specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object starting with the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
public MusicCdIdentifierFrame (ByteVector data, byte version)
|
||||
: base (data, version)
|
||||
{
|
||||
SetData (data, 0, version, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="MusicCdIdentifierFrame" /> by reading its raw data
|
||||
/// in a specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// A <see cref="int" /> indicating at what offset in
|
||||
/// <paramref name="data" /> the frame actually begins.
|
||||
/// </param>
|
||||
/// <param name="header">
|
||||
/// A <see cref="FrameHeader" /> containing the header of the
|
||||
/// frame found at <paramref name="offset" /> in the data.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
protected internal MusicCdIdentifierFrame (ByteVector data, int offset, FrameHeader header, byte version)
|
||||
: base (header)
|
||||
{
|
||||
SetData (data, offset, version, false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the identifier data stored in the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ByteVector" /> containing the identifier
|
||||
/// data stored in the current instance.
|
||||
/// </value>
|
||||
public ByteVector Data { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Public Static Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a music CD identifier frame from a specified tag,
|
||||
/// optionally creating it if it does not exist.
|
||||
/// </summary>
|
||||
/// <param name="tag">
|
||||
/// A <see cref="Tag" /> object to search in.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> specifying whether or not to create
|
||||
/// and add a new frame to the tag if a match is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="MusicCdIdentifierFrame" /> object containing
|
||||
/// the matching frame, or <see langword="null" /> if a match
|
||||
/// wasn't found and <paramref name="create" /> is <see
|
||||
/// langword="false" />.
|
||||
/// </returns>
|
||||
public static MusicCdIdentifierFrame Get (Tag tag, bool create)
|
||||
{
|
||||
MusicCdIdentifierFrame mcdi;
|
||||
foreach (Frame frame in tag) {
|
||||
mcdi = frame as MusicCdIdentifierFrame;
|
||||
|
||||
if (mcdi != null)
|
||||
return mcdi;
|
||||
}
|
||||
|
||||
if (!create)
|
||||
return null;
|
||||
|
||||
mcdi = new MusicCdIdentifierFrame ();
|
||||
tag.AddFrame (mcdi);
|
||||
return mcdi;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <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 override void ParseFields (ByteVector data, byte version)
|
||||
{
|
||||
Data = data;
|
||||
}
|
||||
|
||||
/// <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 override ByteVector RenderFields (byte version)
|
||||
{
|
||||
return Data != null ? Data : new ByteVector ();
|
||||
}
|
||||
|
||||
#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>
|
||||
public override Frame Clone ()
|
||||
{
|
||||
MusicCdIdentifierFrame frame = new MusicCdIdentifierFrame ();
|
||||
if (Data != null)
|
||||
frame.Data = new ByteVector (Data);
|
||||
return frame;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 48de1bca16a0bd7018e48e54a4c4c226
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,345 @@
|
||||
//
|
||||
// PlayCountFrame.cs:
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
namespace TagLib.Id3v2
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Frame" />, implementing support for
|
||||
/// ID3v2 Play Count (PCNT) Frames.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <para>Getting and incrementing the play count of a file.</para>
|
||||
/// <code lang="C#">
|
||||
/// using TagLib;
|
||||
/// using TagLib.Id3v2;
|
||||
///
|
||||
/// public static class TrackUtil
|
||||
/// {
|
||||
/// public static int GetPlayCount (string filename)
|
||||
/// {
|
||||
/// File file = File.Create (filename, ReadStyle.None);
|
||||
/// Id3v2.Tag tag = file.GetTag (TagTypes.Id3v2, false) as Id3v2.Tag;
|
||||
/// if (tag == null)
|
||||
/// return 0;
|
||||
///
|
||||
/// PlayCountFrame frame = PlayCountFrame.Get (tag, false);
|
||||
/// if (frame == null)
|
||||
/// return 0;
|
||||
///
|
||||
/// return frame.PlayCount;
|
||||
/// }
|
||||
///
|
||||
/// public static void IncrementPlayCount (string filename)
|
||||
/// {
|
||||
/// File file = File.Create (filename, ReadStyle.None);
|
||||
/// Id3v2.Tag tag = file.GetTag (TagTypes.Id3v2, true) as Id3v2.Tag;
|
||||
/// if (tag == null)
|
||||
/// return;
|
||||
///
|
||||
/// PlayCountFrame.Get (tag, true).PlayCount ++;
|
||||
/// file.Save ();
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// <code lang="C++">
|
||||
/// #using <System.dll>
|
||||
/// #using <taglib-sharp.dll>
|
||||
///
|
||||
/// using System;
|
||||
/// using TagLib;
|
||||
/// using TagLib::Id3v2;
|
||||
///
|
||||
/// public ref class TrackUtil abstract sealed
|
||||
/// {
|
||||
/// public:
|
||||
/// static int GetPlayCount (String^ filename)
|
||||
/// {
|
||||
/// File^ file = File.Create (filename, ReadStyle.None);
|
||||
/// Id3v2::Tag^ tag = dynamic_cast<Id3v2::Tag^> (file.GetTag (TagTypes::Id3v2, false));
|
||||
/// if (tag == null)
|
||||
/// return 0;
|
||||
///
|
||||
/// PlayCountFrame^ frame = PlayCountFrame::Get (tag, false);
|
||||
/// if (frame == null)
|
||||
/// return 0;
|
||||
///
|
||||
/// return frame->PlayCount;
|
||||
/// }
|
||||
///
|
||||
/// static void IncrementPlayCount (String^ filename)
|
||||
/// {
|
||||
/// File^ file = File::Create (filename, ReadStyle::None);
|
||||
/// Id3v2.Tag^ tag = dynamic_cast<Id3v2::Tag^> (file.GetTag (TagTypes::Id3v2, true));
|
||||
/// if (tag == null)
|
||||
/// return;
|
||||
///
|
||||
/// PlayCountFrame::Get (tag, true)->PlayCount ++;
|
||||
/// file->Save ();
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// <code lang="VB">
|
||||
/// Imports TagLib
|
||||
/// Imports TagLib.Id3v2
|
||||
///
|
||||
/// Public Shared Class TrackUtil
|
||||
/// Public Shared Sub GetPlayCount (filename As String) As Integer
|
||||
/// Dim file As File = File.Create (filename, ReadStyle.None)
|
||||
/// Dim tag As Id3v2.Tag = file.GetTag (TagTypes.Id3v2, False)
|
||||
/// If tag Is Nothing Then Return 0
|
||||
///
|
||||
/// Dim frame As PlayCountFrame = PlayCountFrame.Get (tag, False)
|
||||
/// If frame Is Nothing Then Return 0
|
||||
///
|
||||
/// Return frame.PlayCount
|
||||
/// End Sub
|
||||
///
|
||||
/// Public Shared Sub IncrementPlayCount (filename As String)
|
||||
/// Dim file As File = File.Create (filename, ReadStyle.None)
|
||||
/// Dim tag As Id3v2.Tag = file.GetTag (TagTypes.Id3v2, True)
|
||||
/// If tag Is Nothing Then Exit Sub
|
||||
///
|
||||
/// PlayCountFrame.Get (tag, True).PlayCount += 1
|
||||
/// file.Save ()
|
||||
/// End Sub
|
||||
/// End Class
|
||||
/// </code>
|
||||
/// <code lang="Boo">
|
||||
/// import TagLib
|
||||
/// import TagLib.Id3v2
|
||||
///
|
||||
/// public static class TrackUtil:
|
||||
/// static def GetPlayCount (filename as string) as int:
|
||||
/// file As File = File.Create (filename, ReadStyle.None)
|
||||
/// tag as Id3v2.Tag = file.GetTag (TagTypes.Id3v2, false)
|
||||
/// if tag == null:
|
||||
/// return 0
|
||||
///
|
||||
/// frame as PlayCountFrame = PlayCountFrame.Get (tag, false)
|
||||
/// if frame == null:
|
||||
/// return 0
|
||||
///
|
||||
/// return frame.PlayCount
|
||||
///
|
||||
/// static def IncrementPlayCount (filename as string):
|
||||
/// file as File = File.Create (filename, ReadStyle.None)
|
||||
/// tag as Id3v2.Tag = file.GetTag (TagTypes.Id3v2, True)
|
||||
/// if tag == null:
|
||||
/// return
|
||||
///
|
||||
/// PlayCountFrame.Get (tag, true).PlayCount ++
|
||||
/// file.Save ()
|
||||
/// </code>
|
||||
/// </example>
|
||||
public class PlayCountFrame : Frame
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="PlayCountFrame" /> with a count of zero.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When a frame is created, it is not automatically added to
|
||||
/// the tag. Consider using <see cref="Get" /> for more
|
||||
/// integrated frame creation.
|
||||
/// </remarks>
|
||||
public PlayCountFrame () : base (FrameType.PCNT, 4)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="PlayCountFrame" /> by reading its raw data in a
|
||||
/// specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object starting with the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
public PlayCountFrame (ByteVector data, byte version)
|
||||
: base (data, version)
|
||||
{
|
||||
SetData (data, 0, version, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="PlayCountFrame" /> by reading its raw data in a
|
||||
/// specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// A <see cref="int" /> indicating at what offset in
|
||||
/// <paramref name="data" /> the frame actually begins.
|
||||
/// </param>
|
||||
/// <param name="header">
|
||||
/// A <see cref="FrameHeader" /> containing the header of the
|
||||
/// frame found at <paramref name="offset" /> in the data.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
protected internal PlayCountFrame (ByteVector data, int offset, FrameHeader header, byte version)
|
||||
: base (header)
|
||||
{
|
||||
SetData (data, offset, version, false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the play count of the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ulong" /> containing the play count of the
|
||||
/// current instance.
|
||||
/// </value>
|
||||
public ulong PlayCount { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Static Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a play count frame from a specified tag, optionally
|
||||
/// creating it if it does not exist.
|
||||
/// </summary>
|
||||
/// <param name="tag">
|
||||
/// A <see cref="Tag" /> object to search in.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> specifying whether or not to create
|
||||
/// and add a new frame to the tag if a match is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="PlayCountFrame" /> object containing the
|
||||
/// matching frame, or <see langword="null" /> if a match
|
||||
/// wasn't found and <paramref name="create" /> is <see
|
||||
/// langword="false" />.
|
||||
/// </returns>
|
||||
public static PlayCountFrame Get (Tag tag, bool create)
|
||||
{
|
||||
PlayCountFrame pcnt;
|
||||
foreach (Frame frame in tag) {
|
||||
pcnt = frame as PlayCountFrame;
|
||||
|
||||
if (pcnt != null)
|
||||
return pcnt;
|
||||
}
|
||||
|
||||
if (!create)
|
||||
return null;
|
||||
|
||||
pcnt = new PlayCountFrame ();
|
||||
tag.AddFrame (pcnt);
|
||||
return pcnt;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <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 override void ParseFields (ByteVector data, byte version)
|
||||
{
|
||||
PlayCount = data.ToULong ();
|
||||
}
|
||||
|
||||
/// <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 override ByteVector RenderFields (byte version)
|
||||
{
|
||||
ByteVector data = ByteVector.FromULong (PlayCount);
|
||||
while (data.Count > 4 && data[0] == 0)
|
||||
data.RemoveAt (0);
|
||||
|
||||
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>
|
||||
public override Frame Clone ()
|
||||
{
|
||||
var frame = new PlayCountFrame {
|
||||
PlayCount = PlayCount
|
||||
};
|
||||
return frame;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 64052d14f12d58e988f1a199dfe54599
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,275 @@
|
||||
//
|
||||
// PopularimeterFrame.cs:
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
namespace TagLib.Id3v2
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Frame" />, implementing support for
|
||||
/// ID3v2 Popularimeter (POPM) Frames.
|
||||
/// </summary>
|
||||
public class PopularimeterFrame : Frame
|
||||
{
|
||||
#region Private Properties
|
||||
|
||||
/// <summary>
|
||||
/// Contains the email of the user this frame belongs to.
|
||||
/// </summary>
|
||||
string user = string.Empty;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="PopularimeterFrame" /> for a specified user with a
|
||||
/// rating and play count of zero.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When a frame is created, it is not automatically added to
|
||||
/// the tag. Consider using <see cref="Get" /> for more
|
||||
/// integrated frame creation.
|
||||
/// </remarks>
|
||||
public PopularimeterFrame (string user)
|
||||
: base (FrameType.POPM, 4)
|
||||
{
|
||||
User = user;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="PopularimeterFrame" /> by reading its raw data in a
|
||||
/// specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object starting with the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
public PopularimeterFrame (ByteVector data, byte version)
|
||||
: base (data, version)
|
||||
{
|
||||
SetData (data, 0, version, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="PopularimeterFrame" /> by reading its raw data in a
|
||||
/// specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// A <see cref="int" /> indicating at what offset in
|
||||
/// <paramref name="data" /> the frame actually begins.
|
||||
/// </param>
|
||||
/// <param name="header">
|
||||
/// A <see cref="FrameHeader" /> containing the header of the
|
||||
/// frame found at <paramref name="offset" /> in the data.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
protected internal PopularimeterFrame (ByteVector data, int offset, FrameHeader header, byte version)
|
||||
: base (header)
|
||||
{
|
||||
SetData (data, offset, version, false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the user to whom the current instance
|
||||
/// belongs.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> containing the user to whom the
|
||||
/// current instance belongs.
|
||||
/// </value>
|
||||
public string User {
|
||||
get { return user; }
|
||||
set { user = value ?? string.Empty; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the rating of the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="byte" /> containing the rating of the
|
||||
/// current instance.
|
||||
/// </value>
|
||||
public byte Rating { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the play count of the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ulong" /> containing the play count of the
|
||||
/// current instance.
|
||||
/// </value>
|
||||
public ulong PlayCount { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Static Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a popularimeter frame from a specified tag,
|
||||
/// optionally creating it if it does not exist.
|
||||
/// </summary>
|
||||
/// <param name="tag">
|
||||
/// A <see cref="Tag" /> object to search in.
|
||||
/// </param>
|
||||
/// <param name="user">
|
||||
/// A <see cref="string" /> containing the user to search for
|
||||
/// in the current instance.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> specifying whether or not to create
|
||||
/// and add a new frame to the tag if a match is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="PopularimeterFrame" /> object containing the
|
||||
/// matching frame, or <see langword="null" /> if a match
|
||||
/// wasn't found and <paramref name="create" /> is <see
|
||||
/// langword="false" />.
|
||||
/// </returns>
|
||||
public static PopularimeterFrame Get (Tag tag, string user, bool create)
|
||||
{
|
||||
PopularimeterFrame popm;
|
||||
foreach (Frame frame in tag) {
|
||||
popm = frame as PopularimeterFrame;
|
||||
|
||||
if (popm != null && popm.user.Equals (user))
|
||||
return popm;
|
||||
}
|
||||
|
||||
if (!create)
|
||||
return null;
|
||||
|
||||
popm = new PopularimeterFrame (user);
|
||||
tag.AddFrame (popm);
|
||||
return popm;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <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 override void ParseFields (ByteVector data, byte version)
|
||||
{
|
||||
var delim = ByteVector.TextDelimiter (StringType.Latin1);
|
||||
|
||||
int index = data.Find (delim);
|
||||
if (index < 0)
|
||||
throw new CorruptFileException ("Popularimeter frame does not contain a text delimiter");
|
||||
|
||||
if (index + 2 > data.Count)
|
||||
throw new CorruptFileException ("Popularimeter is too short");
|
||||
|
||||
user = data.ToString (StringType.Latin1, 0, index);
|
||||
Rating = data[index + 1];
|
||||
PlayCount = data.Mid (index + 2).ToULong ();
|
||||
}
|
||||
|
||||
/// <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 override ByteVector RenderFields (byte version)
|
||||
{
|
||||
ByteVector data = ByteVector.FromULong (PlayCount);
|
||||
while (data.Count > 0 && data[0] == 0)
|
||||
data.RemoveAt (0);
|
||||
|
||||
data.Insert (0, Rating);
|
||||
data.Insert (0, 0);
|
||||
data.Insert (0, ByteVector.FromString (user, StringType.Latin1));
|
||||
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>
|
||||
public override Frame Clone ()
|
||||
{
|
||||
PopularimeterFrame frame = new PopularimeterFrame (user);
|
||||
frame.PlayCount = PlayCount;
|
||||
frame.Rating = Rating;
|
||||
return frame;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1fd77da4e9b427af78dedd3b73ee5488
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,404 @@
|
||||
//
|
||||
// PrivateFrame.cs:
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2005-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.Id3v2
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Frame" />, implementing support for
|
||||
/// ID3v2 Private (PRIV) Frames.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>A <see cref="PrivateFrame" /> should be used for storing
|
||||
/// values specific to the application that cannot or should not be
|
||||
/// stored in another frame type.</para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <para>Serializing a database entry and storing it in a private
|
||||
/// field.</para>
|
||||
/// <code lang="C#">
|
||||
/// using System;
|
||||
/// using System.IO;
|
||||
/// using System.Runtime.Serialization;
|
||||
/// using System.Text;
|
||||
/// using System.Xml.Serialization;
|
||||
/// using TagLib.Id3v2;
|
||||
///
|
||||
/// public static class DbUtil
|
||||
/// {
|
||||
/// public static void StoreDatabaseEntry (Tag tag, ISerializable dbEntry)
|
||||
/// {
|
||||
/// StringWriter data = new StringWriter (new StringBuilder ());
|
||||
/// XmlSerializer serializer = new XmlSerializer (dbEntry.GetType ());
|
||||
/// serializer.Serialize (data, dbEntry);
|
||||
/// PrivateFrame frame = PrivateFrame.Get (tag, "org.MyProgram.DatabaseEntry", true);
|
||||
/// frame.PrivateData = Encoding.UTF8.GetBytes (data.ToString ());
|
||||
/// }
|
||||
///
|
||||
/// public static object GetDatabaseEntry (Tag tag, Type type)
|
||||
/// {
|
||||
/// PrivateFrame frame = PrivateFrame.Get (tag, "org.MyProgram.DatabaseEntry", false);
|
||||
/// if (frame == null)
|
||||
/// return null;
|
||||
///
|
||||
/// XmlSerializer serializer = new XmlSerializer (type);
|
||||
/// return serializer.Deserialize (new MemoryStream (frame.PrivateData));
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// <code lang="C++">
|
||||
/// #using <System.dll>
|
||||
/// #using <System.Xml.dll>
|
||||
/// #using <taglib-sharp.dll>
|
||||
///
|
||||
/// using System;
|
||||
/// using System::IO;
|
||||
/// using System::Runtime::Serialization;
|
||||
/// using System::Text;
|
||||
/// using System::Xml::Serialization;
|
||||
/// using TagLib::Id3v2;
|
||||
///
|
||||
/// public ref class DbUtil abstract sealed
|
||||
/// {
|
||||
/// public:
|
||||
/// static void StoreDatabaseEntry (Tag^ tag, ISerializable^ dbEntry)
|
||||
/// {
|
||||
/// StringWriter^ data = gcnew StringWriter (gcnew StringBuilder);
|
||||
/// XmlSerializer serializer = gcnew XmlSerializer (dbEntry->GetType ());
|
||||
/// serializer->Serialize (data, dbEntry);
|
||||
/// PrivateFrame frame = PrivateFrame::Get (tag, L"org.MyProgram.DatabaseEntry", true);
|
||||
/// frame.PrivateData = Encoding::UTF8->GetBytes (data->ToString ());
|
||||
/// }
|
||||
///
|
||||
/// static Object^ GetDatabaseEntry (Tag^ tag, Type^ type)
|
||||
/// {
|
||||
/// PrivateFrame^ frame = PrivateFrame::Get (tag, L"org.MyProgram.DatabaseEntry", false);
|
||||
/// if (frame == null)
|
||||
/// return null;
|
||||
///
|
||||
/// XmlSerializer serializer = gcnew XmlSerializer (type);
|
||||
/// return serializer->Deserialize (gcnew MemoryStream (frame->PrivateData));
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// <code lang="VB">
|
||||
/// Imports System
|
||||
/// Imports System.IO
|
||||
/// Imports System.Runtime.Serialization
|
||||
/// Imports System.Text
|
||||
/// Imports System.Xml.Serialization
|
||||
/// Imports TagLib.Id3v2
|
||||
///
|
||||
/// Public Shared Class DbUtil
|
||||
/// Public Shared Sub StoreDatabaseEntry (tag As Tag, dbEntry As ISerializable)
|
||||
/// Dim data As New StringWriter (New StringBuilder ())
|
||||
/// Dim serializer As New XmlSerializer (dbEntry.GetType ())
|
||||
/// serializer.Serialize (data, dbEntry)
|
||||
/// Dim frame As PrivateFrame = PrivateFrame.Get (tag, "org.MyProgram.DatabaseEntry", True)
|
||||
/// frame.PrivateData = Encoding.UTF8.GetBytes (data.ToString ())
|
||||
/// End Sub
|
||||
///
|
||||
/// Public Shared Sub GetDatabaseEntry (tag As Tag, type As Type)
|
||||
/// Dim frame As PrivateFrame = PrivateFrame.Get (tag, "org.MyProgram.DatabaseEntry", False)
|
||||
/// If frame Is Nothing Then Return Nothing
|
||||
///
|
||||
/// Dim serializer As XmlSerializer = New XmlSerializer (type)
|
||||
/// Return serializer.Deserialize (New MemoryStream (frame.PrivateData))
|
||||
/// End Sub
|
||||
/// End Class
|
||||
/// </code>
|
||||
/// <code lang="Boo">
|
||||
/// import System
|
||||
/// import System.IO
|
||||
/// import System.Runtime.Serialization
|
||||
/// import System.Text
|
||||
/// import System.Xml.Serialization
|
||||
/// import TagLib.Id3v2
|
||||
///
|
||||
/// public static class DbUtil:
|
||||
/// static def StoreDatabaseEntry (tag as Tag, dbEntry as ISerializable):
|
||||
/// data as StringWriter = StringWriter (StringBuilder ())
|
||||
/// serializer as XmlSerializer = XmlSerializer (dbEntry.GetType ())
|
||||
/// serializer.Serialize (data, dbEntry)
|
||||
/// frame as PrivateFrame = PrivateFrame.Get (tag, "org.MyProgram.DatabaseEntry", true)
|
||||
/// frame.PrivateData = Encoding.UTF8.GetBytes (data.ToString ())
|
||||
///
|
||||
/// static def GetDatabaseEntry (tag As Tag, type As Type):
|
||||
/// frame as PrivateFrame = PrivateFrame.Get (tag, "org.MyProgram.DatabaseEntry", false)
|
||||
/// if frame == null:
|
||||
/// return null
|
||||
///
|
||||
/// serializer as XmlSerializer = XmlSerializer (type)
|
||||
/// return serializer.Deserialize (MemoryStream (frame.PrivateData))
|
||||
/// </code>
|
||||
/// </example>
|
||||
public class PrivateFrame : Frame
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="PrivateFrame" /> for a specified owner and data.
|
||||
/// </summary>
|
||||
/// <param name="owner">
|
||||
/// A <see cref="string" /> containing the owner of the new
|
||||
/// frame.
|
||||
/// </param>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the data
|
||||
/// for the new frame.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// When a frame is created, it is not automatically added to
|
||||
/// the tag. Consider using <see cref="Get" /> for more
|
||||
/// integrated frame creation.
|
||||
/// </remarks>
|
||||
public PrivateFrame (string owner, ByteVector data)
|
||||
: base (FrameType.PRIV, 4)
|
||||
{
|
||||
Owner = owner;
|
||||
PrivateData = data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="PrivateFrame" /> without data for a specified
|
||||
/// owner.
|
||||
/// </summary>
|
||||
/// <param name="owner">
|
||||
/// A <see cref="string" /> containing the owner of the new
|
||||
/// frame.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// When a frame is created, it is not automatically added to
|
||||
/// the tag. Consider using <see cref="Get" /> for more
|
||||
/// integrated frame creation.
|
||||
/// </remarks>
|
||||
public PrivateFrame (string owner) : this (owner, null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="PrivateFrame" /> by reading its raw data in a
|
||||
/// specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object starting with the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
public PrivateFrame (ByteVector data, byte version)
|
||||
: base (data, version)
|
||||
{
|
||||
SetData (data, 0, version, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="PrivateFrame" /> by reading its raw data in a
|
||||
/// specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// A <see cref="int" /> indicating at what offset in
|
||||
/// <paramref name="data" /> the frame actually begins.
|
||||
/// </param>
|
||||
/// <param name="header">
|
||||
/// A <see cref="FrameHeader" /> containing the header of the
|
||||
/// frame found at <paramref name="offset" /> in the data.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
protected internal PrivateFrame (ByteVector data, int offset, FrameHeader header, byte version) : base (header)
|
||||
{
|
||||
SetData (data, offset, version, false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the owner of the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> containing the owner of the
|
||||
/// current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// There should only be one frame with a given owner per
|
||||
/// tag.
|
||||
/// </remarks>
|
||||
public string Owner { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the private data stored in the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ByteVector" /> containing the private data
|
||||
/// stored in the current instance.
|
||||
/// </value>
|
||||
public ByteVector PrivateData { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Static Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a specified private frame from the specified tag,
|
||||
/// optionally creating it if it does not exist.
|
||||
/// </summary>
|
||||
/// <param name="tag">
|
||||
/// A <see cref="Tag" /> object to search in.
|
||||
/// </param>
|
||||
/// <param name="owner">
|
||||
/// A <see cref="string" /> specifying the owner to match.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> specifying whether or not to create
|
||||
/// and add a new frame to the tag if a match is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="PrivateFrame" /> object containing the
|
||||
/// matching frame, or <see langword="null" /> if a match
|
||||
/// wasn't found and <paramref name="create" /> is <see
|
||||
/// langword="false" />.
|
||||
/// </returns>
|
||||
public static PrivateFrame Get (Tag tag, string owner, bool create)
|
||||
{
|
||||
PrivateFrame priv;
|
||||
|
||||
foreach (Frame frame in tag.GetFrames (FrameType.PRIV)) {
|
||||
priv = frame as PrivateFrame;
|
||||
if (priv != null && priv.Owner == owner)
|
||||
return priv;
|
||||
}
|
||||
|
||||
if (!create)
|
||||
return null;
|
||||
|
||||
priv = new PrivateFrame (owner);
|
||||
tag.AddFrame (priv);
|
||||
return priv;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <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 override void ParseFields (ByteVector data, byte version)
|
||||
{
|
||||
if (data.Count < 1)
|
||||
throw new CorruptFileException ("A private frame must contain at least 1 byte.");
|
||||
|
||||
var l = ByteVectorCollection.Split (data, ByteVector.TextDelimiter (StringType.Latin1), 1, 2);
|
||||
|
||||
if (l.Count == 2) {
|
||||
Owner = l[0].ToString (StringType.Latin1);
|
||||
PrivateData = l[1];
|
||||
}
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// <exception cref="NotImplementedException">
|
||||
/// <paramref name="version" /> is less than 3. ID3v2.2 does
|
||||
/// not support this frame.
|
||||
/// </exception>
|
||||
protected override ByteVector RenderFields (byte version)
|
||||
{
|
||||
if (version < 3)
|
||||
throw new NotImplementedException ();
|
||||
|
||||
var v = new ByteVector {
|
||||
ByteVector.FromString (Owner, StringType.Latin1),
|
||||
ByteVector.TextDelimiter (StringType.Latin1),
|
||||
PrivateData
|
||||
};
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
#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>
|
||||
public override Frame Clone ()
|
||||
{
|
||||
var frame = new PrivateFrame (Owner);
|
||||
if (PrivateData != null)
|
||||
frame.PrivateData = new ByteVector (PrivateData);
|
||||
return frame;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b323c897f28aac1148ac32d4101a0bae
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,581 @@
|
||||
//
|
||||
// RelativeVolumeFrame.cs:
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Original Source:
|
||||
// textidentificationframe.cpp from TagLib
|
||||
//
|
||||
// Copyright (C) 2005-2007 Brian Nickel
|
||||
// Copyright (C) 2004 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>
|
||||
/// Specified the type of channel data to get from or set to a
|
||||
/// <see cref="RelativeVolumeFrame" /> object.
|
||||
/// </summary>
|
||||
public enum ChannelType
|
||||
{
|
||||
/// <summary>
|
||||
/// The channel data is for some other speaker.
|
||||
/// </summary>
|
||||
Other = 0x00,
|
||||
|
||||
/// <summary>
|
||||
/// The channel data is for the master volume.
|
||||
/// </summary>
|
||||
MasterVolume = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// The channel data is for the front right speaker.
|
||||
/// </summary>
|
||||
FrontRight = 0x02,
|
||||
|
||||
/// <summary>
|
||||
/// The channel data is for the front left speaker.
|
||||
/// </summary>
|
||||
FrontLeft = 0x03,
|
||||
|
||||
/// <summary>
|
||||
/// The channel data is for the back right speaker.
|
||||
/// </summary>
|
||||
BackRight = 0x04,
|
||||
|
||||
/// <summary>
|
||||
/// The channel data is for the back left speaker.
|
||||
/// </summary>
|
||||
BackLeft = 0x05,
|
||||
|
||||
/// <summary>
|
||||
/// The channel data is for the front center speaker.
|
||||
/// </summary>
|
||||
FrontCentre = 0x06,
|
||||
|
||||
/// <summary>
|
||||
/// The channel data is for the back center speaker.
|
||||
/// </summary>
|
||||
BackCentre = 0x07,
|
||||
|
||||
/// <summary>
|
||||
/// The channel data is for the subwoofer.
|
||||
/// </summary>
|
||||
Subwoofer = 0x08
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Frame" />, implementing support for
|
||||
/// ID3v2 Relative Volume (RVA2) Frames.
|
||||
/// </summary>
|
||||
public class RelativeVolumeFrame : Frame
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the channel data.
|
||||
/// </summary>
|
||||
readonly ChannelData[] channels = new ChannelData[9];
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="RelativeVolumeFrame" /> with a specified
|
||||
/// identifier.
|
||||
/// </summary>
|
||||
/// <param name="identification">
|
||||
/// A <see cref="string" /> object containing the
|
||||
/// identification to use for the new frame.
|
||||
/// </param>
|
||||
public RelativeVolumeFrame (string identification)
|
||||
: base (FrameType.RVA2, 4)
|
||||
{
|
||||
Identification = identification;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="RelativeVolumeFrame" /> by reading its raw data in
|
||||
/// a specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object starting with the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
public RelativeVolumeFrame (ByteVector data, byte version)
|
||||
: base (data, version)
|
||||
{
|
||||
SetData (data, 0, version, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="RelativeVolumeFrame" /> by reading its raw data in
|
||||
/// a specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// A <see cref="int" /> indicating at what offset in
|
||||
/// <paramref name="data" /> the frame actually begins.
|
||||
/// </param>
|
||||
/// <param name="header">
|
||||
/// A <see cref="FrameHeader" /> containing the header of the
|
||||
/// frame found at <paramref name="offset" /> in the data.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
protected internal RelativeVolumeFrame (ByteVector data, int offset, FrameHeader header, byte version)
|
||||
: base (header)
|
||||
{
|
||||
SetData (data, offset, version, false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the identification used for the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing the
|
||||
/// identification used for the current instance.
|
||||
/// </value>
|
||||
public string Identification { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of the channels in the current instance that
|
||||
/// contain a value.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="T:ChannelType[]" /> containing the channels
|
||||
/// which have a value set in the current instance.
|
||||
/// </value>
|
||||
public ChannelType[] Channels {
|
||||
get {
|
||||
var types = new List<ChannelType> ();
|
||||
for (int i = 0; i < 9; i++)
|
||||
if (channels[i].IsSet)
|
||||
types.Add ((ChannelType)i);
|
||||
return types.ToArray ();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Creates a text description of the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="string" /> object containing a description
|
||||
/// of the current instance.
|
||||
/// </returns>
|
||||
public override string ToString ()
|
||||
{
|
||||
return Identification;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the volume adjustment index for a specified channel.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="ChannelType" /> value specifying which
|
||||
/// channel to get the value for.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="short" /> value containing the volume
|
||||
/// adjustment index.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// The volume adjustment index is simply the volume
|
||||
/// adjustment multiplied by 512.
|
||||
/// </remarks>
|
||||
/// <seealso cref="SetVolumeAdjustmentIndex"/>
|
||||
/// <seealso cref="GetVolumeAdjustment"/>
|
||||
public short GetVolumeAdjustmentIndex (ChannelType type)
|
||||
{
|
||||
return channels[(int)type].VolumeAdjustmentIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the volume adjustment index for a specified channel.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="ChannelType" /> value specifying which
|
||||
/// channel to set the value for.
|
||||
/// </param>
|
||||
/// <param name="index">
|
||||
/// A <see cref="short" /> value containing the volume
|
||||
/// adjustment index.
|
||||
/// </param>
|
||||
/// <seealso cref="GetVolumeAdjustmentIndex"/>
|
||||
/// <seealso cref="SetVolumeAdjustment"/>
|
||||
public void SetVolumeAdjustmentIndex (ChannelType type, short index)
|
||||
{
|
||||
channels[(int)type].VolumeAdjustmentIndex = index;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the volume adjustment for a specified channel.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="ChannelType" /> value specifying which
|
||||
/// channel to get the value for.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="float" /> value containing the volume
|
||||
/// adjustment in decibles.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// The value can be between -64dB and +64dB.
|
||||
/// </remarks>
|
||||
/// <seealso cref="SetVolumeAdjustment"/>
|
||||
/// <seealso cref="GetVolumeAdjustmentIndex"/>
|
||||
public float GetVolumeAdjustment (ChannelType type)
|
||||
{
|
||||
return channels[(int)type].VolumeAdjustment;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the volume adjustment for a specified channel.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="ChannelType" /> value specifying which
|
||||
/// channel to set the value for.
|
||||
/// </param>
|
||||
/// <param name="adjustment">
|
||||
/// A <see cref="float" /> value containing the volume
|
||||
/// adjustment in decibles.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// The value can be between -64dB and +64dB.
|
||||
/// </remarks>
|
||||
/// <seealso cref="GetVolumeAdjustment"/>
|
||||
/// <seealso cref="SetVolumeAdjustmentIndex"/>
|
||||
public void SetVolumeAdjustment (ChannelType type, float adjustment)
|
||||
{
|
||||
channels[(int)type].VolumeAdjustment = adjustment;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the peak volume index for a specified channel.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="ChannelType" /> value specifying which
|
||||
/// channel to get the value for.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="ulong" /> value containing the peak volume
|
||||
/// index.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// The peak volume index is simply the peak volume
|
||||
/// multiplied by 512.
|
||||
/// </remarks>
|
||||
/// <seealso cref="SetPeakVolumeIndex"/>
|
||||
/// <seealso cref="GetPeakVolume"/>
|
||||
public ulong GetPeakVolumeIndex (ChannelType type)
|
||||
{
|
||||
return channels[(int)type].PeakVolumeIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the peak volume index for a specified channel.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="ChannelType" /> value specifying which
|
||||
/// channel to set the value for.
|
||||
/// </param>
|
||||
/// <param name="index">
|
||||
/// A <see cref="ulong" /> value containing the peak volume
|
||||
/// index.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// The peak volume index is simply the peak volume
|
||||
/// multiplied by 512.
|
||||
/// </remarks>
|
||||
/// <seealso cref="GetPeakVolumeIndex"/>
|
||||
/// <seealso cref="SetPeakVolume"/>
|
||||
public void SetPeakVolumeIndex (ChannelType type, ulong index)
|
||||
{
|
||||
channels[(int)type].PeakVolumeIndex = index;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the peak volume for a specified channel.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="ChannelType" /> value specifying which
|
||||
/// channel to get the value for.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="double" /> value containing the peak volume.
|
||||
/// </returns>
|
||||
/// <seealso cref="SetPeakVolume"/>
|
||||
/// <seealso cref="GetPeakVolumeIndex"/>
|
||||
public double GetPeakVolume (ChannelType type)
|
||||
{
|
||||
return channels[(int)type].PeakVolume;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the peak volume for a specified channel.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="ChannelType" /> value specifying which
|
||||
/// channel to set the value for.
|
||||
/// </param>
|
||||
/// <param name="peak">
|
||||
/// A <see cref="double" /> value containing the peak volume.
|
||||
/// </param>
|
||||
/// <seealso cref="GetPeakVolume"/>
|
||||
/// <seealso cref="SetPeakVolumeIndex"/>
|
||||
public void SetPeakVolume (ChannelType type, double peak)
|
||||
{
|
||||
channels[(int)type].PeakVolume = peak;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Static Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a specified volume adjustment frame from the
|
||||
/// specified tag, optionally creating it if it does not
|
||||
/// exist.
|
||||
/// </summary>
|
||||
/// <param name="tag">
|
||||
/// A <see cref="Tag" /> object to search in.
|
||||
/// </param>
|
||||
/// <param name="identification">
|
||||
/// A <see cref="string" /> specifying the identification to
|
||||
/// match.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> specifying whether or not to create
|
||||
/// and add a new frame to the tag if a match is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="RelativeVolumeFrame" /> object containing
|
||||
/// the matching frame, or <see langword="null" /> if a match
|
||||
/// wasn't found and <paramref name="create" /> is <see
|
||||
/// langword="false" />.
|
||||
/// </returns>
|
||||
public static RelativeVolumeFrame Get (Tag tag, string identification, bool create)
|
||||
{
|
||||
RelativeVolumeFrame rva2;
|
||||
foreach (Frame frame in tag.GetFrames (FrameType.RVA2)) {
|
||||
rva2 = frame as RelativeVolumeFrame;
|
||||
|
||||
if (rva2 == null)
|
||||
continue;
|
||||
|
||||
if (rva2.Identification != identification)
|
||||
continue;
|
||||
|
||||
return rva2;
|
||||
}
|
||||
|
||||
if (!create)
|
||||
return null;
|
||||
|
||||
rva2 = new RelativeVolumeFrame (identification);
|
||||
tag.AddFrame (rva2);
|
||||
return rva2;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Protected Properties
|
||||
|
||||
/// <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>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// <paramref name="data" /> contains less than 5 bytes.
|
||||
/// </exception>
|
||||
protected override void ParseFields (ByteVector data, byte version)
|
||||
{
|
||||
int pos = data.Find (ByteVector.TextDelimiter (StringType.Latin1));
|
||||
if (pos < 0)
|
||||
return;
|
||||
|
||||
Identification = data.ToString (StringType.Latin1, 0, pos++);
|
||||
|
||||
// Each channel is at least 4 bytes.
|
||||
|
||||
while (pos <= data.Count - 4) {
|
||||
int type = data[pos++];
|
||||
|
||||
unchecked {
|
||||
channels[type].VolumeAdjustmentIndex = (short)data.Mid (pos, 2).ToUShort ();
|
||||
}
|
||||
pos += 2;
|
||||
|
||||
int bytes = BitsToBytes (data[pos++]);
|
||||
|
||||
if (data.Count < pos + bytes)
|
||||
break;
|
||||
|
||||
channels[type].PeakVolumeIndex = data.Mid (pos, bytes).ToULong ();
|
||||
pos += bytes;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 override ByteVector RenderFields (byte version)
|
||||
{
|
||||
var data = new ByteVector {
|
||||
ByteVector.FromString (Identification, StringType.Latin1),
|
||||
ByteVector.TextDelimiter (StringType.Latin1)
|
||||
};
|
||||
|
||||
for (byte i = 0; i < 9; i++) {
|
||||
if (!channels[i].IsSet)
|
||||
continue;
|
||||
|
||||
data.Add (i);
|
||||
unchecked {
|
||||
data.Add (ByteVector.FromUShort ((ushort)channels[i].VolumeAdjustmentIndex));
|
||||
}
|
||||
|
||||
byte bits = 0;
|
||||
|
||||
for (byte j = 0; j < 64; j++)
|
||||
if ((channels[i].PeakVolumeIndex & (1UL << j)) != 0)
|
||||
bits = (byte)(j + 1);
|
||||
|
||||
data.Add (bits);
|
||||
|
||||
if (bits > 0)
|
||||
data.Add (ByteVector.FromULong (channels[i].PeakVolumeIndex).Mid (8 - BitsToBytes (bits)));
|
||||
}
|
||||
|
||||
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>
|
||||
public override Frame Clone ()
|
||||
{
|
||||
var frame = new RelativeVolumeFrame (Identification);
|
||||
for (int i = 0; i < 9; i++)
|
||||
frame.channels[i] = channels[i];
|
||||
return frame;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Private Static Methods
|
||||
|
||||
static int BitsToBytes (int i)
|
||||
{
|
||||
return i % 8 == 0 ? i / 8 : (i - i % 8) / 8 + 1;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Classes
|
||||
|
||||
struct ChannelData
|
||||
{
|
||||
public short VolumeAdjustmentIndex;
|
||||
public ulong PeakVolumeIndex;
|
||||
|
||||
public bool IsSet {
|
||||
get {
|
||||
return VolumeAdjustmentIndex != 0 ||
|
||||
PeakVolumeIndex != 0;
|
||||
}
|
||||
}
|
||||
|
||||
public float VolumeAdjustment {
|
||||
get { return VolumeAdjustmentIndex / 512f; }
|
||||
set { VolumeAdjustmentIndex = (short)(value * 512f); }
|
||||
}
|
||||
|
||||
public double PeakVolume {
|
||||
get { return PeakVolumeIndex / 512.0; }
|
||||
set { PeakVolumeIndex = (ulong)(value * 512.0); }
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 68b45b2ff2e0a76be878c55edca8b8a8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,554 @@
|
||||
//
|
||||
// SynchronizedLyricsFrame.cs:
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 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.Collections.Generic;
|
||||
|
||||
namespace TagLib.Id3v2
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Frame" />, implementing support for
|
||||
/// ID3v2 Synchronised Lyrics and Text (SYLT) Frames.
|
||||
/// </summary>
|
||||
public class SynchronisedLyricsFrame : Frame
|
||||
{
|
||||
|
||||
#region Private Properties
|
||||
|
||||
/// <summary>
|
||||
/// Contains the ISO-639-2 language code.
|
||||
/// </summary>
|
||||
string language;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the text.
|
||||
/// </summary>
|
||||
SynchedText[] text = new SynchedText[0];
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="SynchronisedLyricsFrame" /> with a specified
|
||||
/// description, ISO-639-2 language code, text type, and text
|
||||
/// encoding.
|
||||
/// </summary>
|
||||
/// <param name="description">
|
||||
/// A <see cref="string" /> object containing the description
|
||||
/// of the new instnace.
|
||||
/// </param>
|
||||
/// <param name="language">
|
||||
/// A <see cref="string" /> object containing the ISO-639-2
|
||||
/// language code of the new instance.
|
||||
/// </param>
|
||||
/// <param name="type">
|
||||
/// A <see cref="SynchedTextType" /> containing the type of
|
||||
/// text to be stored in the new instance.
|
||||
/// </param>
|
||||
/// <param name="encoding">
|
||||
/// A <see cref="StringType" /> containing the text encoding
|
||||
/// to use when rendering the new instance.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// When a frame is created, it is not automatically added to
|
||||
/// the tag. Consider using <see cref="Get" /> for more
|
||||
/// integrated frame creation.
|
||||
/// </remarks>
|
||||
public SynchronisedLyricsFrame (string description, string language, SynchedTextType type, StringType encoding)
|
||||
: base (FrameType.SYLT, 4)
|
||||
{
|
||||
TextEncoding = encoding;
|
||||
this.language = language;
|
||||
Description = description;
|
||||
Type = type;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="SynchronisedLyricsFrame" /> with a specified
|
||||
/// description, ISO-639-2 language code, and text type.
|
||||
/// </summary>
|
||||
/// <param name="description">
|
||||
/// A <see cref="string" /> object containing the description
|
||||
/// of the new instnace.
|
||||
/// </param>
|
||||
/// <param name="language">
|
||||
/// A <see cref="string" /> object containing the ISO-639-2
|
||||
/// language code of the new instance.
|
||||
/// </param>
|
||||
/// <param name="type">
|
||||
/// A <see cref="SynchedTextType" /> containing the type of
|
||||
/// text to be stored in the new instance.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// When a frame is created, it is not automatically added to
|
||||
/// the tag. Consider using <see cref="Get" /> for more
|
||||
/// integrated frame creation.
|
||||
/// </remarks>
|
||||
public SynchronisedLyricsFrame (string description, string language, SynchedTextType type)
|
||||
: this (description, language, type, Tag.DefaultEncoding)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="SynchronisedLyricsFrame" /> by reading its raw data
|
||||
/// in a specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object starting with the raw
|
||||
/// representation of the new instance.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
public SynchronisedLyricsFrame (ByteVector data, byte version)
|
||||
: base (data, version)
|
||||
{
|
||||
SetData (data, 0, version, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="SynchronisedLyricsFrame" /> by reading its raw data
|
||||
/// in a specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the raw
|
||||
/// representation of the new instance.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// A <see cref="int" /> indicating at what offset in
|
||||
/// <paramref name="data" /> the frame actually begins.
|
||||
/// </param>
|
||||
/// <param name="header">
|
||||
/// A <see cref="FrameHeader" /> containing the header of the
|
||||
/// frame found at <paramref name="offset" /> in the data.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
protected internal SynchronisedLyricsFrame (ByteVector data, int offset, FrameHeader header, byte version)
|
||||
: base (header)
|
||||
{
|
||||
SetData (data, offset, version, false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the text encoding to use when storing the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> containing the text encoding to
|
||||
/// use when storing the current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// This encoding is overridden when rendering if <see
|
||||
/// cref="Tag.ForceDefaultEncoding" /> is <see
|
||||
/// langword="true" /> or the render version does not support
|
||||
/// it.
|
||||
/// </remarks>
|
||||
public StringType TextEncoding { get; set; } = Tag.DefaultEncoding;
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the ISO-639-2 language code stored in the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> containing the ISO-639-2 language
|
||||
/// code stored in the current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// There should only be one frame with a matching
|
||||
/// description, type, and ISO-639-2 language code per tag.
|
||||
/// </remarks>
|
||||
public string Language {
|
||||
get {
|
||||
return (language != null && language.Length > 2)
|
||||
? language.Substring (0, 3) : "XXX";
|
||||
}
|
||||
set { language = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the description stored in the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> containing the description
|
||||
/// stored in the current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// There should only be one frame with a matching
|
||||
/// description, type, and ISO-639-2 language code per tag.
|
||||
/// </remarks>
|
||||
public string Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the timestamp format used by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TimestampFormat" /> value describing the
|
||||
/// timestamp format used by the current instance.
|
||||
/// </value>
|
||||
public TimestampFormat Format { get; set; } = TimestampFormat.Unknown;
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the type of text contained in the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TimestampFormat" /> value describing the
|
||||
/// type of text contained in the current instance.
|
||||
/// </value>
|
||||
public SynchedTextType Type { get; set; } = SynchedTextType.Other;
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the text contained in the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="T:SynchedText[]" /> containing the text
|
||||
/// contained in the current instance.
|
||||
/// </value>
|
||||
public SynchedText[] Text {
|
||||
get { return text; }
|
||||
set { text = value ?? (new SynchedText[0]); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Static Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a specified lyrics frame from the specified tag,
|
||||
/// optionally creating it if it does not exist.
|
||||
/// </summary>
|
||||
/// <param name="tag">
|
||||
/// A <see cref="Tag" /> object to search in.
|
||||
/// </param>
|
||||
/// <param name="description">
|
||||
/// A <see cref="string" /> object specifying the description
|
||||
/// to match.
|
||||
/// </param>
|
||||
/// <param name="language">
|
||||
/// A <see cref="string" /> object specifying the ISO-639-2
|
||||
/// language code to match.
|
||||
/// </param>
|
||||
/// <param name="type">
|
||||
/// A <see cref="SynchedTextType" /> value specifying the
|
||||
/// text type to match.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> specifying whether or not to create
|
||||
/// and add a new frame to the tag if a match is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="SynchronisedLyricsFrame" /> object
|
||||
/// containing the matching frame, or <see langword="null" />
|
||||
/// if a match wasn't found and <paramref name="create" /> is
|
||||
/// <see langword="false" />.
|
||||
/// </returns>
|
||||
public static SynchronisedLyricsFrame Get (Tag tag, string description, string language, SynchedTextType type, bool create)
|
||||
{
|
||||
foreach (Frame f in tag) {
|
||||
if (!(f is SynchronisedLyricsFrame lyr))
|
||||
continue;
|
||||
|
||||
if (lyr.Description == description &&
|
||||
(language == null ||
|
||||
language == lyr.Language) &&
|
||||
type == lyr.Type)
|
||||
return lyr;
|
||||
}
|
||||
|
||||
if (!create)
|
||||
return null;
|
||||
|
||||
var frame = new SynchronisedLyricsFrame (description, language, type);
|
||||
tag.AddFrame (frame);
|
||||
return frame;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a specified lyrics frame from the specified tag,
|
||||
/// trying to to match the description and language but
|
||||
/// accepting an incomplete match.
|
||||
/// </summary>
|
||||
/// <param name="tag">
|
||||
/// A <see cref="Tag" /> object to search in.
|
||||
/// </param>
|
||||
/// <param name="description">
|
||||
/// A <see cref="string" /> object specifying the description
|
||||
/// to match.
|
||||
/// </param>
|
||||
/// <param name="language">
|
||||
/// A <see cref="string" /> object specifying the ISO-639-2
|
||||
/// language code to match.
|
||||
/// </param>
|
||||
/// <param name="type">
|
||||
/// A <see cref="SynchedTextType" /> value specifying the
|
||||
/// text type to match.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="SynchronisedLyricsFrame" /> object
|
||||
/// containing the matching frame, or <see langword="null" />
|
||||
/// if a match wasn't found.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// <para>The method tries matching with the following order
|
||||
/// of precidence:</para>
|
||||
/// <list type="number">
|
||||
/// <item><term>The first frame with a matching
|
||||
/// description, language, and type.</term></item>
|
||||
/// <item><term>The first frame with a matching
|
||||
/// description and language.</term></item>
|
||||
/// <item><term>The first frame with a matching
|
||||
/// language.</term></item>
|
||||
/// <item><term>The first frame with a matching
|
||||
/// description.</term></item>
|
||||
/// <item><term>The first frame with a matching
|
||||
/// type.</term></item>
|
||||
/// <item><term>The first frame.</term></item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
public static SynchronisedLyricsFrame GetPreferred (Tag tag, string description, string language, SynchedTextType type)
|
||||
{
|
||||
// This is weird, so bear with me. The best thing we can
|
||||
// have is something straightforward and in our own
|
||||
// language. If it has a description, then it is
|
||||
// probably used for something other than an actual
|
||||
// comment. If that doesn't work, we'd still rather have
|
||||
// something in our language than something in another.
|
||||
// After that all we have left are things in other
|
||||
// languages, so we'd rather have one with actual
|
||||
// content, so we try to get one with no description
|
||||
// first.
|
||||
|
||||
int best_value = -1;
|
||||
SynchronisedLyricsFrame best_frame = null;
|
||||
|
||||
foreach (Frame f in tag) {
|
||||
if (!(f is SynchronisedLyricsFrame cf))
|
||||
continue;
|
||||
|
||||
int value = 0;
|
||||
if (cf.Language == language)
|
||||
value += 4;
|
||||
if (cf.Description == description)
|
||||
value += 2;
|
||||
if (cf.Type == type)
|
||||
value += 1;
|
||||
|
||||
if (value == 7)
|
||||
return cf;
|
||||
|
||||
if (value <= best_value)
|
||||
continue;
|
||||
|
||||
best_value = value;
|
||||
best_frame = cf;
|
||||
}
|
||||
|
||||
return best_frame;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <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 override void ParseFields (ByteVector data, byte version)
|
||||
{
|
||||
if (data.Count < 6)
|
||||
throw new CorruptFileException ("Not enough bytes in field.");
|
||||
|
||||
TextEncoding = (StringType)data[0];
|
||||
language = data.ToString (StringType.Latin1, 1, 3);
|
||||
Format = (TimestampFormat)data[4];
|
||||
Type = (SynchedTextType)data[5];
|
||||
|
||||
var delim = ByteVector.TextDelimiter (TextEncoding);
|
||||
int delim_index = data.Find (delim, 6, delim.Count);
|
||||
|
||||
if (delim_index < 0)
|
||||
throw new CorruptFileException ("Text delimiter expected.");
|
||||
|
||||
Description = data.ToString (TextEncoding, 6, delim_index - 6);
|
||||
|
||||
int offset = delim_index + delim.Count;
|
||||
var l = new List<SynchedText> ();
|
||||
|
||||
while (offset + delim.Count + 4 < data.Count) {
|
||||
delim_index = data.Find (delim, offset, delim.Count);
|
||||
|
||||
if (delim_index < offset)
|
||||
throw new CorruptFileException ("Text delimiter expected.");
|
||||
|
||||
string text = data.ToString (TextEncoding, offset, delim_index - offset);
|
||||
offset = delim_index + delim.Count;
|
||||
|
||||
if (offset + 4 > data.Count)
|
||||
break;
|
||||
|
||||
l.Add (new SynchedText (data.Mid (offset, 4).ToUInt (), text));
|
||||
offset += 4;
|
||||
}
|
||||
|
||||
this.text = l.ToArray ();
|
||||
}
|
||||
|
||||
/// <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 override ByteVector RenderFields (byte version)
|
||||
{
|
||||
var encoding = CorrectEncoding (TextEncoding, version);
|
||||
var delim = ByteVector.TextDelimiter (encoding);
|
||||
var v = new ByteVector {
|
||||
(byte)encoding,
|
||||
ByteVector.FromString (Language, StringType.Latin1),
|
||||
(byte)Format,
|
||||
(byte)Type,
|
||||
ByteVector.FromString (Description, encoding),
|
||||
delim
|
||||
};
|
||||
|
||||
foreach (SynchedText t in text) {
|
||||
v.Add (ByteVector.FromString (t.Text, encoding));
|
||||
v.Add (delim);
|
||||
v.Add (ByteVector.FromUInt ((uint)t.Time));
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
#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>
|
||||
public override Frame Clone ()
|
||||
{
|
||||
var frame = new SynchronisedLyricsFrame (Description, language, Type, TextEncoding) {
|
||||
Format = Format,
|
||||
text = (SynchedText[])text.Clone ()
|
||||
};
|
||||
return frame;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This structure contains a single entry in a <see
|
||||
/// cref="SynchronisedLyricsFrame" /> object.
|
||||
/// </summary>
|
||||
public struct SynchedText
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="SynchedText" /> with a specified time and text.
|
||||
/// </summary>
|
||||
/// <param name="time">
|
||||
/// A <see cref="long" /> value representing an amount of
|
||||
/// time in a format define in the class using it. The
|
||||
/// specific format is specified in <see
|
||||
/// cref="SynchronisedLyricsFrame.Format" />.
|
||||
/// </param>
|
||||
/// <param name="text">
|
||||
/// A <see cref="string" /> object containing the text
|
||||
/// for the point in time.
|
||||
/// </param>
|
||||
public SynchedText (long time, string text)
|
||||
{
|
||||
Time = time;
|
||||
Text = text;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the time offset of the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="long" /> value representing an amount of
|
||||
/// time in a format define in the class using it. The
|
||||
/// specific format is specified in <see
|
||||
/// cref="SynchronisedLyricsFrame.Format" />.
|
||||
/// </value>
|
||||
public long Time { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the text for the point in time represented
|
||||
/// by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing the text
|
||||
/// for the point in time.
|
||||
/// </value>
|
||||
public string Text { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1690a32df7e6754bc8de435b544cf336
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,296 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TagLib.Id3v2
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Frame" /> to provide support for
|
||||
/// Table of Contents Frames, i.e. "<c>CTOC</c>",
|
||||
/// (ID3v2 Chapter Frame Addendum 1.0, https://id3.org/id3v2-chapters-1.0).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The <see cref="TableOfContentsFrame"/> is special in that it can hold
|
||||
/// an arbitrary amount of sub-frames, which are made available here as a
|
||||
/// List of <see cref="Frame"/>s in the property <see cref="SubFrames"/>.
|
||||
///
|
||||
/// A tag may contain multiple <see cref="TableOfContentsFrame"/>s, there
|
||||
/// may however be only one top-level "<c>CTOC</c>" as stated by the
|
||||
/// property <see cref="IsTopLevel"/>.
|
||||
///
|
||||
/// Each <see cref="TableOfContentsFrame"/> must have an identifying string
|
||||
/// that is unique across all <see cref="TableOfContentsFrame"/>s and
|
||||
/// <see cref="ChapterFrame"/>s in the tag. This is the <see cref="Id"/>
|
||||
/// property. It is not intended for humans and players will not display it.
|
||||
/// For humans, add a "<c>TIT2</c>" <see cref="TextInformationFrame"/>.
|
||||
/// </remarks>
|
||||
public class TableOfContentsFrame : Frame
|
||||
{
|
||||
[System.Flags]
|
||||
private enum CTOCFlags : byte
|
||||
{
|
||||
TopLevel = 1,
|
||||
Ordered = 2
|
||||
}
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new empty instance of <see
|
||||
/// cref="TableOfContentsFrame" />.
|
||||
/// </summary>
|
||||
public TableOfContentsFrame ()
|
||||
: base (FrameType.CTOC, 4)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new empty instance of <see
|
||||
/// cref="TableOfContentsFrame" /> with the given TOC Id.
|
||||
/// </summary>
|
||||
public TableOfContentsFrame(string id)
|
||||
: this()
|
||||
{
|
||||
Id = id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="TableOfContentsFrame" /> with the given TOC Id
|
||||
/// and adds a TIT2 <see cref="TextInformationFrame"/>
|
||||
/// with the given title.
|
||||
/// </summary>
|
||||
public TableOfContentsFrame(string id, string title)
|
||||
: this(id)
|
||||
{
|
||||
SubFrames.Add(new TextInformationFrame("TIT2") { Text = new[] { title } });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="TableOfContentsFrame" /> by reading its raw data in
|
||||
/// a specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object starting with the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
public TableOfContentsFrame (ByteVector data, byte version)
|
||||
: base (data, version)
|
||||
{
|
||||
SetData (data, 0, version, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="TableOfContentsFrame" /> by reading its raw data in a
|
||||
/// specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// A <see cref="int" /> indicating at what offset in
|
||||
/// <paramref name="data" /> the frame actually begins.
|
||||
/// </param>
|
||||
/// <param name="header">
|
||||
/// A <see cref="FrameHeader" /> containing the header of the
|
||||
/// frame found at <paramref name="offset" /> in the data.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
protected internal TableOfContentsFrame (ByteVector data, int offset, FrameHeader header, byte version)
|
||||
: base (header)
|
||||
{
|
||||
SetData (data, offset, version, false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the internal table of contents id.
|
||||
/// This should be <see cref="StringType.Latin1" />
|
||||
/// and must be unique with respect to any other
|
||||
/// "<c>CTOC</c>" or "<c>CHAP</c>" frame in the tag.
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the boolean stating that this is the root
|
||||
/// of all "<c>CTOC</c>"s. As such there must be only one
|
||||
/// "<c>CTOC</c>" with this set to true.
|
||||
/// </summary>
|
||||
public bool IsTopLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the boolean stating that this table of
|
||||
/// contents’ chapters should be played in order.
|
||||
/// </summary>
|
||||
public bool IsOrdered { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the list of chapters in this table of contents
|
||||
/// identified by their <see cref="ChapterFrame.Id"/>s.
|
||||
/// Because the number of chapters is stored in this frame using
|
||||
/// only one byte for parsing purposes, this should not contain
|
||||
/// more than 255 chapters.
|
||||
/// </summary>
|
||||
public List<string> ChapterIds { get; set; } = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the descriptive sub-fields for this chapter. It
|
||||
/// is recommended by the spec to have at least a "<c>TIT2</c>"
|
||||
/// <see cref="TextInformationFrame"/> with the chapter title, but
|
||||
/// it can contain anything.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A List of arbitrary <see cref="Frame" />s.
|
||||
/// </value>
|
||||
public List<Frame> SubFrames { get; set; } = new List<Frame>();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <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 override void ParseFields (ByteVector data, byte version)
|
||||
{
|
||||
// https://id3.org/id3v2-chapters-1.0
|
||||
|
||||
int idLength = data.IndexOf((byte)0) + 1;
|
||||
Id = data.ToString(StringType.Latin1, 0, idLength - 1);
|
||||
|
||||
var flags = (CTOCFlags)data[idLength]; //Flags %000000ab Entry count $xx (8-bit unsigned int)
|
||||
IsTopLevel = flags.HasFlag(CTOCFlags.TopLevel); //a
|
||||
IsOrdered = flags.HasFlag(CTOCFlags.Ordered); //b
|
||||
|
||||
var chapterCount = data[idLength + 1]; //Entry count $xx (8-bit unsigned int)
|
||||
|
||||
if (data.Count <= idLength + 2)
|
||||
return; //no chapter ids and no subframes
|
||||
|
||||
/* Get chapter ids according to the chapterCount byte.
|
||||
* Anything left after that should be subframes.
|
||||
* TODO: If there are more chapters than fit inside
|
||||
* the chapterCount byte, I guess the file is malformed?
|
||||
*/
|
||||
int position = idLength + 2;
|
||||
for (int i = 0; i < chapterCount; i++)
|
||||
{
|
||||
int nextPosition = data.Find((byte)0, position) + 1;
|
||||
ChapterIds.Add(data.Mid(position, nextPosition-position-1).ToString(StringType.Latin1));
|
||||
position = nextPosition;
|
||||
}
|
||||
|
||||
SubFrames = new List<Frame>();
|
||||
int frame_data_endposition = data.Count;
|
||||
while (position < frame_data_endposition)
|
||||
{
|
||||
Frame frame;
|
||||
try
|
||||
{
|
||||
frame = FrameFactory.CreateFrame(data, null, ref position, version, true /* ? */);
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
catch (CorruptFileException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
if (frame == null)
|
||||
break;
|
||||
|
||||
// Only add frames that contain data.
|
||||
if (frame.Size == 0)
|
||||
continue;
|
||||
|
||||
SubFrames.Add(frame);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 override ByteVector RenderFields (byte version)
|
||||
{
|
||||
var data = ByteVector.FromString(Id, StringType.Latin1);
|
||||
data.Add((byte)0);
|
||||
data.Add((byte)((IsTopLevel ? CTOCFlags.TopLevel : 0) | (IsOrdered ? CTOCFlags.Ordered : 0)));
|
||||
data.Add(ChapterIds.Count >= byte.MaxValue ? byte.MaxValue /*TODO: throw?*/ : (byte)ChapterIds.Count);
|
||||
|
||||
foreach(var chap in ChapterIds)
|
||||
{
|
||||
data.Add(ByteVector.FromString(chap, StringType.Latin1));
|
||||
data.Add((byte)0);
|
||||
}
|
||||
|
||||
foreach (var f in SubFrames)
|
||||
data.Add(f.Render(version));
|
||||
|
||||
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>
|
||||
public override Frame Clone()
|
||||
{
|
||||
var frame = new TableOfContentsFrame(Id);
|
||||
frame.IsTopLevel = IsTopLevel;
|
||||
frame.IsOrdered = IsOrdered;
|
||||
|
||||
foreach (var c in ChapterIds)
|
||||
frame.ChapterIds.Add(c);
|
||||
|
||||
foreach (var f in SubFrames)
|
||||
frame.SubFrames.Add(f.Clone());
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 248bc416286076e6f8cdf2c73222fa1e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,360 @@
|
||||
//
|
||||
// TermsOfUseFrame.cs:
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 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
|
||||
//
|
||||
|
||||
namespace TagLib.Id3v2
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Frame" />, implementing support for
|
||||
/// ID3v2 Terms of Use (USER) Frames.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This frame contains license text or restrictions on the use of a
|
||||
/// media file.
|
||||
/// </remarks>
|
||||
public class TermsOfUseFrame : Frame
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the ISO-639-2 language code of the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
string language;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and intializes a new instance of <see
|
||||
/// cref="TermsOfUseFrame" /> with a specified language and
|
||||
/// encoding.
|
||||
/// </summary>
|
||||
/// <param name="language">
|
||||
/// A <see cref="string" /> containing the ISO-639-2 language
|
||||
/// code of the new frame.
|
||||
/// </param>
|
||||
/// <param name="encoding">
|
||||
/// A <see cref="StringType" /> containing the text encoding
|
||||
/// to use when rendering the new frame.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// When a frame is created, it is not automatically added to
|
||||
/// the tag. Consider using <see cref="Get" /> for more
|
||||
/// integrated frame creation.
|
||||
/// </remarks>
|
||||
public TermsOfUseFrame (string language, StringType encoding)
|
||||
: base (FrameType.USER, 4)
|
||||
{
|
||||
TextEncoding = encoding;
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and intializes a new instance of <see
|
||||
/// cref="TermsOfUseFrame" /> with a specified language.
|
||||
/// </summary>
|
||||
/// <param name="language">
|
||||
/// A <see cref="string" /> containing the ISO-639-2 language
|
||||
/// code of the new frame.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// When a frame is created, it is not automatically added to
|
||||
/// the tag. Consider using <see cref="Get" /> for more
|
||||
/// integrated frame creation.
|
||||
/// </remarks>
|
||||
public TermsOfUseFrame (string language)
|
||||
: base (FrameType.USER, 4)
|
||||
{
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="TermsOfUseFrame" /> by reading its raw data in a
|
||||
/// specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object starting with the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
public TermsOfUseFrame (ByteVector data, byte version)
|
||||
: base (data, version)
|
||||
{
|
||||
SetData (data, 0, version, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="TermsOfUseFrame" /> by reading its raw data in a
|
||||
/// specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// A <see cref="int" /> indicating at what offset in
|
||||
/// <paramref name="data" /> the frame actually begins.
|
||||
/// </param>
|
||||
/// <param name="header">
|
||||
/// A <see cref="FrameHeader" /> containing the header of the
|
||||
/// frame found at <paramref name="offset" /> in the data.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
protected internal TermsOfUseFrame (ByteVector data, int offset, FrameHeader header, byte version)
|
||||
: base (header)
|
||||
{
|
||||
SetData (data, offset, version, false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the text encoding to use when storing the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> containing the text encoding to
|
||||
/// use when storing the current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// This encoding is overridden when rendering if <see
|
||||
/// cref="Tag.ForceDefaultEncoding" /> is <see
|
||||
/// langword="true" /> or the render version does not support
|
||||
/// it.
|
||||
/// </remarks>
|
||||
public StringType TextEncoding { get; set; } = Tag.DefaultEncoding;
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the ISO-639-2 language code stored in the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> containing the ISO-639-2 language
|
||||
/// code stored in the current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// There should only be one file with a matching
|
||||
/// ISO-639-2 language code per tag.
|
||||
/// </remarks>
|
||||
public string Language {
|
||||
get {
|
||||
return (language != null && language.Length > 2)
|
||||
? language.Substring (0, 3) : "XXX";
|
||||
}
|
||||
set { language = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the terms of use stored in the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing the terms of
|
||||
/// use.
|
||||
/// </value>
|
||||
public string Text { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string representation of the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="string" /> containing the terms of use.
|
||||
/// </returns>
|
||||
public override string ToString ()
|
||||
{
|
||||
return Text;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Static Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a specified terms of use frame from the specified
|
||||
/// tag, optionally creating it if it does not exist.
|
||||
/// </summary>
|
||||
/// <param name="tag">
|
||||
/// A <see cref="Tag" /> object to search in.
|
||||
/// </param>
|
||||
/// <param name="language">
|
||||
/// A <see cref="string" /> specifying the ISO-639-2 language
|
||||
/// code to match.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> specifying whether or not to create
|
||||
/// and add a new frame to the tag if a match is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="TermsOfUseFrame" /> object containing the
|
||||
/// matching frame, or <see langword="null" /> if a match
|
||||
/// wasn't found and <paramref name="create" /> is <see
|
||||
/// langword="false" />.
|
||||
/// </returns>
|
||||
public static TermsOfUseFrame Get (Tag tag, string language, bool create)
|
||||
{
|
||||
foreach (Frame f in tag.GetFrames (FrameType.USER)) {
|
||||
if (f is TermsOfUseFrame cf && (language == null || language == cf.Language))
|
||||
return cf;
|
||||
}
|
||||
|
||||
if (!create)
|
||||
return null;
|
||||
|
||||
var frame = new TermsOfUseFrame (language);
|
||||
tag.AddFrame (frame);
|
||||
return frame;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a specified terms of use frame from the specified
|
||||
/// tag, trying to to match the language but accepting one
|
||||
/// with a different language if a match was not found.
|
||||
/// </summary>
|
||||
/// <param name="tag">
|
||||
/// A <see cref="Tag" /> object to search in.
|
||||
/// </param>
|
||||
/// <param name="language">
|
||||
/// A <see cref="string" /> specifying the ISO-639-2 language
|
||||
/// code to match.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="TermsOfUseFrame" /> object containing the
|
||||
/// matching frame, or <see langword="null" /> if a match
|
||||
/// wasn't found.
|
||||
/// </returns>
|
||||
public static TermsOfUseFrame GetPreferred (Tag tag, string language)
|
||||
{
|
||||
TermsOfUseFrame best = null;
|
||||
foreach (Frame f in tag.GetFrames (FrameType.USER)) {
|
||||
if (!(f is TermsOfUseFrame cf))
|
||||
continue;
|
||||
|
||||
if (cf.Language == language)
|
||||
return cf;
|
||||
|
||||
if (best == null)
|
||||
best = cf;
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <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 override void ParseFields (ByteVector data, byte version)
|
||||
{
|
||||
if (data.Count < 4)
|
||||
throw new CorruptFileException ("Not enough bytes in field.");
|
||||
|
||||
TextEncoding = (StringType)data[0];
|
||||
language = data.ToString (StringType.Latin1, 1, 3);
|
||||
Text = data.ToString (TextEncoding, 4, data.Count - 4);
|
||||
}
|
||||
|
||||
/// <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 override ByteVector RenderFields (byte version)
|
||||
{
|
||||
var encoding = CorrectEncoding (TextEncoding, version);
|
||||
var v = new ByteVector {
|
||||
(byte)encoding,
|
||||
ByteVector.FromString (Language,
|
||||
StringType.Latin1),
|
||||
ByteVector.FromString (Text, encoding)
|
||||
};
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
#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>
|
||||
public override Frame Clone ()
|
||||
{
|
||||
var frame = new TermsOfUseFrame (language, TextEncoding) {
|
||||
Text = Text
|
||||
};
|
||||
return frame;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cf81525ecc14023b38c3de1b72eabc92
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a11b4e4eb62ab7553a18ead87ecb069f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,295 @@
|
||||
//
|
||||
// UniqueFileIdentifierFrame.cs:
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Original Source:
|
||||
// uniquefileidentifierframe.cpp from TagLib
|
||||
//
|
||||
// Copyright (C) 2005-2007 Brian Nickel
|
||||
// Copyright (C) 2004 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 class extends <see cref="Frame" />, implementing support for
|
||||
/// ID3v2 Unique File Identifier (UFID) Frames.
|
||||
/// </summary>
|
||||
public class UniqueFileIdentifierFrame : Frame
|
||||
{
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="UniqueFileIdentifierFrame" /> with a specified
|
||||
/// owner and identifier data.
|
||||
/// </summary>
|
||||
/// <param name="owner">
|
||||
/// A <see cref="string" /> containing the owner of the new
|
||||
/// frame.
|
||||
/// </param>
|
||||
/// <param name="identifier">
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// identifier for the new frame.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// When a frame is created, it is not automatically added to
|
||||
/// the tag. Consider using <see
|
||||
/// cref="Get(Tag,string,bool)" /> for more integrated frame
|
||||
/// creation.
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="owner" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public UniqueFileIdentifierFrame (string owner, ByteVector identifier)
|
||||
: base (FrameType.UFID, 4)
|
||||
{
|
||||
if (owner == null)
|
||||
throw new ArgumentNullException (nameof (owner));
|
||||
|
||||
Owner = owner;
|
||||
Identifier = identifier;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="UniqueFileIdentifierFrame" /> with a specified
|
||||
/// owner.
|
||||
/// </summary>
|
||||
/// <param name="owner">
|
||||
/// A <see cref="string" /> containing the owner of the new
|
||||
/// frame.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// When a frame is created, it is not automatically added to
|
||||
/// the tag. Consider using <see
|
||||
/// cref="Get(Tag,string,bool)" /> for more integrated frame
|
||||
/// creation.
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="owner" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public UniqueFileIdentifierFrame (string owner)
|
||||
: this (owner, null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="UniqueFileIdentifierFrame" /> by reading its raw
|
||||
/// data in a specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object starting with the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
public UniqueFileIdentifierFrame (ByteVector data, byte version)
|
||||
: base (data, version)
|
||||
{
|
||||
SetData (data, 0, version, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="UniqueFileIdentifierFrame" /> by reading its raw
|
||||
/// data in a specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// A <see cref="int" /> indicating at what offset in
|
||||
/// <paramref name="data" /> the frame actually begins.
|
||||
/// </param>
|
||||
/// <param name="header">
|
||||
/// A <see cref="FrameHeader" /> containing the header of the
|
||||
/// frame found at <paramref name="offset" /> in the data.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
protected internal UniqueFileIdentifierFrame (ByteVector data, int offset, FrameHeader header, byte version)
|
||||
: base (header)
|
||||
{
|
||||
SetData (data, offset, version, false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the owner of the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> containing the owner of the
|
||||
/// current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// There should only be one frame with a matching owner per
|
||||
/// tag.
|
||||
/// </remarks>
|
||||
public string Owner { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the identifier data stored in the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ByteVector" /> object containiner the unique
|
||||
/// file identifier frame.
|
||||
/// </value>
|
||||
public ByteVector Identifier { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Static Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a specified unique file identifer frame from the
|
||||
/// specified tag, optionally creating it if it does not
|
||||
/// exist.
|
||||
/// </summary>
|
||||
/// <param name="tag">
|
||||
/// A <see cref="Tag" /> object to search in.
|
||||
/// </param>
|
||||
/// <param name="owner">
|
||||
/// A <see cref="string" /> specifying the owner to match.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> specifying whether or not to create
|
||||
/// and add a new frame to the tag if a match is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="UserTextInformationFrame" /> object
|
||||
/// containing the matching frame, or <see langword="null" />
|
||||
/// if a match wasn't found and <paramref name="create" /> is
|
||||
/// <see langword="false" />.
|
||||
/// </returns>
|
||||
public static UniqueFileIdentifierFrame Get (Tag tag, string owner, bool create)
|
||||
{
|
||||
UniqueFileIdentifierFrame ufid;
|
||||
|
||||
foreach (Frame frame in tag.GetFrames (FrameType.UFID)) {
|
||||
ufid = frame as UniqueFileIdentifierFrame;
|
||||
|
||||
if (ufid == null)
|
||||
continue;
|
||||
|
||||
if (ufid.Owner == owner)
|
||||
return ufid;
|
||||
}
|
||||
|
||||
if (!create)
|
||||
return null;
|
||||
|
||||
ufid = new UniqueFileIdentifierFrame (owner, null);
|
||||
tag.AddFrame (ufid);
|
||||
return ufid;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <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 override void ParseFields (ByteVector data, byte version)
|
||||
{
|
||||
var fields = ByteVectorCollection.Split (data, (byte)0);
|
||||
|
||||
if (fields.Count != 2)
|
||||
return;
|
||||
|
||||
Owner = fields[0].ToString (StringType.Latin1);
|
||||
Identifier = fields[1];
|
||||
}
|
||||
|
||||
/// <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 override ByteVector RenderFields (byte version)
|
||||
{
|
||||
var data = new ByteVector {
|
||||
ByteVector.FromString (Owner, StringType.Latin1),
|
||||
ByteVector.TextDelimiter (StringType.Latin1),
|
||||
Identifier
|
||||
};
|
||||
|
||||
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>
|
||||
public override Frame Clone ()
|
||||
{
|
||||
var frame = new UniqueFileIdentifierFrame (Owner);
|
||||
if (Identifier != null)
|
||||
frame.Identifier = new ByteVector (Identifier);
|
||||
return frame;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0beadc8383b3d20b78515794a0f1e05b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,169 @@
|
||||
//
|
||||
// UnknownFrame.cs:
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Original Source:
|
||||
// unknownframe.cpp from TagLib
|
||||
//
|
||||
// Copyright (C) 2005-2007 Brian Nickel
|
||||
// Copyright (C) 2002 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
|
||||
//
|
||||
|
||||
namespace TagLib.Id3v2
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Frame" /> to provide a fallback
|
||||
/// type when no other frame class works for a given frame.
|
||||
/// </summary>
|
||||
public class UnknownFrame : Frame
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="UnknownFrame" /> with a specified type.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="ByteVector" /> object containing an ID3v2.4
|
||||
/// frame identifier.
|
||||
/// </param>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector"/> object containing the contents
|
||||
/// of the frame.
|
||||
/// </param>
|
||||
public UnknownFrame (ByteVector type, ByteVector data)
|
||||
: base (type, 4)
|
||||
{
|
||||
Data = data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="UnknownFrame" /> with a specified type.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="ByteVector" /> object containing an ID3v2.4
|
||||
/// frame identifier.
|
||||
/// </param>
|
||||
public UnknownFrame (ByteVector type) : this (type, null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="UnknownFrame" /> by reading its raw data in a
|
||||
/// specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object starting with the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
public UnknownFrame (ByteVector data, byte version)
|
||||
: base (data, version)
|
||||
{
|
||||
SetData (data, 0, version, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="UnknownFrame" /> by reading its raw data in a
|
||||
/// specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// A <see cref="int" /> indicating at what offset in
|
||||
/// <paramref name="data" /> the frame actually begins.
|
||||
/// </param>
|
||||
/// <param name="header">
|
||||
/// A <see cref="FrameHeader" /> containing the header of the
|
||||
/// frame found at <paramref name="offset" /> in the data.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
protected internal UnknownFrame (ByteVector data, int offset, FrameHeader header, byte version)
|
||||
: base (header)
|
||||
{
|
||||
SetData (data, offset, version, false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the field data in the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ByteVector" /> containing the field data.
|
||||
/// </value>
|
||||
public ByteVector Data { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <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 override void ParseFields (ByteVector data, byte version)
|
||||
{
|
||||
Data = data;
|
||||
}
|
||||
|
||||
/// <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 override ByteVector RenderFields (byte version)
|
||||
{
|
||||
return Data ?? new ByteVector ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 53f93e0eaec8ec939b970f8d2ebd3cd1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,497 @@
|
||||
//
|
||||
// UnsynchronisedLyricsFrame.cs:
|
||||
//
|
||||
// Author:
|
||||
// Patrick Laplante
|
||||
//
|
||||
// Original Source:
|
||||
// TagLib.Id3v2.CommentsFrame
|
||||
//
|
||||
// Copyright (C) 2007 Brian Nickel (Original Implementation)
|
||||
// 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
|
||||
//
|
||||
|
||||
namespace TagLib.Id3v2
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Frame" />, implementing support for
|
||||
/// ID3v2 Unsynchronised Lyrics (USLT) Frames.
|
||||
/// </summary>
|
||||
public class UnsynchronisedLyricsFrame : Frame
|
||||
{
|
||||
#region Private Properties
|
||||
|
||||
/// <summary>
|
||||
/// Contains the ISO-639-2 language code of the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
string language;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the description of the current instance.
|
||||
/// </summary>
|
||||
string description;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the lyrics text of the current instance.
|
||||
/// </summary>
|
||||
string text;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="UnsynchronisedLyricsFrame" /> with a specified
|
||||
/// description, ISO-639-2 language code, and text encoding.
|
||||
/// </summary>
|
||||
/// <param name="description">
|
||||
/// A <see cref="string" /> containing the description of the
|
||||
/// new frame.
|
||||
/// </param>
|
||||
/// <param name="language">
|
||||
/// A <see cref="string" /> containing the ISO-639-2 language
|
||||
/// code of the new frame.
|
||||
/// </param>
|
||||
/// <param name="encoding">
|
||||
/// A <see cref="StringType" /> containing the text encoding
|
||||
/// to use when rendering the new frame.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// When a frame is created, it is not automatically added to
|
||||
/// the tag. Consider using <see cref="Get" /> for more
|
||||
/// integrated frame creation.
|
||||
/// </remarks>
|
||||
public UnsynchronisedLyricsFrame (string description, string language, StringType encoding)
|
||||
: base (FrameType.USLT, 4)
|
||||
{
|
||||
TextEncoding = encoding;
|
||||
this.language = language;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="UnsynchronisedLyricsFrame" /> with a specified
|
||||
/// description and ISO-639-2 language code.
|
||||
/// </summary>
|
||||
/// <param name="description">
|
||||
/// A <see cref="string" /> containing the description of the
|
||||
/// new frame.
|
||||
/// </param>
|
||||
/// <param name="language">
|
||||
/// A <see cref="string" /> containing the ISO-639-2 language
|
||||
/// code of the new frame.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// When a frame is created, it is not automatically added to
|
||||
/// the tag. Consider using <see cref="Get" /> for more
|
||||
/// integrated frame creation.
|
||||
/// </remarks>
|
||||
public UnsynchronisedLyricsFrame (string description, string language)
|
||||
: this (description, language, Tag.DefaultEncoding)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="UnsynchronisedLyricsFrame" /> with a specified
|
||||
/// description.
|
||||
/// </summary>
|
||||
/// <param name="description">
|
||||
/// A <see cref="string" /> containing the description of the
|
||||
/// new frame.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// When a frame is created, it is not automatically added to
|
||||
/// the tag. Consider using <see cref="Get" /> for more
|
||||
/// integrated frame creation.
|
||||
/// </remarks>
|
||||
public UnsynchronisedLyricsFrame (string description)
|
||||
: this (description, null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="UnsynchronisedLyricsFrame" /> by reading its raw
|
||||
/// data in a specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object starting with the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
public UnsynchronisedLyricsFrame (ByteVector data, byte version)
|
||||
: base (data, version)
|
||||
{
|
||||
SetData (data, 0, version, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="UnsynchronisedLyricsFrame" /> by reading its raw
|
||||
/// data in a specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// A <see cref="int" /> indicating at what offset in
|
||||
/// <paramref name="data" /> the frame actually begins.
|
||||
/// </param>
|
||||
/// <param name="header">
|
||||
/// A <see cref="FrameHeader" /> containing the header of the
|
||||
/// frame found at <paramref name="offset" /> in the data.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
protected internal UnsynchronisedLyricsFrame (ByteVector data, int offset, FrameHeader header, byte version)
|
||||
: base (header)
|
||||
{
|
||||
SetData (data, offset, version, false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the text encoding to use when storing the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> containing the text encoding to
|
||||
/// use when storing the current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// This encoding is overridden when rendering if <see
|
||||
/// cref="Tag.ForceDefaultEncoding" /> is <see
|
||||
/// langword="true" /> or the render version does not support
|
||||
/// it.
|
||||
/// </remarks>
|
||||
public StringType TextEncoding { get; set; } = Tag.DefaultEncoding;
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the ISO-639-2 language code stored in the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> containing the ISO-639-2 language
|
||||
/// code stored in the current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// There should only be one file with a matching description
|
||||
/// and ISO-639-2 language code per tag.
|
||||
/// </remarks>
|
||||
public string Language {
|
||||
get {
|
||||
if (language != null && language.Length > 2)
|
||||
return language.Substring (0, 3);
|
||||
|
||||
return "XXX";
|
||||
}
|
||||
set { language = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the description stored in the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> containing the description
|
||||
/// stored in the current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// There should only be one frame with a matching
|
||||
/// description and ISO-639-2 language code per tag.
|
||||
/// </remarks>
|
||||
public string Description {
|
||||
get {
|
||||
if (description != null)
|
||||
return description;
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
set { description = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the lyrical text stored in the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> containing the lyrical text
|
||||
/// stored in the current instance.
|
||||
/// </value>
|
||||
public string Text {
|
||||
get {
|
||||
if (text != null)
|
||||
return text;
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
set { text = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string representation of the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="string" /> containing the lyrical text.
|
||||
/// </returns>
|
||||
public override string ToString ()
|
||||
{
|
||||
return Text;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Static Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a specified lyrics frame from the specified tag,
|
||||
/// optionally creating it if it does not exist.
|
||||
/// </summary>
|
||||
/// <param name="tag">
|
||||
/// A <see cref="Tag" /> object to search in.
|
||||
/// </param>
|
||||
/// <param name="description">
|
||||
/// A <see cref="string" /> specifying the description to
|
||||
/// match.
|
||||
/// </param>
|
||||
/// <param name="language">
|
||||
/// A <see cref="string" /> specifying the ISO-639-2 language
|
||||
/// code to match.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> specifying whether or not to create
|
||||
/// and add a new frame to the tag if a match is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="UnsynchronisedLyricsFrame" /> object
|
||||
/// containing the matching frame, or <see langword="null" />
|
||||
/// if a match wasn't found and <paramref name="create" /> is
|
||||
/// <see langword="false" />.
|
||||
/// </returns>
|
||||
public static UnsynchronisedLyricsFrame Get (Tag tag, string description, string language, bool create)
|
||||
{
|
||||
UnsynchronisedLyricsFrame uslt;
|
||||
foreach (Frame frame in tag.GetFrames (FrameType.USLT)) {
|
||||
uslt = frame as UnsynchronisedLyricsFrame;
|
||||
|
||||
if (uslt == null)
|
||||
continue;
|
||||
|
||||
if (uslt.Description != description)
|
||||
continue;
|
||||
|
||||
if (language != null && language != uslt.Language)
|
||||
continue;
|
||||
|
||||
return uslt;
|
||||
}
|
||||
|
||||
if (!create)
|
||||
return null;
|
||||
|
||||
uslt = new UnsynchronisedLyricsFrame (description,
|
||||
language);
|
||||
tag.AddFrame (uslt);
|
||||
return uslt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a specified comments frame from the specified tag,
|
||||
/// trying to to match the description and language but
|
||||
/// accepting an incomplete match.
|
||||
/// </summary>
|
||||
/// <param name="tag">
|
||||
/// A <see cref="Tag" /> object to search in.
|
||||
/// </param>
|
||||
/// <param name="description">
|
||||
/// A <see cref="string" /> specifying the description to
|
||||
/// match.
|
||||
/// </param>
|
||||
/// <param name="language">
|
||||
/// A <see cref="string" /> specifying the ISO-639-2 language
|
||||
/// code to match.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="UnsynchronisedLyricsFrame" /> object
|
||||
/// containing the matching frame, or <see langword="null" />
|
||||
/// if a match wasn't found.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// <para>The method tries matching with the following order
|
||||
/// of precidence:</para>
|
||||
/// <list type="number">
|
||||
/// <item><term>The first frame with a matching
|
||||
/// description and language.</term></item>
|
||||
/// <item><term>The first frame with a matching
|
||||
/// language.</term></item>
|
||||
/// <item><term>The first frame with a matching
|
||||
/// description.</term></item>
|
||||
/// <item><term>The first frame.</term></item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
public static UnsynchronisedLyricsFrame GetPreferred (Tag tag, string description, string language)
|
||||
{
|
||||
// This is weird, so bear with me. The best thing we can
|
||||
// have is something straightforward and in our own
|
||||
// language. If it has a description, then it is
|
||||
// probably used for something other than an actual
|
||||
// comment. If that doesn't work, we'd still rather have
|
||||
// something in our language than something in another.
|
||||
// After that all we have left are things in other
|
||||
// languages, so we'd rather have one with actual
|
||||
// content, so we try to get one with no description
|
||||
// first.
|
||||
|
||||
int best_value = -1;
|
||||
UnsynchronisedLyricsFrame best_frame = null;
|
||||
|
||||
foreach (Frame frame in tag.GetFrames (FrameType.USLT)) {
|
||||
if (!(frame is UnsynchronisedLyricsFrame uslt))
|
||||
continue;
|
||||
|
||||
bool same_name = uslt.Description == description;
|
||||
bool same_lang = uslt.Language == language;
|
||||
|
||||
if (same_name && same_lang)
|
||||
return uslt;
|
||||
|
||||
int value = same_lang ? 2 : same_name ? 1 : 0;
|
||||
|
||||
if (value <= best_value)
|
||||
continue;
|
||||
|
||||
best_value = value;
|
||||
best_frame = uslt;
|
||||
}
|
||||
|
||||
return best_frame;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <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 override void ParseFields (ByteVector data, byte version)
|
||||
{
|
||||
if (data.Count < 4)
|
||||
throw new CorruptFileException ("Not enough bytes in field.");
|
||||
|
||||
TextEncoding = (StringType)data[0];
|
||||
language = data.ToString (StringType.Latin1, 1, 3);
|
||||
|
||||
string[] split = data.ToStrings (TextEncoding, 4, 2);
|
||||
|
||||
if (split.Length == 1) {
|
||||
// Bad lyrics frame. Assume that it lacks a
|
||||
// description.
|
||||
description = string.Empty;
|
||||
text = split[0];
|
||||
} else {
|
||||
description = split[0];
|
||||
text = split[1];
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 override ByteVector RenderFields (byte version)
|
||||
{
|
||||
var encoding = CorrectEncoding (TextEncoding, version);
|
||||
var v = new ByteVector {
|
||||
(byte)encoding,
|
||||
ByteVector.FromString (Language, StringType.Latin1),
|
||||
ByteVector.FromString (description, encoding),
|
||||
ByteVector.TextDelimiter (encoding),
|
||||
ByteVector.FromString (text, encoding)
|
||||
};
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
#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>
|
||||
public override Frame Clone ()
|
||||
{
|
||||
var frame = new UnsynchronisedLyricsFrame (description, language, TextEncoding) {
|
||||
text = text
|
||||
};
|
||||
return frame;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 855f521ea4c91ccaa9507a7f70cc8b4f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,768 @@
|
||||
//
|
||||
// UrlLinkFrame.cs: Provides support ID3v2 Url Link Frames
|
||||
// (Section 4.3.1), covering "W000" to "WZZZ", excluding "WXXX".
|
||||
//
|
||||
// Author:
|
||||
// Helmut Wahrmann
|
||||
//
|
||||
// Original Source:
|
||||
// textidentificationframe.cpp from TagLib
|
||||
//
|
||||
// Copyright (C) 2008 Helmut Wahrmann
|
||||
// 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;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace TagLib.Id3v2
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Frame" /> to provide support ID3v2
|
||||
/// Url Link Frames (Section 4.3.1), covering "<c>W000</c>" to
|
||||
/// "<c>WZZZ</c>", excluding "<c>WXXX</c>".
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>With these frames dynamic data such as webpages with touring
|
||||
/// information, price information or plain ordinary news can be added to
|
||||
/// the tag. There may only be one URL [URL] link frame of its kind in an
|
||||
/// tag, except when stated otherwise in the frame description. If the
|
||||
/// text string is followed by a string termination, all the following
|
||||
/// information should be ignored and not be displayed.</para>
|
||||
/// <para>The following table contains types and descriptions as
|
||||
/// found in the ID3 2.4.0 native frames specification. (Copyright
|
||||
/// (C) Martin Nilsson 2000.)</para>
|
||||
///
|
||||
/// <list type="table">
|
||||
/// <listheader>
|
||||
/// <term>ID</term>
|
||||
/// <description>Description</description>
|
||||
/// </listheader>
|
||||
/// <item>
|
||||
/// <term>WCOM</term>
|
||||
/// <description>The 'Commercial information' frame is a URL pointing at a webpage
|
||||
/// with information such as where the album can be bought. There may be
|
||||
/// more than one "WCOM" frame in a tag, but not with the same content.
|
||||
/// </description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>WCOP</term>
|
||||
/// <description>The 'Copyright/Legal information' frame is a URL pointing at a
|
||||
/// webpage where the terms of use and ownership of the file is described.
|
||||
/// </description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>WOAF</term>
|
||||
/// <description>The 'Official audio file webpage' frame is a URL pointing at a file
|
||||
/// specific webpage.
|
||||
/// </description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>WOAR</term>
|
||||
/// <description>The 'Official artist/performer webpage' frame is a URL pointing at
|
||||
/// the artists official webpage. There may be more than one "WOAR" frame
|
||||
/// in a tag if the audio contains more than one performer, but not with
|
||||
/// the same content.
|
||||
/// </description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>WOAS</term>
|
||||
/// <description>The 'Official audio source webpage' frame is a URL pointing at the
|
||||
/// official webpage for the source of the audio file, e.g. a movie.
|
||||
/// </description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>WORS</term>
|
||||
/// <description>The 'Official Internet radio station homepage' contains a URL
|
||||
/// pointing at the homepage of the internet radio station.
|
||||
/// </description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>WPAY</term>
|
||||
/// <description>The 'Payment' frame is a URL pointing at a webpage that will handle
|
||||
/// the process of paying for this file.
|
||||
/// </description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>WPUB</term>
|
||||
/// <description>The 'Publishers official webpage' frame is a URL pointing at the
|
||||
/// official webpage for the publisher.
|
||||
/// </description>
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
public class UrlLinkFrame : Frame
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the encoding to use for the text.
|
||||
/// </summary>
|
||||
StringType encoding = StringType.Latin1;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the text fields.
|
||||
/// </summary>
|
||||
string[] text_fields = new string[0];
|
||||
|
||||
/// <summary>
|
||||
/// Contains the raw data from the frame, or
|
||||
/// <see langword="null" /> if it has been processed.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Rather than processing the data when the frame is loaded,
|
||||
/// it is parsed on demand, reducing the ammount of
|
||||
/// unnecessary conversion.
|
||||
/// </remarks>
|
||||
ByteVector raw_data;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the ID3v2 version of <see cref="raw_data" />.
|
||||
/// </summary>
|
||||
byte raw_version;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of
|
||||
/// <see cref="UrlLinkFrame" /> with a specified
|
||||
/// identifier and text encoding.
|
||||
/// </summary>
|
||||
/// <param name="ident">
|
||||
/// A <see cref="ByteVector" /> object containing an ID3v2.4
|
||||
/// frame identifier.
|
||||
/// </param>
|
||||
public UrlLinkFrame (ByteVector ident)
|
||||
: base (ident, 4)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of
|
||||
/// <see cref="UrlLinkFrame" /> by reading its raw
|
||||
/// contents in a specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object starting with the
|
||||
/// frame to read.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> value containing the ID3v2 version
|
||||
/// in which <paramref name="data" /> is encoded.
|
||||
/// </param>
|
||||
public UrlLinkFrame (ByteVector data, byte version)
|
||||
: base (data, version)
|
||||
{
|
||||
SetData (data, 0, version, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of
|
||||
/// <see cref="UrlLinkFrame" /> by reading its raw
|
||||
/// contents from a specifed position in a
|
||||
/// <see cref="ByteVector" /> object in a specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the frame
|
||||
/// to read.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// A <see cref="int" /> value specifying the offset in
|
||||
/// <paramref name="data" /> at which the frame begins.
|
||||
/// </param>
|
||||
/// <param name="header">
|
||||
/// A <see cref="FrameHeader" /> value containing the header
|
||||
/// that would be read in the frame.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> value containing the ID3v2 version
|
||||
/// in which <paramref name="data" /> is encoded.
|
||||
/// </param>
|
||||
protected internal UrlLinkFrame (ByteVector data, int offset, FrameHeader header, byte version)
|
||||
: base (header)
|
||||
{
|
||||
SetData (data, offset, version, false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
/// <summary>
|
||||
/// Gets and sets the text contained in the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="T:string[]" /> containing the text contained
|
||||
/// in the current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// <para>Modifying the contents of the returned value will
|
||||
/// not modify the contents of the current instance. The
|
||||
/// value must be reassigned for the value to change.</para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <para>Modifying the values text values of a frame.</para>
|
||||
/// <code> UrlLinkFrame frame = UrlLinkFrame.Get (myTag, "WCOP", true);
|
||||
/// /* Upper casing all the text: */
|
||||
/// string[] text = frame.Text;
|
||||
/// for (int i = 0; i < text.Length; i++)
|
||||
/// text [i] = text [i].ToUpper ();
|
||||
/// frame.Text = text;
|
||||
///
|
||||
/// /* Replacing the value completely: */
|
||||
/// frame.Text = new string [] {"http://www.somewhere.com"};</code>
|
||||
/// </example>
|
||||
public virtual string[] Text {
|
||||
get {
|
||||
ParseRawData ();
|
||||
return (string[])text_fields.Clone ();
|
||||
}
|
||||
set {
|
||||
raw_data = null;
|
||||
text_fields = value != null ?
|
||||
(string[])value.Clone () :
|
||||
new string[0];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the text encoding to use when rendering
|
||||
/// the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="StringType" /> value specifying the encoding
|
||||
/// to use when rendering the current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// This value will be overwritten if
|
||||
/// <see cref="TagLib.Id3v2.Tag.ForceDefaultEncoding" /> is
|
||||
/// <see langword="true" />.
|
||||
/// </remarks>
|
||||
public StringType TextEncoding {
|
||||
get {
|
||||
ParseRawData ();
|
||||
return encoding;
|
||||
}
|
||||
set { encoding = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string representation of the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="string" /> containing the joined text.
|
||||
/// </returns>
|
||||
public override string ToString ()
|
||||
{
|
||||
ParseRawData ();
|
||||
return string.Join ("; ", Text);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Static Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="UrlLinkFrame" /> object of a
|
||||
/// specified type from a specified tag, optionally creating
|
||||
/// and adding one with a specified encoding if none is
|
||||
/// found.
|
||||
/// </summary>
|
||||
/// <param name="tag">
|
||||
/// A <see cref="Tag" /> object to search for the specified
|
||||
/// tag in.
|
||||
/// </param>
|
||||
/// <param name="ident">
|
||||
/// A <see cref="ByteVector" /> object containing the frame
|
||||
/// identifer to search for.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> value specifying whether or not to
|
||||
/// create a new frame if an existing frame was not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="UrlLinkFrame" /> object containing
|
||||
/// the frame found in or added to <paramref name="tag" /> or
|
||||
/// <see langword="null" /> if no value was found
|
||||
/// <paramref name="create" /> is <see langword="false" />.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// To create a frame without having to specify the encoding,
|
||||
/// use <see cref="Get(Tag,ByteVector,bool)" />.
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="tag" /> or <paramref name="ident" /> is
|
||||
/// <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// <paramref name="ident" /> is not exactly four bytes long.
|
||||
/// </exception>
|
||||
public static UrlLinkFrame Get (Tag tag, ByteVector ident, bool create)
|
||||
{
|
||||
if (tag == null)
|
||||
throw new ArgumentNullException (nameof (tag));
|
||||
|
||||
if (ident == null)
|
||||
throw new ArgumentNullException (nameof (ident));
|
||||
|
||||
if (ident.Count != 4)
|
||||
throw new ArgumentException ("Identifier must be four bytes long.",
|
||||
nameof (ident));
|
||||
|
||||
foreach (var frame in tag.GetFrames<UrlLinkFrame> (ident))
|
||||
return frame;
|
||||
|
||||
if (!create)
|
||||
return null;
|
||||
|
||||
var new_frame = new UrlLinkFrame (ident);
|
||||
tag.AddFrame (new_frame);
|
||||
return new_frame;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <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 override void ParseFields (ByteVector data, byte version)
|
||||
{
|
||||
raw_data = data;
|
||||
raw_version = version;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the actual parsing of the raw data.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Because of the high parsing cost and relatively low usage
|
||||
/// of the class, <see cref="ParseFields" /> only stores the
|
||||
/// field data so it can be parsed on demand. Whenever a
|
||||
/// property or method is called which requires the data,
|
||||
/// this method is called, and only on the first call does it
|
||||
/// actually parse the data.
|
||||
/// </remarks>
|
||||
protected void ParseRawData ()
|
||||
{
|
||||
if (raw_data == null)
|
||||
return;
|
||||
|
||||
ByteVector data = raw_data;
|
||||
raw_data = null;
|
||||
|
||||
var field_list = new List<string> ();
|
||||
|
||||
ByteVector delim = ByteVector.TextDelimiter (encoding);
|
||||
|
||||
if (FrameId != FrameType.WXXX) {
|
||||
field_list.AddRange (data.ToStrings (StringType.Latin1, 0));
|
||||
} else if (data.Count > 1 && !data.Mid (0,
|
||||
delim.Count).Equals (delim)) {
|
||||
string value = data.ToString (StringType.Latin1, 1,
|
||||
data.Count - 1);
|
||||
|
||||
// Do a fast removal of end bytes.
|
||||
if (value.Length > 1 &&
|
||||
value[value.Length - 1] == 0)
|
||||
for (int i = value.Length - 1; i >= 0; i--)
|
||||
if (value[i] != 0) {
|
||||
value = value.Substring (0, i + 1);
|
||||
break;
|
||||
}
|
||||
|
||||
field_list.Add (value);
|
||||
}
|
||||
|
||||
// Bad tags may have one or more nul characters at the
|
||||
// end of a string, resulting in empty strings at the
|
||||
// end of the FieldList. Strip them off.
|
||||
while (field_list.Count != 0 && string.IsNullOrEmpty (field_list[field_list.Count - 1]))
|
||||
field_list.RemoveAt (field_list.Count - 1);
|
||||
|
||||
text_fields = field_list.ToArray ();
|
||||
}
|
||||
|
||||
/// <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 override ByteVector RenderFields (byte version)
|
||||
{
|
||||
if (raw_data != null && raw_version == version)
|
||||
return raw_data;
|
||||
|
||||
StringType encoding = CorrectEncoding (TextEncoding, version);
|
||||
|
||||
bool wxxx = FrameId == FrameType.WXXX;
|
||||
|
||||
ByteVector v;
|
||||
|
||||
if (wxxx)
|
||||
v = new ByteVector ((byte)encoding);
|
||||
else
|
||||
v = new ByteVector ();
|
||||
string[] text = text_fields;
|
||||
|
||||
if (version > 3 || wxxx) {
|
||||
if (wxxx) {
|
||||
if (text.Length == 0)
|
||||
text = new string[] { null, null };
|
||||
else if (text.Length == 1)
|
||||
text = new[] {text [0],
|
||||
null};
|
||||
}
|
||||
|
||||
v.Add (ByteVector.FromString (string.Join ("/", text), StringType.Latin1));
|
||||
} else {
|
||||
v.Add (ByteVector.FromString (string.Join ("/", text), StringType.Latin1));
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
#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>
|
||||
public override Frame Clone ()
|
||||
{
|
||||
UrlLinkFrame frame = (this is UserUrlLinkFrame) ?
|
||||
new UserUrlLinkFrame (null, encoding) : new UrlLinkFrame (FrameId);
|
||||
|
||||
frame.text_fields = (string[])text_fields.Clone ();
|
||||
if (raw_data != null)
|
||||
frame.raw_data = new ByteVector (raw_data);
|
||||
|
||||
frame.raw_version = raw_version;
|
||||
return frame;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This class extends <see cref="UrlLinkFrame" /> to provide
|
||||
/// support for ID3v2 User Url Link (WXXX) Frames.
|
||||
/// </summary>
|
||||
public class UserUrlLinkFrame : UrlLinkFrame
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of
|
||||
/// <see cref="UserUrlLinkFrame" /> with a specified
|
||||
/// description and text encoding.
|
||||
/// </summary>
|
||||
/// <param name="description">
|
||||
/// A <see cref="string" /> containing the description of the
|
||||
/// new frame.
|
||||
/// </param>
|
||||
/// <param name="encoding">
|
||||
/// A <see cref="StringType" /> containing the text encoding
|
||||
/// to use when rendering the new frame.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// When a frame is created, it is not automatically added to
|
||||
/// the tag. Consider using
|
||||
/// <see cref="Get(Tag,string,StringType,bool)" /> for more
|
||||
/// integrated frame creation.
|
||||
/// </remarks>
|
||||
public UserUrlLinkFrame (string description, StringType encoding)
|
||||
: base (FrameType.WXXX)
|
||||
{
|
||||
base.Text = new[] { description };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of
|
||||
/// <see cref="UserUrlLinkFrame" /> with a specified
|
||||
/// description.
|
||||
/// </summary>
|
||||
/// <param name="description">
|
||||
/// A <see cref="string" /> containing the description of the
|
||||
/// new frame.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// When a frame is created, it is not automatically added to
|
||||
/// the tag. Consider using
|
||||
/// <see cref="Get(Tag,string,bool)" /> for more integrated frame
|
||||
/// creation.
|
||||
/// </remarks>
|
||||
public UserUrlLinkFrame (string description)
|
||||
: base (FrameType.WXXX)
|
||||
{
|
||||
base.Text = new[] { description };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of
|
||||
/// <see cref="UserUrlLinkFrame" /> by reading its raw
|
||||
/// data in a specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object starting with the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
public UserUrlLinkFrame (ByteVector data, byte version)
|
||||
: base (data, version)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of
|
||||
/// <see cref="UserUrlLinkFrame" /> by reading its raw
|
||||
/// data in a specified ID3v2 version.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the raw
|
||||
/// representation of the new frame.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// A <see cref="int" /> indicating at what offset in
|
||||
/// <paramref name="data" /> the frame actually begins.
|
||||
/// </param>
|
||||
/// <param name="header">
|
||||
/// A <see cref="FrameHeader" /> containing the header of the
|
||||
/// frame found at <paramref name="offset" /> in the data.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// A <see cref="byte" /> indicating the ID3v2 version the
|
||||
/// raw frame is encoded in.
|
||||
/// </param>
|
||||
protected internal UserUrlLinkFrame (ByteVector data, int offset, FrameHeader header, byte version)
|
||||
: base (data, offset, header, version)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the description stored in the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> containing the description
|
||||
/// stored in the current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// There should only be one frame with a matching
|
||||
/// description per tag.
|
||||
/// </remarks>
|
||||
public string Description {
|
||||
get {
|
||||
string[] text = base.Text;
|
||||
return text.Length > 0 ? text[0] : null;
|
||||
}
|
||||
|
||||
set {
|
||||
string[] text = base.Text;
|
||||
if (text.Length > 0)
|
||||
text[0] = value;
|
||||
else
|
||||
text = new[] { value };
|
||||
|
||||
base.Text = text;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the text contained in the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="T:string[]" /> containing the text contained
|
||||
/// in the current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// <para>Modifying the contents of the returned value will
|
||||
/// not modify the contents of the current instance. The
|
||||
/// value must be reassigned for the value to change.</para>
|
||||
/// </remarks>
|
||||
public override string[] Text {
|
||||
get {
|
||||
string[] text = base.Text;
|
||||
if (text.Length < 2)
|
||||
return new string[0];
|
||||
|
||||
string[] new_text = new string[text.Length - 1];
|
||||
for (int i = 0; i < new_text.Length; i++)
|
||||
new_text[i] = text[i + 1];
|
||||
|
||||
return new_text;
|
||||
}
|
||||
set {
|
||||
string[] new_value = new string[
|
||||
value?.Length + 1 ?? 1];
|
||||
|
||||
new_value[0] = Description;
|
||||
|
||||
for (int i = 1; i < new_value.Length; i++)
|
||||
new_value[i] = value[i - 1];
|
||||
|
||||
base.Text = new_value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string representation of the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="string" /> containing the joined text.
|
||||
/// </returns>
|
||||
public override string ToString ()
|
||||
{
|
||||
return new StringBuilder ().Append ("[")
|
||||
.Append (Description)
|
||||
.Append ("] ")
|
||||
.Append (base.ToString ()).ToString ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Static Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a specified user text frame from the specified tag,
|
||||
/// optionally creating it if it does not exist.
|
||||
/// </summary>
|
||||
/// <param name="tag">
|
||||
/// A <see cref="Tag" /> object to search in.
|
||||
/// </param>
|
||||
/// <param name="description">
|
||||
/// A <see cref="string" /> specifying the description to
|
||||
/// match.
|
||||
/// </param>
|
||||
/// <param name="type">
|
||||
/// A <see cref="StringType" /> specifying the encoding to
|
||||
/// use if creating a new frame.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> specifying whether or not to create
|
||||
/// and add a new frame to the tag if a match is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="UserUrlLinkFrame" /> object
|
||||
/// containing the matching frame, or <see langword="null" />
|
||||
/// if a match wasn't found and <paramref name="create" /> is
|
||||
/// <see langword="false" />.
|
||||
/// </returns>
|
||||
public static UserUrlLinkFrame Get (Tag tag, string description, StringType type, bool create)
|
||||
{
|
||||
if (tag == null)
|
||||
throw new ArgumentNullException (nameof (tag));
|
||||
|
||||
if (description == null)
|
||||
throw new ArgumentNullException (nameof (description));
|
||||
|
||||
if (description.Length == 0)
|
||||
throw new ArgumentException ("Description must not be empty.",
|
||||
nameof (description));
|
||||
|
||||
foreach (var frame in tag.GetFrames<UserUrlLinkFrame> (FrameType.WXXX))
|
||||
if (description.Equals (frame.Description))
|
||||
return frame;
|
||||
|
||||
if (!create)
|
||||
return null;
|
||||
|
||||
var new_frame = new UserUrlLinkFrame (description, type);
|
||||
tag.AddFrame (new_frame);
|
||||
return new_frame;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a specified user text frame from the specified tag,
|
||||
/// optionally creating it if it does not exist.
|
||||
/// </summary>
|
||||
/// <param name="tag">
|
||||
/// A <see cref="Tag" /> object to search in.
|
||||
/// </param>
|
||||
/// <param name="description">
|
||||
/// A <see cref="string" /> specifying the description to
|
||||
/// match.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> specifying whether or not to create
|
||||
/// and add a new frame to the tag if a match is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="UserUrlLinkFrame" /> object
|
||||
/// containing the matching frame, or <see langword="null" />
|
||||
/// if a match wasn't found and <paramref name="create" /> is
|
||||
/// <see langword="false" />.
|
||||
/// </returns>
|
||||
public static UserUrlLinkFrame Get (Tag tag, string description, bool create)
|
||||
{
|
||||
return Get (tag, description, Tag.DefaultEncoding, create);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: df869fa34208a7a94afcc355039e6d76
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,292 @@
|
||||
//
|
||||
// Header.cs:
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Original Source:
|
||||
// id3v2header.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>
|
||||
/// Indicates the flags applied to a <see cref="Header" /> object.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum HeaderFlags : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// The header contains no flags.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The tag described by the header has been unsynchronized.
|
||||
/// </summary>
|
||||
Unsynchronisation = 0x80,
|
||||
|
||||
/// <summary>
|
||||
/// The tag described by the header has contains an extended
|
||||
/// header.
|
||||
/// </summary>
|
||||
ExtendedHeader = 0x40,
|
||||
|
||||
/// <summary>
|
||||
/// The tag described by the header is experimental.
|
||||
/// </summary>
|
||||
ExperimentalIndicator = 0x20,
|
||||
|
||||
/// <summary>
|
||||
/// The tag described by the header contains a footer.
|
||||
/// </summary>
|
||||
FooterPresent = 0x10
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This structure provides a representation of an ID3v2 tag header
|
||||
/// which can be read from and written to disk.
|
||||
/// </summary>
|
||||
public struct Header
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the tag's major version.
|
||||
/// </summary>
|
||||
byte major_version;
|
||||
|
||||
/// <summary>
|
||||
/// Contains tag's flags.
|
||||
/// </summary>
|
||||
HeaderFlags flags;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Fields
|
||||
|
||||
/// <summary>
|
||||
/// The size of a ID3v2 header.
|
||||
/// </summary>
|
||||
public const uint Size = 10;
|
||||
|
||||
/// <summary>
|
||||
/// The identifier used to recognize a ID3v2 headers.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "ID3"
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector FileIdentifier = "ID3";
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <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 (nameof (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];
|
||||
RevisionNumber = 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.");
|
||||
|
||||
TagSize = SynchData.ToUInt (data.Mid (6, 4));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the major version of the tag described by
|
||||
/// the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="byte" /> value specifying the ID3v2 version
|
||||
/// of tag described by the current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// When the version is set, unsupported header flags will
|
||||
/// automatically be removed from the tag.
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="value" /> is less than 2 or more than 4.
|
||||
/// </exception>
|
||||
public byte MajorVersion {
|
||||
get {
|
||||
return major_version == 0 ? Tag.DefaultVersion :
|
||||
major_version;
|
||||
}
|
||||
set {
|
||||
if (value < 2 || value > 4)
|
||||
throw new ArgumentException ("Version unsupported");
|
||||
|
||||
if (value < 3)
|
||||
flags &= ~(HeaderFlags.ExtendedHeader | HeaderFlags.ExperimentalIndicator);
|
||||
|
||||
if (value < 4)
|
||||
flags &= ~HeaderFlags.FooterPresent;
|
||||
|
||||
major_version = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the version revision number of the tag
|
||||
/// represented by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="byte" /> value containing the version
|
||||
/// revision number of the tag represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// This value should always be zeroed. A non-zero value
|
||||
/// indicates an experimental or new version of the format
|
||||
/// which may not be completely understood by the current
|
||||
/// implementation. Some software may refuse to read tags
|
||||
/// with a non-zero value.
|
||||
/// </remarks>
|
||||
public byte RevisionNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the flags applied to the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A bitwise combined <see cref="HeaderFlags" /> value
|
||||
/// containing the flags applied to the current instance.
|
||||
/// </value>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// <paramref name="value" /> contains a flag not supported
|
||||
/// by the the ID3v2 version of the current instance.
|
||||
/// </exception>
|
||||
public HeaderFlags Flags {
|
||||
get { return flags; }
|
||||
set {
|
||||
if (0 != (value & (HeaderFlags.ExtendedHeader | HeaderFlags.ExperimentalIndicator)) && MajorVersion < 3)
|
||||
throw new ArgumentException ("Feature only supported in version 2.3+", nameof (value));
|
||||
|
||||
if (0 != (value & HeaderFlags.FooterPresent) && MajorVersion < 3)
|
||||
throw new ArgumentException ("Feature only supported in version 2.4+", nameof (value));
|
||||
|
||||
flags = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the size of the tag described by the
|
||||
/// current instance, minus the header and footer.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the size of the
|
||||
/// tag described by the current instance.
|
||||
/// </value>
|
||||
public uint TagSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the complete size of the tag described by the
|
||||
/// current instance, including the header and footer.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the complete size
|
||||
/// of the tag described by the current instance.
|
||||
/// </value>
|
||||
public uint CompleteTagSize {
|
||||
get {
|
||||
if ((flags & HeaderFlags.FooterPresent) != 0)
|
||||
return TagSize + Size + Footer.Size;
|
||||
else
|
||||
return TagSize + Size;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ID3v2 header.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered header.
|
||||
/// </returns>
|
||||
public ByteVector Render ()
|
||||
{
|
||||
var v = new ByteVector {
|
||||
FileIdentifier,
|
||||
MajorVersion,
|
||||
RevisionNumber,
|
||||
(byte)flags,
|
||||
SynchData.FromUInt (TagSize)
|
||||
};
|
||||
return v;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: afa6b03e96f588b57b65575ffe7b1b4f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,155 @@
|
||||
//
|
||||
// SynchData.cs: Provides support for encoding and decoding unsynchronized data
|
||||
// and numbers.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Original Source:
|
||||
// id3v2synchdata.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 static class provides support for encoding and decoding
|
||||
/// unsynchronized data and numbers.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Unsynchronization is designed so that portions of the tag won't
|
||||
/// be misinterpreted as MPEG audio stream headers by removing the
|
||||
/// possibility of the synch bytes occuring in the tag.
|
||||
/// </remarks>
|
||||
public static class SynchData
|
||||
{
|
||||
/// <summary>
|
||||
/// Decodes synchronized integer data into a <see
|
||||
/// cref="uint" /> value.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the number
|
||||
/// to decode. Only the first 4 bytes of this value will be
|
||||
/// used.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="uint" /> value containing the decoded
|
||||
/// number.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="data" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public static uint ToUInt (ByteVector data)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
uint sum = 0;
|
||||
int last = data.Count > 4 ? 3 : data.Count - 1;
|
||||
|
||||
for (int i = 0; i <= last; i++)
|
||||
sum |= (uint)(data[i] & 0x7f)
|
||||
<< ((last - i) * 7);
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encodes a <see cref="uint" /> value as synchronized
|
||||
/// integer data.
|
||||
/// </summary>
|
||||
/// <param name="value">
|
||||
/// A <see cref="uint" /> value containing the number to
|
||||
/// encode.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the encoded
|
||||
/// number.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="value" /> is greater than 268435455.
|
||||
/// </exception>
|
||||
public static ByteVector FromUInt (uint value)
|
||||
{
|
||||
if ((value >> 28) != 0)
|
||||
throw new ArgumentOutOfRangeException (nameof (value),
|
||||
"value must be less than 268435456.");
|
||||
|
||||
ByteVector v = new ByteVector (4, 0);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
v[i] = (byte)(value >> ((3 - i) * 7) & 0x7f);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unsynchronizes a <see cref="ByteVector" /> object by
|
||||
/// inserting empty bytes where necessary.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object to unsynchronize.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="data" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public static void UnsynchByteVector (ByteVector data)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
for (int i = data.Count - 2; i >= 0; i--)
|
||||
if (data[i] == 0xFF && (data[i + 1] == 0 ||
|
||||
(data[i + 1] & 0xE0) != 0))
|
||||
data.Insert (i + 1, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resynchronizes a <see cref="ByteVector" /> object by
|
||||
/// removing the added bytes.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object to resynchronize.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="data" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public static void ResynchByteVector (ByteVector data)
|
||||
{
|
||||
if (data == null) {
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
}
|
||||
|
||||
int i = 0, j = 0;
|
||||
while (i < data.Count - 1) {
|
||||
if (i != j) {
|
||||
data[j] = data[i];
|
||||
}
|
||||
i += data[i] == 0xFF && data[i + 1] == 0 ? 2 : 1;
|
||||
j++;
|
||||
}
|
||||
if (i < data.Count) {
|
||||
data[j++] = data[i++];
|
||||
}
|
||||
data.Resize (j);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93f455c4dc22f3553b204aa07c2c3d37
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// SynchedTextType.cs:
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 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
|
||||
//
|
||||
|
||||
namespace TagLib.Id3v2
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the type of text contained in a <see
|
||||
/// cref="SynchronisedLyricsFrame" />.
|
||||
/// </summary>
|
||||
public enum SynchedTextType
|
||||
{
|
||||
/// <summary>
|
||||
/// The text is some other type of text.
|
||||
/// </summary>
|
||||
Other = 0x00,
|
||||
|
||||
/// <summary>
|
||||
/// The text contains lyrical data.
|
||||
/// </summary>
|
||||
Lyrics = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// The text contains a transcription.
|
||||
/// </summary>
|
||||
TextTranscription = 0x02,
|
||||
|
||||
/// <summary>
|
||||
/// The text lists the movements in the piece.
|
||||
/// </summary>
|
||||
Movement = 0x03,
|
||||
|
||||
/// <summary>
|
||||
/// The text describes events that occur.
|
||||
/// </summary>
|
||||
Events = 0x04,
|
||||
|
||||
/// <summary>
|
||||
/// The text contains chord changes that occur in the music.
|
||||
/// </summary>
|
||||
Chord = 0x05,
|
||||
|
||||
/// <summary>
|
||||
/// The text contains trivia or "pop up" information about
|
||||
/// the media.
|
||||
/// </summary>
|
||||
Trivia = 0x06,
|
||||
|
||||
/// <summary>
|
||||
/// The text contains URL's for relevant webpages.
|
||||
/// </summary>
|
||||
WebpageUrls = 0x07,
|
||||
|
||||
/// <summary>
|
||||
/// The text contains URL's for relevant images.
|
||||
/// </summary>
|
||||
ImageUrls = 0x08
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 307691597261c993dba370310670f2ef
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9d64050aad154a9718a58535d034ac5d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// TimestampFormat.cs:
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 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
|
||||
//
|
||||
|
||||
|
||||
namespace TagLib.Id3v2
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the timestamp format used by a <see
|
||||
/// cref="SynchronisedLyricsFrame" /> and <see cref="EventTimeCodesFrame"/>.
|
||||
/// </summary>
|
||||
public enum TimestampFormat
|
||||
{
|
||||
/// <summary>
|
||||
/// The timestamp is of unknown format.
|
||||
/// </summary>
|
||||
Unknown = 0x00,
|
||||
|
||||
/// <summary>
|
||||
/// The timestamp represents the number of MPEG frames since
|
||||
/// the beginning of the audio stream.
|
||||
/// </summary>
|
||||
AbsoluteMpegFrames = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// The timestamp represents the number of milliseconds since
|
||||
/// the beginning of the audio stream.
|
||||
/// </summary>
|
||||
AbsoluteMilliseconds = 0x02
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3e1be87f9440ffca58bc6ed3f1533bab
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in new issue
Block a user