Initial commit
This commit is contained in:
commit
262601edb8
2025 files changed
+218754
No files matched your search
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 308bd862125e5ae9c95724055c402e8c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,415 @@
|
||||
//
|
||||
// AudioHeader.cs: Provides information about an ADTS AAC audio stream.
|
||||
//
|
||||
// Copyright (C) 2009 Patrick Dehne
|
||||
//
|
||||
// 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.Aac
|
||||
{
|
||||
/// <summary>
|
||||
/// This structure implements <see cref="IAudioCodec" /> and provides
|
||||
/// information about an ADTS AAC audio stream.
|
||||
/// </summary>
|
||||
public class AudioHeader : IAudioCodec
|
||||
{
|
||||
#region Private Static Value Arrays
|
||||
|
||||
/// <summary>
|
||||
/// Contains a sample rate table for ADTS AAC audio.
|
||||
/// </summary>
|
||||
static readonly int[] sample_rates = new int[13] {
|
||||
96000, 88200, 64000, 48000, 44100, 32000,
|
||||
24000, 22050, 16000, 12000, 11025, 8000, 7350
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Contains a channel table for ADTS AAC audio.
|
||||
/// </summary>
|
||||
static readonly int[] channels = new int[8] {
|
||||
0, 1, 2, 3, 4, 5, 6, 8
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Private Properties
|
||||
|
||||
/// <summary>
|
||||
/// Contains the audio stream length.
|
||||
/// </summary>
|
||||
long stream_length;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the audio stream duration.
|
||||
/// </summary>
|
||||
TimeSpan duration;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of channels in the audio
|
||||
/// </summary>
|
||||
readonly int audiochannels;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the bitrate of the audio stream
|
||||
/// </summary>
|
||||
readonly int audiobitrate;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the samplerate of the audio stream
|
||||
/// </summary>
|
||||
readonly int audiosamplerate;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Fields
|
||||
|
||||
/// <summary>
|
||||
/// An empty and unset header.
|
||||
/// </summary>
|
||||
public static readonly AudioHeader Unknown = new AudioHeader ();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new empty instance of <see
|
||||
/// cref="AudioHeader" />
|
||||
/// </summary>
|
||||
AudioHeader ()
|
||||
{
|
||||
stream_length = 0;
|
||||
duration = TimeSpan.Zero;
|
||||
audiochannels = 0;
|
||||
audiobitrate = 0;
|
||||
audiosamplerate = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="AudioHeader" /> by populating it with specified
|
||||
/// values.
|
||||
/// </summary>
|
||||
/// <param name="channels">
|
||||
/// A <see cref="int" /> value indicating the number
|
||||
/// of channels in the audio stream
|
||||
/// </param>
|
||||
/// <param name="bitrate">
|
||||
/// A <see cref="int" /> value indicating the bitrate
|
||||
/// of the audio stream
|
||||
/// </param>
|
||||
/// <param name="samplerate">
|
||||
/// A <see cref="int" /> value indicating the samplerate
|
||||
/// of the audio stream
|
||||
/// </param>
|
||||
/// <param name="numberofsamples">
|
||||
/// A <see cref="int" /> value indicating the number
|
||||
/// of samples in the audio stream
|
||||
/// </param>
|
||||
/// <param name="numberofframes">
|
||||
/// A <see cref="int" /> value indicating the number
|
||||
/// of frames in the audio stream
|
||||
/// </param>
|
||||
AudioHeader (int channels, int bitrate, int samplerate, int numberofsamples, int numberofframes)
|
||||
{
|
||||
duration = TimeSpan.Zero;
|
||||
stream_length = 0;
|
||||
audiochannels = channels;
|
||||
audiobitrate = bitrate;
|
||||
audiosamplerate = samplerate;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets a text description of the media represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing a description
|
||||
/// of the media represented by the current instance.
|
||||
/// </value>
|
||||
public string Description {
|
||||
get {
|
||||
return "ADTS AAC";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the types of media represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Always <see cref="MediaTypes.Audio" />.
|
||||
/// </value>
|
||||
public MediaTypes MediaTypes {
|
||||
get { return MediaTypes.Audio; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the duration of the media represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TimeSpan" /> containing the duration of the
|
||||
/// media represented by the current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// If <see cref="SetStreamLength" /> has not been called, this
|
||||
/// value will not be correct.
|
||||
/// </remarks>
|
||||
public TimeSpan Duration {
|
||||
get {
|
||||
return duration;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bitrate of the audio represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing a bitrate of the
|
||||
/// audio represented by the current instance.
|
||||
/// </value>
|
||||
public int AudioBitrate {
|
||||
get {
|
||||
return audiobitrate;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sample rate of the audio represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the sample rate of
|
||||
/// the audio represented by the current instance.
|
||||
/// </value>
|
||||
public int AudioSampleRate {
|
||||
get {
|
||||
return audiosamplerate;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of channels in the audio represented by
|
||||
/// the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the number of
|
||||
/// channels in the audio represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public int AudioChannels {
|
||||
get { return audiochannels; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Sets the length of the audio stream represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <param name="streamLength">
|
||||
/// A <see cref="long" /> value specifying the length in
|
||||
/// bytes of the audio stream represented by the current
|
||||
/// instance.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// The this value has been set, <see cref="Duration" /> will
|
||||
/// return an incorrect value.
|
||||
/// </remarks>
|
||||
public void SetStreamLength (long streamLength)
|
||||
{
|
||||
stream_length = streamLength;
|
||||
duration = TimeSpan.FromSeconds (stream_length * 8.0 / audiobitrate);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Static Methods
|
||||
|
||||
/// <summary>
|
||||
/// Searches for an audio header in a <see cref="TagLib.File"
|
||||
/// /> starting at a specified position and searching through
|
||||
/// a specified number of bytes.
|
||||
/// </summary>
|
||||
/// <param name="header">
|
||||
/// A <see cref="AudioHeader" /> object in which the found
|
||||
/// header will be stored.
|
||||
/// </param>
|
||||
/// <param name="file">
|
||||
/// A <see cref="TagLib.File" /> object to search.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specifying the seek position
|
||||
/// in <paramref name="file" /> at which to start searching.
|
||||
/// </param>
|
||||
/// <param name="length">
|
||||
/// A <see cref="int" /> value specifying the maximum number
|
||||
/// of bytes to search before aborting.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="bool" /> value indicating whether or not a
|
||||
/// header was found.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public static bool Find (out AudioHeader header, TagLib.File file, long position, int length)
|
||||
{
|
||||
if (file == null)
|
||||
throw new ArgumentNullException (nameof (file));
|
||||
|
||||
long end = position + length;
|
||||
header = Unknown;
|
||||
|
||||
file.Seek (position);
|
||||
|
||||
ByteVector buffer = file.ReadBlock (3);
|
||||
|
||||
if (buffer.Count < 3)
|
||||
return false;
|
||||
|
||||
do {
|
||||
file.Seek (position + 3);
|
||||
buffer = buffer.Mid (buffer.Count - 3);
|
||||
buffer.Add (file.ReadBlock (
|
||||
(int)TagLib.File.BufferSize));
|
||||
|
||||
for (int i = 0; i < buffer.Count - 3 &&
|
||||
(length < 0 || position + i < end); i++)
|
||||
if (buffer[i] == 0xFF
|
||||
&& buffer[i + 1] >= 0xF0) // 0xFFF
|
||||
try {
|
||||
BitStream bits = new BitStream (buffer.Mid (i, 7).Data);
|
||||
|
||||
// 12 bits sync header
|
||||
bits.ReadInt32 (12);
|
||||
|
||||
// 1 bit mpeg 2/4
|
||||
bits.ReadInt32 (1);
|
||||
|
||||
// 2 bits layer
|
||||
bits.ReadInt32 (2);
|
||||
|
||||
// 1 bit protection absent
|
||||
bits.ReadInt32 (1);
|
||||
|
||||
// 2 bits profile object type
|
||||
bits.ReadInt32 (2);
|
||||
|
||||
// 4 bits sampling frequency index
|
||||
int samplerateindex = bits.ReadInt32 (4);
|
||||
if (samplerateindex >= sample_rates.Length)
|
||||
return false;
|
||||
long samplerate = sample_rates[samplerateindex];
|
||||
|
||||
// 1 bit private bit
|
||||
bits.ReadInt32 (1);
|
||||
|
||||
// 3 bits channel configuration
|
||||
int channelconfigindex = bits.ReadInt32 (3);
|
||||
if (channelconfigindex >= channels.Length)
|
||||
return false;
|
||||
|
||||
// 4 copyright bits
|
||||
bits.ReadInt32 (4);
|
||||
|
||||
// 13 bits frame length
|
||||
long framelength = bits.ReadInt32 (13); // double check framelength
|
||||
if (framelength < 7)
|
||||
return false;
|
||||
|
||||
// 11 bits buffer fullness
|
||||
bits.ReadInt32 (11);
|
||||
|
||||
// 2 bits number of raw data blocks in frame
|
||||
int numberofframes = bits.ReadInt32 (2) + 1;
|
||||
|
||||
long numberofsamples = numberofframes * 1024;
|
||||
long bitrate = framelength * 8 * samplerate / numberofsamples;
|
||||
|
||||
header = new AudioHeader (channels[channelconfigindex],
|
||||
(int)bitrate,
|
||||
(int)samplerate,
|
||||
(int)numberofsamples,
|
||||
numberofframes);
|
||||
|
||||
return true;
|
||||
} catch (CorruptFileException) {
|
||||
}
|
||||
|
||||
position += TagLib.File.BufferSize;
|
||||
} while (buffer.Count > 3 && (length < 0 || position < end));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches for an audio header in a <see cref="TagLib.File"
|
||||
/// /> starting at a specified position and searching to the
|
||||
/// end of the file.
|
||||
/// </summary>
|
||||
/// <param name="header">
|
||||
/// A <see cref="AudioHeader" /> object in which the found
|
||||
/// header will be stored.
|
||||
/// </param>
|
||||
/// <param name="file">
|
||||
/// A <see cref="TagLib.File" /> object to search.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specifying the seek position
|
||||
/// in <paramref name="file" /> at which to start searching.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="bool" /> value indicating whether or not a
|
||||
/// header was found.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Searching to the end of the file can be very, very slow
|
||||
/// especially for corrupt or non-MPEG files. It is
|
||||
/// recommended to use <see
|
||||
/// cref="M:AudioHeader.Find(AudioHeader,TagLib.File,long,int)" />
|
||||
/// instead.
|
||||
/// </remarks>
|
||||
public static bool Find (out AudioHeader header, TagLib.File file, long position)
|
||||
{
|
||||
return Find (out header, file, position, -1);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a70f4e38ac189d2389cf4717f5a1869a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,100 @@
|
||||
//
|
||||
// BitStream.cs: Helper to read bits from a byte array.
|
||||
//
|
||||
// Copyright (C) 2009 Patrick Dehne
|
||||
//
|
||||
// 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;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace TagLib.Aac
|
||||
{
|
||||
/// <summary>
|
||||
/// This class is used to help reading arbitary number of bits from
|
||||
/// a fixed array of bytes
|
||||
/// </summary>
|
||||
public class BitStream
|
||||
{
|
||||
readonly BitArray bits;
|
||||
int bitindex;
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Construct a new <see cref="BitStream"/>.
|
||||
/// </summary>
|
||||
/// <param name="buffer">
|
||||
/// A <see cref="T:System.Byte[]"/>, must be 7 bytes long.
|
||||
/// </param>
|
||||
public BitStream (byte[] buffer)
|
||||
{
|
||||
Debug.Assert (buffer.Length == 7, "buffer.Length == 7", "buffer size invalid");
|
||||
|
||||
if (buffer.Length != 7)
|
||||
throw new ArgumentException ("Buffer size must be 7 bytes");
|
||||
|
||||
// Reverse bits
|
||||
bits = new BitArray (buffer.Length * 8);
|
||||
for (int i = 0; i < buffer.Length; i++) {
|
||||
for (int y = 0; y < 8; y++) {
|
||||
bits[i * 8 + y] = ((buffer[i] & (1 << (7 - y))) > 0);
|
||||
}
|
||||
}
|
||||
|
||||
bitindex = 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Reads an Int32 from the bitstream
|
||||
/// </summary>
|
||||
/// <param name="numberOfBits">
|
||||
/// A <see cref="int" /> value containing the number
|
||||
/// of bits to read from the bitstream
|
||||
/// </param>
|
||||
public int ReadInt32 (int numberOfBits)
|
||||
{
|
||||
Debug.Assert (numberOfBits > 0, "numberOfBits < 1");
|
||||
Debug.Assert (numberOfBits <= 32, "numberOfBits <= 32");
|
||||
|
||||
if (numberOfBits <= 0)
|
||||
throw new ArgumentException ("Number of bits to read must be >= 1");
|
||||
|
||||
if (numberOfBits > 32)
|
||||
throw new ArgumentException ("Number of bits to read must be <= 32");
|
||||
|
||||
int value = 0;
|
||||
int start = bitindex + numberOfBits - 1;
|
||||
for (int i = 0; i < numberOfBits; i++) {
|
||||
value += bits[start] ? (1 << i) : 0;
|
||||
bitindex++;
|
||||
start--;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8284bad068f4283f29df4c52751a79cc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,272 @@
|
||||
//
|
||||
// File.cs: Provides tagging and properties support for ADTS AAC files
|
||||
//
|
||||
// Here is the ADTS Header description used for implementation:
|
||||
// http://www.hydrogenaudio.org/forums/lofiversion/index.php/t21617.html
|
||||
//
|
||||
// Copyright (C) 2009 Patrick Dehne
|
||||
//
|
||||
// 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.Aac
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="TagLib.NonContainer.File" /> to
|
||||
/// provide tagging and properties support for ADTS AAC audio files.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A <see cref="TagLib.Id3v1.Tag" /> and <see
|
||||
/// cref="TagLib.Id3v2.Tag" /> will be added automatically to any
|
||||
/// file that doesn't contain one. This change does not effect the
|
||||
/// file until it is saved and can be reversed using the following
|
||||
/// method:
|
||||
/// <code>file.RemoveTags (file.TagTypes & ~file.TagTypesOnDisk);</code>
|
||||
/// </remarks>
|
||||
[SupportedMimeType ("taglib/aac", "aac")]
|
||||
[SupportedMimeType ("audio/aac")]
|
||||
public class File : TagLib.NonContainer.File
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the first audio header.
|
||||
/// </summary>
|
||||
AudioHeader first_header;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local
|
||||
/// file system and specified read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path, ReadStyle propertiesStyle)
|
||||
: base (path, propertiesStyle)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local
|
||||
/// file system with an average read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path) : base (path)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction and
|
||||
/// specified read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction, ReadStyle propertiesStyle)
|
||||
: base (abstraction, propertiesStyle)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction with
|
||||
/// an average read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction)
|
||||
: base (abstraction)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a tag of a specified type from the current instance,
|
||||
/// optionally creating a new tag if possible.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="TagLib.TagTypes" /> value indicating the
|
||||
/// type of tag to read.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> value specifying whether or not to
|
||||
/// try and create the tag if one is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="Tag" /> object containing the tag that was
|
||||
/// found in or added to the current instance. If no
|
||||
/// matching tag was found and none was created, <see
|
||||
/// langword="null" /> is returned.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// If a <see cref="TagLib.Id3v2.Tag" /> is added to the
|
||||
/// current instance, it will be placed at the start of the
|
||||
/// file. On the other hand, <see cref="TagLib.Id3v1.Tag" />
|
||||
/// <see cref="TagLib.Ape.Tag" /> will be added to the end of
|
||||
/// the file. All other tag types will be ignored.
|
||||
/// </remarks>
|
||||
public override Tag GetTag (TagTypes type, bool create)
|
||||
{
|
||||
Tag t = (Tag as TagLib.NonContainer.Tag).GetTag (type);
|
||||
|
||||
if (t != null || !create)
|
||||
return t;
|
||||
|
||||
switch (type) {
|
||||
case TagTypes.Id3v1:
|
||||
return EndTag.AddTag (type, Tag);
|
||||
|
||||
case TagTypes.Id3v2:
|
||||
return StartTag.AddTag (type, Tag);
|
||||
|
||||
case TagTypes.Ape:
|
||||
return EndTag.AddTag (type, Tag);
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Reads format specific information at the start of the
|
||||
/// file.
|
||||
/// </summary>
|
||||
/// <param name="start">
|
||||
/// A <see cref="long" /> value containing the seek position
|
||||
/// at which the tags end and the media data begins.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// This method only searches for an audio header in the
|
||||
/// first 16384 bytes of code to avoid searching forever in
|
||||
/// corrupt files.
|
||||
/// </remarks>
|
||||
protected override void ReadStart (long start, ReadStyle propertiesStyle)
|
||||
{
|
||||
// Only check the first 16 bytes so we're not stuck
|
||||
// reading a bad file forever.
|
||||
if ((propertiesStyle & ReadStyle.Average) != 0 &&
|
||||
!AudioHeader.Find (out first_header, this, start, 0x4000))
|
||||
throw new CorruptFileException ("ADTS audio header not found.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads format specific information at the end of the
|
||||
/// file.
|
||||
/// </summary>
|
||||
/// <param name="end">
|
||||
/// A <see cref="long" /> value containing the seek position
|
||||
/// at which the media data ends and the tags begin.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
protected override void ReadEnd (long end, ReadStyle propertiesStyle)
|
||||
{
|
||||
// Make sure we have ID3v1 and ID3v2 tags.
|
||||
GetTag (TagTypes.Id3v1, true);
|
||||
GetTag (TagTypes.Id3v2, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the audio properties from the file represented by
|
||||
/// the current instance.
|
||||
/// </summary>
|
||||
/// <param name="start">
|
||||
/// A <see cref="long" /> value containing the seek position
|
||||
/// at which the tags end and the media data begins.
|
||||
/// </param>
|
||||
/// <param name="end">
|
||||
/// A <see cref="long" /> value containing the seek position
|
||||
/// at which the media data ends and the tags begin.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="TagLib.Properties" /> object describing the
|
||||
/// media properties of the file represented by the current
|
||||
/// instance.
|
||||
/// </returns>
|
||||
protected override Properties ReadProperties (long start, long end, ReadStyle propertiesStyle)
|
||||
{
|
||||
first_header.SetStreamLength (end - start);
|
||||
return new Properties (TimeSpan.Zero, first_header);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ea5a2b9978c53a708489187d4f05f90
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4e181c0c58fe3641d805ee0aabca0c10
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,486 @@
|
||||
//
|
||||
// File.cs: Provides tagging and properties support for Apple's AIFF
|
||||
// files.
|
||||
//
|
||||
// Author:
|
||||
// Helmut Wahrmann
|
||||
//
|
||||
// Copyright (C) 2009 Helmut Wahrmann
|
||||
//
|
||||
// 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.Aiff
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="TagLib.File" /> to provide
|
||||
/// support for reading and writing tags and properties for files
|
||||
/// using the AIFF file format.
|
||||
/// </summary>
|
||||
[SupportedMimeType ("taglib/aif", "aif")]
|
||||
[SupportedMimeType ("taglib/aiff", "aiff")]
|
||||
[SupportedMimeType ("audio/x-aiff")]
|
||||
[SupportedMimeType ("audio/aiff")]
|
||||
[SupportedMimeType ("sound/aiff")]
|
||||
[SupportedMimeType ("application/x-aiff")]
|
||||
public class File : TagLib.File
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the address of the AIFF header block.
|
||||
/// </summary>
|
||||
ByteVector header_block;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the Id3v2 tag.
|
||||
/// </summary>
|
||||
Id3v2.Tag tag;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the media properties.
|
||||
/// </summary>
|
||||
Properties properties;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Static Fields
|
||||
|
||||
/// <summary>
|
||||
/// The identifier used to recognize a AIFF files.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "FORM"
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector FileIdentifier = "FORM";
|
||||
|
||||
/// <summary>
|
||||
/// The identifier used to recognize a AIFF Common chunk.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "COMM"
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector CommIdentifier = "COMM";
|
||||
|
||||
/// <summary>
|
||||
/// The identifier used to recognize a AIFF Sound Data Chunk.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "SSND"
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector SoundIdentifier = "SSND";
|
||||
|
||||
/// <summary>
|
||||
/// The identifier used to recognize a AIFF ID3 chunk.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "ID3 "
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector ID3Identifier = "ID3 ";
|
||||
|
||||
/// <summary>
|
||||
/// The identifier used to recognize a AIFF Form type.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "AIFF"
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector AIFFFormType = "AIFF";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local file
|
||||
/// system and specified read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path, ReadStyle propertiesStyle)
|
||||
: this (new LocalFileAbstraction (path), propertiesStyle)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local file
|
||||
/// system with an average read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path)
|
||||
: this (path, ReadStyle.Average)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction and
|
||||
/// specified read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction, ReadStyle propertiesStyle) : base (abstraction)
|
||||
{
|
||||
Mode = AccessMode.Read;
|
||||
try {
|
||||
Read (true, propertiesStyle, out var aiff_size, out var tag_start, out var tag_end);
|
||||
} finally {
|
||||
Mode = AccessMode.Closed;
|
||||
}
|
||||
|
||||
TagTypesOnDisk = TagTypes;
|
||||
|
||||
GetTag (TagTypes.Id3v2, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction with an
|
||||
/// average read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction)
|
||||
: this (abstraction, ReadStyle.Average)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets a abstract representation of all tags stored in the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TagLib.Tag" /> object representing all tags
|
||||
/// stored in the current instance.
|
||||
/// </value>
|
||||
public override Tag Tag {
|
||||
get { return tag; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the media properties of the file represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TagLib.Properties" /> object containing the
|
||||
/// media properties of the file represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public override Properties Properties {
|
||||
get { return properties; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Saves the changes made in the current instance to the
|
||||
/// file it represents.
|
||||
/// </summary>
|
||||
public override void Save ()
|
||||
{
|
||||
// Boilerplate
|
||||
PreSave ();
|
||||
|
||||
Mode = AccessMode.Write;
|
||||
try {
|
||||
var data = new ByteVector ();
|
||||
|
||||
// Add the ID3 chunk and ID32 tag to the vector
|
||||
if (tag != null) {
|
||||
ByteVector tag_data = tag.Render ();
|
||||
if (tag_data.Count > 10) {
|
||||
if (tag_data.Count % 2 == 1)
|
||||
tag_data.Add (0);
|
||||
|
||||
data.Add ("ID3 ");
|
||||
data.Add (ByteVector.FromUInt ((uint)tag_data.Count, true));
|
||||
data.Add (tag_data);
|
||||
}
|
||||
}
|
||||
|
||||
Read (false, ReadStyle.None, out var aiff_size,
|
||||
out var tag_start, out var tag_end);
|
||||
|
||||
// If tagging info cannot be found, place it at
|
||||
// the end of the file.
|
||||
if (tag_start < 12 || tag_end < tag_start)
|
||||
tag_start = tag_end = Length;
|
||||
|
||||
int length = (int)(tag_end - tag_start + 8);
|
||||
|
||||
// Insert the tagging data.
|
||||
Insert (data, tag_start, length);
|
||||
|
||||
// If the data size changed update the aiff size.
|
||||
if (data.Count - length != 0 &&
|
||||
tag_start <= aiff_size) {
|
||||
// Depending, if a Tag has been added or removed,
|
||||
// the length needs to be adjusted
|
||||
if (tag == null) {
|
||||
length -= 16;
|
||||
} else {
|
||||
length -= 8;
|
||||
}
|
||||
|
||||
Insert (ByteVector.FromUInt ((uint)(aiff_size + data.Count - length), true), 4, 4);
|
||||
}
|
||||
// Update the tag types.
|
||||
TagTypesOnDisk = TagTypes;
|
||||
} finally {
|
||||
Mode = AccessMode.Closed;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a set of tag types from the current instance.
|
||||
/// </summary>
|
||||
/// <param name="types">
|
||||
/// A bitwise combined <see cref="TagLib.TagTypes" /> value
|
||||
/// containing tag types to be removed from the file.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// In order to remove all tags from a file, pass <see
|
||||
/// cref="TagTypes.AllTags" /> as <paramref name="types" />.
|
||||
/// </remarks>
|
||||
public override void RemoveTags (TagTypes types)
|
||||
{
|
||||
if (types == TagTypes.Id3v2 || types == TagTypes.AllTags) {
|
||||
tag = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a tag of a specified type from the current instance,
|
||||
/// optionally creating a new tag if possible.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="TagLib.TagTypes" /> value indicating the
|
||||
/// type of tag to read.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> value specifying whether or not to
|
||||
/// try and create the tag if one is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="Tag" /> object containing the tag that was
|
||||
/// found in or added to the current instance. If no
|
||||
/// matching tag was found and none was created, <see
|
||||
/// langword="null" /> is returned.
|
||||
/// </returns>
|
||||
public override Tag GetTag (TagTypes type, bool create)
|
||||
{
|
||||
Tag id32_tag = null;
|
||||
|
||||
switch (type) {
|
||||
case TagTypes.Id3v2:
|
||||
if (tag == null && create) {
|
||||
tag = new Id3v2.Tag {
|
||||
Version = 2
|
||||
};
|
||||
}
|
||||
|
||||
id32_tag = tag;
|
||||
break;
|
||||
}
|
||||
|
||||
return id32_tag;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Search the file for a chunk whose name is given by
|
||||
/// the chunkName parameter, starting from startPos.
|
||||
/// Note that startPos must be a valid position for a
|
||||
/// chunk, or else finding will fail.
|
||||
/// </summary>
|
||||
/// <param name="chunkName">Name of the chunk to search for</param>
|
||||
/// <param name="startPos">Position for starting the search</param>
|
||||
/// <returns>
|
||||
/// Position of the chunk in the stream, or -1
|
||||
/// if no chunk was found.
|
||||
/// </returns>
|
||||
long FindChunk (ByteVector chunkName, long startPos)
|
||||
{
|
||||
long initialPos = Tell;
|
||||
|
||||
try {
|
||||
// Start at the given position
|
||||
Seek (startPos);
|
||||
|
||||
// While not eof
|
||||
while (Tell < Length) {
|
||||
// Read 4-byte chunk name
|
||||
ByteVector chunkHeader = ReadBlock (4);
|
||||
|
||||
if (chunkHeader == chunkName) {
|
||||
// We found a matching chunk, return the position
|
||||
// of the header start
|
||||
return Tell - 4;
|
||||
} else {
|
||||
// This chunk is not the one we are looking for
|
||||
// Continue the search, seeking over the chunk
|
||||
uint chunkSize = ReadBlock (4).ToUInt ();
|
||||
// Seek forward "chunkSize" bytes
|
||||
Seek (chunkSize, System.IO.SeekOrigin.Current);
|
||||
}
|
||||
}
|
||||
|
||||
// We did not find the chunk
|
||||
return -1;
|
||||
} finally {
|
||||
Seek (initialPos);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the contents of the current instance determining
|
||||
/// the size of the riff data, the area the tagging is in,
|
||||
/// and optionally reading in the tags and media properties.
|
||||
/// </summary>
|
||||
/// <param name="read_tags">
|
||||
/// If <see langword="true" />, any tags found will be read
|
||||
/// into the current instance.
|
||||
/// </param>
|
||||
/// <param name="style">
|
||||
/// A <see cref="ReadStyle"/> value specifying how the media
|
||||
/// data is to be read into the current instance.
|
||||
/// </param>
|
||||
/// <param name="aiff_size">
|
||||
/// A <see cref="uint"/> value reference to be filled with
|
||||
/// the size of the RIFF data as read from the file.
|
||||
/// </param>
|
||||
/// <param name="tag_start">
|
||||
/// A <see cref="long" /> value reference to be filled with
|
||||
/// the absolute seek position at which the tagging data
|
||||
/// starts.
|
||||
/// </param>
|
||||
/// <param name="tag_end">
|
||||
/// A <see cref="long" /> value reference to be filled with
|
||||
/// the absolute seek position at which the tagging data
|
||||
/// ends.
|
||||
/// </param>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// The file does not begin with <see cref="FileIdentifier"
|
||||
/// />.
|
||||
/// </exception>
|
||||
void Read (bool read_tags, ReadStyle style, out uint aiff_size, out long tag_start, out long tag_end)
|
||||
{
|
||||
Seek (0);
|
||||
if (ReadBlock (4) != FileIdentifier)
|
||||
throw new CorruptFileException ("File does not begin with AIFF identifier");
|
||||
|
||||
aiff_size = ReadBlock (4).ToUInt (true);
|
||||
tag_start = -1;
|
||||
tag_end = -1;
|
||||
|
||||
// Check formType
|
||||
if (ReadBlock (4) != AIFFFormType)
|
||||
throw new CorruptFileException ("File form type is not AIFF");
|
||||
|
||||
long formBlockChunksPosition = Tell;
|
||||
|
||||
// Get the properties of the file
|
||||
if (header_block == null &&
|
||||
style != ReadStyle.None) {
|
||||
long common_chunk_pos = FindChunk (CommIdentifier, formBlockChunksPosition);
|
||||
|
||||
if (common_chunk_pos == -1) {
|
||||
throw new CorruptFileException ("No Common chunk available in AIFF file.");
|
||||
}
|
||||
|
||||
Seek (common_chunk_pos);
|
||||
header_block = ReadBlock ((int)StreamHeader.Size);
|
||||
|
||||
var header = new StreamHeader (header_block, aiff_size);
|
||||
properties = new Properties (TimeSpan.Zero, header);
|
||||
}
|
||||
|
||||
// Search for the ID3 chunk
|
||||
long id3_chunk_pos = FindChunk (ID3Identifier, formBlockChunksPosition);
|
||||
|
||||
// Search for the sound chunk
|
||||
long sound_chunk_pos = FindChunk (SoundIdentifier, formBlockChunksPosition);
|
||||
|
||||
// Ensure there is a sound chunk for the file to be valid
|
||||
if (sound_chunk_pos == -1) {
|
||||
throw new CorruptFileException ("No Sound chunk available in AIFF file.");
|
||||
}
|
||||
|
||||
// Get the length of the Sound chunk and use this as a start value to look for the ID3 chunk
|
||||
Seek (sound_chunk_pos + 4);
|
||||
|
||||
// Read the id3 chunk
|
||||
if (id3_chunk_pos > -1) {
|
||||
if (read_tags && tag == null) {
|
||||
tag = new Id3v2.Tag (this, id3_chunk_pos + 8, style);
|
||||
}
|
||||
|
||||
// Get the length of the tag out of the ID3 chunk
|
||||
Seek (id3_chunk_pos + 4);
|
||||
uint tag_size = ReadBlock (4).ToUInt (true) + 8;
|
||||
|
||||
tag_start = InvariantStartPosition = id3_chunk_pos;
|
||||
tag_end = InvariantEndPosition = tag_start + tag_size;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7c3c2cdcd3206d6c2984e6419139fc01
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,248 @@
|
||||
//
|
||||
// StreamHeader.cs: Provides support for reading Apple's AIFF stream
|
||||
// properties.
|
||||
//
|
||||
// Author:
|
||||
// Helmut Wahrmann
|
||||
//
|
||||
// Copyright (C) 2009 Helmut Wahrmann
|
||||
//
|
||||
// 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.Aiff
|
||||
{
|
||||
/// <summary>
|
||||
/// This struct implements <see cref="IAudioCodec" /> to provide
|
||||
/// support for reading Apple's AIFF stream properties.
|
||||
/// </summary>
|
||||
public struct StreamHeader : IAudioCodec, ILosslessAudioCodec
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of channels.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (9,10).
|
||||
/// 1 is monophonic, 2 is stereo, 4 means 4 channels, etc..
|
||||
/// any number of audio channels may be represented
|
||||
/// </remarks>
|
||||
readonly ushort channels;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of sample frames in the Sound Data chunk.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (11-14).
|
||||
/// </remarks>
|
||||
readonly ulong total_frames;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of bits per sample.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (15,16).
|
||||
/// It can be any number from 1 to 32.
|
||||
/// </remarks>
|
||||
readonly ushort bits_per_sample;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the sample rate.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (17-26).
|
||||
/// the sample rate at which the sound is to be played back,
|
||||
/// in sample frames per second
|
||||
/// </remarks>
|
||||
readonly ulong sample_rate;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the length of the audio stream.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is provided by the constructor.
|
||||
/// </remarks>
|
||||
readonly long stream_length;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Static Fields
|
||||
|
||||
/// <summary>
|
||||
/// The size of an AIFF Common chunk
|
||||
/// </summary>
|
||||
public const uint Size = 26;
|
||||
|
||||
/// <summary>
|
||||
/// The identifier used to recognize a AIFF file.
|
||||
/// Altough an AIFF file start with "FORM2, we're interested
|
||||
/// in the Common chunk only, which contains the properties we need.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "COMM"
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector FileIdentifier = "COMM";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="StreamHeader" /> for a specified header block and
|
||||
/// stream length.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the stream
|
||||
/// header data.
|
||||
/// </param>
|
||||
/// <param name="streamLength">
|
||||
/// A <see cref="long" /> value containing the length of the
|
||||
/// AIFF Audio stream in bytes.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="data" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// <paramref name="data" /> does not begin with <see
|
||||
/// cref="FileIdentifier" />
|
||||
/// </exception>
|
||||
public StreamHeader (ByteVector data, long streamLength)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
|
||||
if (!data.StartsWith (FileIdentifier))
|
||||
throw new CorruptFileException ("Data does not begin with identifier.");
|
||||
|
||||
stream_length = streamLength;
|
||||
|
||||
// The first 8 bytes contain the Common chunk identifier "COMM"
|
||||
// And the size of the common chunk, which is always 18
|
||||
channels = data.Mid (8, 2).ToUShort (true);
|
||||
total_frames = data.Mid (10, 4).ToULong (true);
|
||||
bits_per_sample = data.Mid (14, 2).ToUShort (true);
|
||||
sample_rate = (ulong)data.Mid (16, 10).ToExtendedPrecision ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the duration of the media represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TimeSpan" /> containing the duration of the
|
||||
/// media represented by the current instance.
|
||||
/// </value>
|
||||
public TimeSpan Duration {
|
||||
get {
|
||||
if (sample_rate <= 0 || total_frames <= 0)
|
||||
return TimeSpan.Zero;
|
||||
|
||||
return TimeSpan.FromSeconds (
|
||||
total_frames /
|
||||
(double)sample_rate);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the types of media represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Always <see cref="MediaTypes.Audio" />.
|
||||
/// </value>
|
||||
public MediaTypes MediaTypes {
|
||||
get { return MediaTypes.Audio; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a text description of the media represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing a description
|
||||
/// of the media represented by the current instance.
|
||||
/// </value>
|
||||
public string Description {
|
||||
get { return "AIFF Audio"; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bitrate of the audio represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing a bitrate of the
|
||||
/// audio represented by the current instance.
|
||||
/// </value>
|
||||
public int AudioBitrate {
|
||||
get {
|
||||
TimeSpan d = Duration;
|
||||
if (d <= TimeSpan.Zero)
|
||||
return 0;
|
||||
|
||||
return (int)((stream_length * 8L) / d.TotalSeconds) / 1000;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sample rate of the audio represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the sample rate of
|
||||
/// the audio represented by the current instance.
|
||||
/// </value>
|
||||
public int AudioSampleRate {
|
||||
get { return (int)sample_rate; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of channels in the audio represented by
|
||||
/// the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the number of
|
||||
/// channels in the audio represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public int AudioChannels {
|
||||
get { return channels; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of bits per sample in the audio
|
||||
/// represented by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the number of bits
|
||||
/// per sample in the audio represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public int BitsPerSample {
|
||||
get { return bits_per_sample; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c36b8cbc292897db7b1633bd3967807b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 81f4ff937a733e84599dd980bba85dcf
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,275 @@
|
||||
//
|
||||
// File.cs: Provides tagging and properties support for Monkey's Audio APE
|
||||
// files.
|
||||
//
|
||||
// Author:
|
||||
// Helmut Wahrmann
|
||||
//
|
||||
// Copyright (C) 2007 Helmut Wahrmann
|
||||
// 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;
|
||||
|
||||
namespace TagLib.Ape
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="TagLib.NonContainer.File" /> to
|
||||
/// provide tagging and properties support for Monkey's Audio APE
|
||||
/// files.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A <see cref="TagLib.Ape.Tag" /> will be added automatically to
|
||||
/// any file that doesn't contain one. This change does not effect
|
||||
/// the physical file until <see cref="TagLib.File.Save" /> is called and can be
|
||||
/// reversed using the following method:
|
||||
/// <code>file.RemoveTags (file.TagTypes & ~file.TagTypesOnDisk);</code>
|
||||
/// </remarks>
|
||||
[SupportedMimeType ("taglib/ape", "ape")]
|
||||
[SupportedMimeType ("audio/x-ape")]
|
||||
[SupportedMimeType ("audio/ape")]
|
||||
[SupportedMimeType ("application/x-ape")]
|
||||
public class File : TagLib.NonContainer.File
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the block with the audio header.
|
||||
/// </summary>
|
||||
ByteVector header_block;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local file
|
||||
/// system and specified read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path, ReadStyle propertiesStyle)
|
||||
: base (path, propertiesStyle)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local file
|
||||
/// system with an average read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path)
|
||||
: base (path)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction and
|
||||
/// specified read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction, ReadStyle propertiesStyle)
|
||||
: base (abstraction, propertiesStyle)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction with an
|
||||
/// average read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction)
|
||||
: base (abstraction)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a tag of a specified type from the current instance,
|
||||
/// optionally creating a new tag if possible.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="TagLib.TagTypes" /> value indicating the
|
||||
/// type of tag to read.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> value specifying whether or not to
|
||||
/// try and create the tag if one is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="Tag" /> object containing the tag that was
|
||||
/// found in or added to the current instance. If no
|
||||
/// matching tag was found and none was created, <see
|
||||
/// langword="null" /> is returned.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// If a <see cref="TagLib.Id3v2.Tag" /> is added to the
|
||||
/// current instance, it will be placed at the start of the
|
||||
/// file. On the other hand, <see cref="TagLib.Id3v1.Tag" />
|
||||
/// <see cref="TagLib.Ape.Tag" /> will be added to the end of
|
||||
/// the file. All other tag types will be ignored.
|
||||
/// </remarks>
|
||||
public override TagLib.Tag GetTag (TagTypes type, bool create)
|
||||
{
|
||||
TagLib.Tag t = (Tag as TagLib.NonContainer.Tag)
|
||||
.GetTag (type);
|
||||
|
||||
if (t != null || !create)
|
||||
return t;
|
||||
|
||||
switch (type) {
|
||||
case TagTypes.Id3v1:
|
||||
return EndTag.AddTag (type, Tag);
|
||||
|
||||
case TagTypes.Id3v2:
|
||||
return StartTag.AddTag (type, Tag);
|
||||
|
||||
case TagTypes.Ape:
|
||||
return EndTag.AddTag (type, Tag);
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Reads format specific information at the start of the
|
||||
/// file.
|
||||
/// </summary>
|
||||
/// <param name="start">
|
||||
/// A <see cref="long" /> value containing the seek position
|
||||
/// at which the tags end and the media data begins.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
protected override void ReadStart (long start, ReadStyle propertiesStyle)
|
||||
{
|
||||
if (header_block != null &&
|
||||
(propertiesStyle & ReadStyle.Average) == 0)
|
||||
return;
|
||||
|
||||
Seek (start);
|
||||
header_block = ReadBlock ((int)StreamHeader.Size);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads format specific information at the end of the
|
||||
/// file.
|
||||
/// </summary>
|
||||
/// <param name="end">
|
||||
/// A <see cref="long" /> value containing the seek position
|
||||
/// at which the media data ends and the tags begin.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
protected override void ReadEnd (long end, ReadStyle propertiesStyle)
|
||||
{
|
||||
// Make sure we have an APE tag.
|
||||
GetTag (TagTypes.Ape, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the audio properties from the file represented by
|
||||
/// the current instance.
|
||||
/// </summary>
|
||||
/// <param name="start">
|
||||
/// A <see cref="long" /> value containing the seek position
|
||||
/// at which the tags end and the media data begins.
|
||||
/// </param>
|
||||
/// <param name="end">
|
||||
/// A <see cref="long" /> value containing the seek position
|
||||
/// at which the media data ends and the tags begin.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="TagLib.Properties" /> object describing the
|
||||
/// media properties of the file represented by the current
|
||||
/// instance.
|
||||
/// </returns>
|
||||
protected override Properties ReadProperties (long start, long end, ReadStyle propertiesStyle)
|
||||
{
|
||||
StreamHeader header = new StreamHeader (header_block,
|
||||
end - start);
|
||||
|
||||
return new Properties (TimeSpan.Zero, header);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6bd919f3cebce9e6b94eb2887772bf8d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,392 @@
|
||||
//
|
||||
// Footer.cs: Provides a representation of an APEv2 tag footer which can be read
|
||||
// from and written to disk.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Original Source:
|
||||
// apefooter.cpp from TagLib
|
||||
//
|
||||
// Copyright (C) 2005-2007 Brian Nickel
|
||||
// Copyright (C) 2004 Allan Sandfeld Jensen (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
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Ape
|
||||
{
|
||||
#region Enums
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the flags applied to a <see cref="Footer" /> object.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum FooterFlags : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// The tag lacks a footer object.
|
||||
/// </summary>
|
||||
FooterAbsent = 0x40000000,
|
||||
|
||||
/// <summary>
|
||||
/// The footer is actually a header.
|
||||
/// </summary>
|
||||
IsHeader = 0x20000000,
|
||||
|
||||
/// <summary>
|
||||
/// The tag contains a header.
|
||||
/// </summary>
|
||||
HeaderPresent = 0x80000000
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This structure provides a representation of an APEv2 tag footer
|
||||
/// which can be read from and written to disk.
|
||||
/// </summary>
|
||||
public struct Footer : IEquatable<Footer>
|
||||
{
|
||||
#region Private Properties
|
||||
|
||||
/// <summary>
|
||||
/// Contains the APE tag version.
|
||||
/// </summary>
|
||||
readonly uint version;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Static Fields
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the size of an APEv2 footer.
|
||||
/// </summary>
|
||||
public const uint Size = 32;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the identifier used find an APEv2 footer in a
|
||||
/// file.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "<c>APETAGEX</c>"
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector FileIdentifier = "APETAGEX";
|
||||
|
||||
#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" /> or does not begin with <see
|
||||
/// cref="FileIdentifier" />.
|
||||
/// </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 File Identifier");
|
||||
|
||||
version = data.Mid (8, 4).ToUInt (false);
|
||||
TagSize = data.Mid (12, 4).ToUInt (false);
|
||||
ItemCount = data.Mid (16, 4).ToUInt (false);
|
||||
Flags = (FooterFlags)data.Mid (20, 4).ToUInt (false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the version of APE tag described by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the version of the
|
||||
/// APE tag described by the current instance.
|
||||
/// </value>
|
||||
public uint Version {
|
||||
get { return version == 0 ? 2000 : version; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the flags that apply to the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A bitwise combined <see cref="FooterFlags" /> value
|
||||
/// containing the flags that apply to the current instance.
|
||||
/// </value>
|
||||
public FooterFlags Flags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the number of items in the tag represented
|
||||
/// by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the number of
|
||||
/// items in the tag represented by the current instance.
|
||||
/// </value>
|
||||
public uint ItemCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the tag represented by the current
|
||||
/// instance, including the footer but excluding the header
|
||||
/// if applicable.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the size of the
|
||||
/// tag represented by the current instance.
|
||||
/// </value>
|
||||
public uint TagSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the complete size of the tag represented by the
|
||||
/// current instance, including the header and footer.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the size of the
|
||||
/// tag represented by the current instance.
|
||||
/// </value>
|
||||
public uint CompleteTagSize {
|
||||
get {
|
||||
return TagSize + ((Flags &
|
||||
FooterFlags.HeaderPresent) != 0 ?
|
||||
Size : 0);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as an APE tag footer.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public ByteVector RenderFooter ()
|
||||
{
|
||||
return Render (false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as an APE tag header.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance or an empty
|
||||
/// <see cref="ByteVector" /> object if <see cref="Flags" />
|
||||
/// does not include <see cref="FooterFlags.HeaderPresent"
|
||||
/// />.
|
||||
/// </returns>
|
||||
public ByteVector RenderHeader ()
|
||||
{
|
||||
return (Flags & FooterFlags.HeaderPresent) != 0 ? Render (true) : new ByteVector ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as either an APE tag header
|
||||
/// or footer.
|
||||
/// </summary>
|
||||
/// <param name="isHeader">
|
||||
/// A <see cref="bool" /> value indicating whether or not the
|
||||
/// current instance is to be rendered as a header.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
ByteVector Render (bool isHeader)
|
||||
{
|
||||
var v = new ByteVector {
|
||||
|
||||
// add the file identifier -- "APETAGEX"
|
||||
FileIdentifier,
|
||||
|
||||
// add the version number -- we always render a 2.000
|
||||
// tag regardless of what the tag originally was.
|
||||
ByteVector.FromUInt (2000, false),
|
||||
|
||||
// add the tag size
|
||||
ByteVector.FromUInt (TagSize, false),
|
||||
|
||||
// add the item count
|
||||
ByteVector.FromUInt (ItemCount, false)
|
||||
};
|
||||
|
||||
// render and add the flags
|
||||
uint flags = 0;
|
||||
|
||||
if ((Flags & FooterFlags.HeaderPresent) != 0)
|
||||
flags |= (uint)FooterFlags.HeaderPresent;
|
||||
|
||||
// footer is always present
|
||||
if (isHeader)
|
||||
flags |= (uint)FooterFlags.IsHeader;
|
||||
else
|
||||
flags &= (uint)~FooterFlags.IsHeader;
|
||||
|
||||
v.Add (ByteVector.FromUInt (flags, false));
|
||||
|
||||
// add the reserved 64bit
|
||||
v.Add (ByteVector.FromULong (0));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region IEquatable
|
||||
|
||||
/// <summary>
|
||||
/// Generates a hash code for the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="int" /> value containing the hash code for
|
||||
/// the current instance.
|
||||
/// </returns>
|
||||
public override int GetHashCode ()
|
||||
{
|
||||
unchecked {
|
||||
return (int)((uint)Flags ^ TagSize ^ ItemCount ^ version);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether or not the current instance is equal to
|
||||
/// another object.
|
||||
/// </summary>
|
||||
/// <param name="other">
|
||||
/// A <see cref="object" /> to compare to the current
|
||||
/// instance.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="bool" /> value indicating whether or not the
|
||||
/// current instance is equal to <paramref name="other" />.
|
||||
/// </returns>
|
||||
/// <seealso cref="M:System.IEquatable`1.Equals" />
|
||||
public override bool Equals (object other)
|
||||
{
|
||||
if (!(other is Footer))
|
||||
return false;
|
||||
|
||||
return Equals ((Footer)other);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether or not the current instance is equal to
|
||||
/// another instance of <see cref="Footer" />.
|
||||
/// </summary>
|
||||
/// <param name="other">
|
||||
/// A <see cref="Footer" /> object to compare to the current
|
||||
/// instance.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="bool" /> value indicating whether or not the
|
||||
/// current instance is equal to <paramref name="other" />.
|
||||
/// </returns>
|
||||
/// <seealso cref="M:System.IEquatable`1.Equals" />
|
||||
public bool Equals (Footer other)
|
||||
{
|
||||
return Flags == other.Flags &&
|
||||
TagSize == other.TagSize &&
|
||||
ItemCount == other.ItemCount &&
|
||||
version == other.version;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not two instances of <see cref="Footer"
|
||||
/// /> are equal to eachother.
|
||||
/// </summary>
|
||||
/// <param name="first">
|
||||
/// The first <see cref="Footer" /> object to compare.
|
||||
/// </param>
|
||||
/// <param name="second">
|
||||
/// The second <see cref="Footer" /> object to compare.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if <paramref name="first" /> is
|
||||
/// equal to <paramref name="second" />. Otherwise, <see
|
||||
/// langword="false" />.
|
||||
/// </returns>
|
||||
public static bool operator == (Footer first, Footer second)
|
||||
{
|
||||
return first.Equals (second);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not two instances of <see cref="Footer"
|
||||
/// /> are unequal to eachother.
|
||||
/// </summary>
|
||||
/// <param name="first">
|
||||
/// The first <see cref="Footer" /> object to compare.
|
||||
/// </param>
|
||||
/// <param name="second">
|
||||
/// The second <see cref="Footer" /> object to compare.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if <paramref name="first" /> is
|
||||
/// unequal to <paramref name="second" />. Otherwise, <see
|
||||
/// langword="false" />.
|
||||
/// </returns>
|
||||
public static bool operator != (Footer first, Footer second)
|
||||
{
|
||||
return !first.Equals (second);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3fd643b62da0d63f89725b4266c74752
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,500 @@
|
||||
//
|
||||
// Item.cs: Provides a representation of an APEv2 tag item which can be read
|
||||
// from and written to disk.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Original Source:
|
||||
// apeitem.cpp from TagLib
|
||||
//
|
||||
// Copyright (C) 2005-2007 Brian Nickel
|
||||
// Copyright (C) 2004 by Allan Sandfeld Jensen (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.Ape
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the type of data stored in a <see cref="Item" />
|
||||
/// object.
|
||||
/// </summary>
|
||||
public enum ItemType
|
||||
{
|
||||
/// <summary>
|
||||
/// The item contains Unicode text.
|
||||
/// </summary>
|
||||
Text = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The item contains binary data.
|
||||
/// </summary>
|
||||
Binary = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The item contains a locator (file path/URL) for external
|
||||
/// information.
|
||||
/// </summary>
|
||||
Locator = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This class provides a representation of an APEv2 tag item which
|
||||
/// can be read from and written to disk.
|
||||
/// </summary>
|
||||
public class Item : ICloneable
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the item value.
|
||||
/// </summary>
|
||||
ReadOnlyByteVector data;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the item text.
|
||||
/// </summary>
|
||||
string[] text;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Item" /> by reading in a raw APEv2 item.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the item to
|
||||
/// read.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// A <see cref="int" /> value specifying the offset in
|
||||
/// <paramref name="data" /> at which the item data begins.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="data" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="offset" /> is less than zero.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// A complete item could not be read.
|
||||
/// </exception>
|
||||
public Item (ByteVector data, int offset)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
Parse (data, offset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Item" /> with a specified key and value.
|
||||
/// </summary>
|
||||
/// <param name="key">
|
||||
/// A <see cref="string" /> object containing the key to use
|
||||
/// for the current instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="string" /> object containing the value to
|
||||
/// store in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="key" /> or <paramref name="value" /> is
|
||||
/// <see langword="null" />.
|
||||
/// </exception>
|
||||
public Item (string key, string value)
|
||||
{
|
||||
if (key == null)
|
||||
throw new ArgumentNullException (nameof (key));
|
||||
|
||||
if (value == null)
|
||||
throw new ArgumentNullException (nameof (value));
|
||||
|
||||
Key = key;
|
||||
text = new [] { value };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Item" /> with a specified key and collection of
|
||||
/// values.
|
||||
/// </summary>
|
||||
/// <param name="key">
|
||||
/// A <see cref="string" /> object containing the key to use
|
||||
/// for the current instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="T:string[]" /> containing the values to store
|
||||
/// in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="key" /> or <paramref name="value" /> is
|
||||
/// <see langword="null" />.
|
||||
/// </exception>
|
||||
public Item (string key, params string[] value)
|
||||
{
|
||||
if (key == null)
|
||||
throw new ArgumentNullException (nameof (key));
|
||||
|
||||
if (value == null)
|
||||
throw new ArgumentNullException (nameof (value));
|
||||
|
||||
Key = key;
|
||||
text = (string[])value.Clone ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Item" /> with a specified key and collection of
|
||||
/// values.
|
||||
/// </summary>
|
||||
/// <param name="key">
|
||||
/// A <see cref="string" /> object containing the key to use
|
||||
/// for the current instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="StringCollection" /> object containing the
|
||||
/// values to store in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="key" /> or <paramref name="value" /> is
|
||||
/// <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <seealso cref="Item(string,string[])" />
|
||||
[Obsolete ("Use Item(string,string[])")]
|
||||
public Item (string key, StringCollection value)
|
||||
{
|
||||
if (key == null)
|
||||
throw new ArgumentNullException (nameof (key));
|
||||
|
||||
if (value == null)
|
||||
throw new ArgumentNullException (nameof (value));
|
||||
|
||||
Key = key;
|
||||
text = value.ToArray ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Item" /> with a specified key and raw data.
|
||||
/// </summary>
|
||||
/// <param name="key">
|
||||
/// A <see cref="string" /> object containing the key to use
|
||||
/// for the current instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="StringCollection" /> object containing the
|
||||
/// values to store in the new instance.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// This constructor automatically marks the new instance as
|
||||
/// <see cref="ItemType.Binary" />.
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="key" /> or <paramref name="value" /> is
|
||||
/// <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <seealso cref="Item(string,string[])" />
|
||||
public Item (string key, ByteVector value)
|
||||
{
|
||||
Key = key;
|
||||
Type = ItemType.Binary;
|
||||
|
||||
data = value as ReadOnlyByteVector;
|
||||
if (data == null)
|
||||
data = new ReadOnlyByteVector (value);
|
||||
}
|
||||
|
||||
Item (Item item)
|
||||
{
|
||||
Type = item.Type;
|
||||
Key = item.Key;
|
||||
|
||||
if (item.data != null)
|
||||
data = new ReadOnlyByteVector (item.data);
|
||||
|
||||
if (item.text != null)
|
||||
text = (string[])item.text.Clone ();
|
||||
|
||||
ReadOnly = item.ReadOnly;
|
||||
Size = item.Size;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the key used to identify the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing the key used to
|
||||
/// identify the current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// This value is used for specifying the contents of the
|
||||
/// item in a common and consistant fashion. For example,
|
||||
/// <c>"TITLE"</c> specifies that the item contains the title
|
||||
/// of the track.
|
||||
/// </remarks>
|
||||
public string Key { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the binary value stored in the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ByteVector" /> object containing the binary
|
||||
/// value stored in the current instance, or <see
|
||||
/// langword="null" /> if the item contains text.
|
||||
/// </value>
|
||||
public ByteVector Value {
|
||||
get { return (Type == ItemType.Binary) ? data : null; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the current instance as it last appeared
|
||||
/// on disk.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the size of the
|
||||
/// current instance as it last appeared on disk.
|
||||
/// </value>
|
||||
public int Size { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the type of value contained in the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ItemType" /> value indicating the type of
|
||||
/// value contained in the current instance.
|
||||
/// </value>
|
||||
public ItemType Type { get; set; } = ItemType.Text;
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets whether or not the current instance is
|
||||
/// flagged as read-only on disk.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="bool" /> value indicating whether or not the
|
||||
/// current instance is flagged as read-only on disk.
|
||||
/// </value>
|
||||
public bool ReadOnly { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not the current instance is empty.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="bool" /> value indicating whether or not the
|
||||
/// current instance contains no value.
|
||||
/// </value>
|
||||
public bool IsEmpty {
|
||||
get {
|
||||
if (Type != ItemType.Binary)
|
||||
return text == null || text.Length == 0;
|
||||
else
|
||||
return data == null || data.IsEmpty;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets the contents of the current instance as a <see
|
||||
/// cref="string" />.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// <para>A <see cref="string" /> object containing the text
|
||||
/// stored in the current instance, or <see langword="null"
|
||||
/// /> if the item is empty of contains binary data.</para>
|
||||
/// <para>If the current instance contains multiple string
|
||||
/// values, they will be returned as a comma separated
|
||||
/// value.</para>
|
||||
/// </returns>
|
||||
public override string ToString ()
|
||||
{
|
||||
if (Type == ItemType.Binary || text == null)
|
||||
return null;
|
||||
|
||||
return string.Join (", ", text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the contents of the current instance as a <see
|
||||
/// cref="string" /> array.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="T:string[]" /> containing the text stored in
|
||||
/// the current instance, or an empty array if the item
|
||||
/// contains binary data.
|
||||
/// </returns>
|
||||
public string[] ToStringArray ()
|
||||
{
|
||||
if (Type == ItemType.Binary || text == null)
|
||||
return new string[0];
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as an APEv2 item.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public ByteVector Render ()
|
||||
{
|
||||
uint flags = (uint)((ReadOnly) ? 1 : 0) |
|
||||
((uint)Type << 1);
|
||||
|
||||
if (IsEmpty)
|
||||
return new ByteVector ();
|
||||
|
||||
ByteVector result = null;
|
||||
|
||||
if (Type == ItemType.Binary) {
|
||||
if (text == null && data != null)
|
||||
result = data;
|
||||
}
|
||||
|
||||
if (result == null && text != null) {
|
||||
result = new ByteVector ();
|
||||
|
||||
for (int i = 0; i < text.Length; i++) {
|
||||
if (i != 0)
|
||||
result.Add (0);
|
||||
|
||||
result.Add (ByteVector.FromString (text[i], StringType.UTF8));
|
||||
}
|
||||
}
|
||||
|
||||
// If no data is stored, don't write the item.
|
||||
if (result == null || result.Count == 0)
|
||||
return new ByteVector ();
|
||||
|
||||
var output = new ByteVector {
|
||||
ByteVector.FromUInt ((uint)result.Count,
|
||||
false),
|
||||
ByteVector.FromUInt (flags, false),
|
||||
ByteVector.FromString (Key, StringType.UTF8),
|
||||
0,
|
||||
result
|
||||
};
|
||||
|
||||
Size = output.Count;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Populates the current instance by reading in a raw APEv2
|
||||
/// item.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the item to
|
||||
/// read.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// A <see cref="int" /> value specifying the offset in
|
||||
/// <paramref name="data" /> at which the item data begins.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="data" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="offset" /> is less than zero.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// A complete item could not be read.
|
||||
/// </exception>
|
||||
protected void Parse (ByteVector data, int offset)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
if (offset < 0)
|
||||
throw new ArgumentOutOfRangeException (nameof (offset));
|
||||
|
||||
|
||||
// 11 bytes is the minimum size for an APE item
|
||||
if (data.Count < offset + 11)
|
||||
throw new CorruptFileException ("Not enough data for APE Item");
|
||||
|
||||
uint value_length = data.Mid (offset, 4).ToUInt (false);
|
||||
uint flags = data.Mid (offset + 4, 4).ToUInt (false);
|
||||
|
||||
ReadOnly = (flags & 1) == 1;
|
||||
Type = (ItemType)((flags >> 1) & 3);
|
||||
|
||||
int pos = data.Find (ByteVector.TextDelimiter (StringType.UTF8), offset + 8);
|
||||
|
||||
Key = data.ToString (StringType.UTF8, offset + 8, pos - offset - 8);
|
||||
|
||||
if (value_length > data.Count - pos - 1)
|
||||
throw new CorruptFileException ("Invalid data length.");
|
||||
|
||||
Size = pos + 1 + (int)value_length - offset;
|
||||
|
||||
if (Type == ItemType.Binary)
|
||||
this.data = new ReadOnlyByteVector (data.Mid (pos + 1, (int)value_length));
|
||||
else
|
||||
text = data.Mid (pos + 1, (int)value_length).ToStrings (StringType.UTF8, 0);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region ICloneable
|
||||
|
||||
/// <summary>
|
||||
/// Creates a deep copy of the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A new <see cref="Item"/> object identical to the current
|
||||
/// instance.
|
||||
/// </returns>
|
||||
public Item Clone ()
|
||||
{
|
||||
return new Item (this);
|
||||
}
|
||||
|
||||
object ICloneable.Clone ()
|
||||
{
|
||||
return Clone ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ec6d7edea3a67467d8e074bff4ac65d7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,359 @@
|
||||
//
|
||||
// StreamHeader.cs: Provides support for reading Monkey's Audio APE stream
|
||||
// properties.
|
||||
//
|
||||
// Author:
|
||||
// Helmut Wahrmann
|
||||
//
|
||||
// Copyright (C) 2007 Helmut Wahrmann
|
||||
// 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;
|
||||
using System.Globalization;
|
||||
|
||||
namespace TagLib.Ape
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the compression level used when encoding a Monkey's
|
||||
/// Audio APE file.
|
||||
/// </summary>
|
||||
public enum CompressionLevel
|
||||
{
|
||||
/// <summary>
|
||||
/// The audio is not compressed.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The audio is mildly compressed.
|
||||
/// </summary>
|
||||
Fast = 1000,
|
||||
|
||||
/// <summary>
|
||||
/// The audio is compressed at a normal level.
|
||||
/// </summary>
|
||||
Normal = 2000,
|
||||
|
||||
/// <summary>
|
||||
/// The audio is highly compressed.
|
||||
/// </summary>
|
||||
High = 3000,
|
||||
|
||||
/// <summary>
|
||||
/// The audio is extremely highly compressed.
|
||||
/// </summary>
|
||||
ExtraHigh = 4000,
|
||||
|
||||
/// <summary>
|
||||
/// The audio is compressed to an insane level.
|
||||
/// </summary>
|
||||
Insane
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This struct implements <see cref="IAudioCodec" /> to provide
|
||||
/// support for reading Monkey's Audio APE stream properties.
|
||||
/// </summary>
|
||||
public struct StreamHeader : IAudioCodec, ILosslessAudioCodec
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the APE version.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (4,5) of the file and is
|
||||
/// 1000 times the actual version number, so 3810 indicates
|
||||
/// version 3.81.
|
||||
/// </remarks>
|
||||
readonly ushort version;
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// Contains the format flags.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (53,54).
|
||||
/// </remarks>
|
||||
private ushort format_flags;
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of audio blocks in one frame.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (55-58).
|
||||
/// </remarks>
|
||||
readonly uint blocks_per_frame;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of audio blocks in the final frame.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (59-62).
|
||||
/// </remarks>
|
||||
readonly uint final_frame_blocks;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the total number of frames.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (63-66).
|
||||
/// </remarks>
|
||||
readonly uint total_frames;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of bits per sample.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (67,68) and is typically
|
||||
/// 16.
|
||||
/// </remarks>
|
||||
readonly ushort bits_per_sample;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of channels.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (69,70) and is typically
|
||||
/// 1 or 2.
|
||||
/// </remarks>
|
||||
readonly ushort channels;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the sample rate.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (71-74) and is typically
|
||||
/// 44100.
|
||||
/// </remarks>
|
||||
readonly uint sample_rate;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the length of the audio stream.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is provided by the constructor.
|
||||
/// </remarks>
|
||||
readonly long stream_length;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Static Fields
|
||||
|
||||
/// <summary>
|
||||
/// The size of a Monkey Audio header.
|
||||
/// </summary>
|
||||
public const uint Size = 76;
|
||||
|
||||
/// <summary>
|
||||
/// The identifier used to recognize a WavPack file.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "MAC "
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector FileIdentifier = "MAC ";
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="StreamHeader" /> for a specified header block and
|
||||
/// stream length.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the stream
|
||||
/// header data.
|
||||
/// </param>
|
||||
/// <param name="streamLength">
|
||||
/// A <see cref="long" /> value containing the length of the
|
||||
/// Monkey Audio stream in bytes.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="data" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// <paramref name="data" /> does not begin with <see
|
||||
/// cref="FileIdentifier" /> or is less than <see cref="Size"
|
||||
/// /> bytes long.
|
||||
/// </exception>
|
||||
public StreamHeader (ByteVector data, long streamLength)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
if (!data.StartsWith (FileIdentifier))
|
||||
throw new CorruptFileException (
|
||||
"Data does not begin with identifier.");
|
||||
|
||||
if (data.Count < Size)
|
||||
throw new CorruptFileException (
|
||||
"Insufficient data in stream header");
|
||||
|
||||
stream_length = streamLength;
|
||||
version = data.Mid (4, 2).ToUShort (false);
|
||||
Compression = (CompressionLevel)data.Mid (52, 2)
|
||||
.ToUShort (false);
|
||||
// format_flags = data.Mid(54, 2).ToUShort(false);
|
||||
blocks_per_frame = data.Mid (56, 4).ToUInt (false);
|
||||
final_frame_blocks = data.Mid (60, 4).ToUInt (false);
|
||||
total_frames = data.Mid (64, 4).ToUInt (false);
|
||||
bits_per_sample = data.Mid (68, 2).ToUShort (false);
|
||||
channels = data.Mid (70, 2).ToUShort (false);
|
||||
sample_rate = data.Mid (72, 4).ToUInt (false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the duration of the media represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TimeSpan" /> containing the duration of the
|
||||
/// media represented by the current instance.
|
||||
/// </value>
|
||||
public TimeSpan Duration {
|
||||
get {
|
||||
if (sample_rate <= 0 || total_frames <= 0)
|
||||
return TimeSpan.Zero;
|
||||
|
||||
return TimeSpan.FromSeconds (
|
||||
((total_frames - 1) *
|
||||
blocks_per_frame + final_frame_blocks) /
|
||||
(double)sample_rate);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the types of media represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Always <see cref="MediaTypes.Audio" />.
|
||||
/// </value>
|
||||
public MediaTypes MediaTypes {
|
||||
get { return MediaTypes.Audio; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a text description of the media represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing a description
|
||||
/// of the media represented by the current instance.
|
||||
/// </value>
|
||||
public string Description {
|
||||
get {
|
||||
return string.Format (
|
||||
CultureInfo.InvariantCulture, "Monkey's Audio APE Version {0:0.000}", Version);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bitrate of the audio represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing a bitrate of the
|
||||
/// audio represented by the current instance.
|
||||
/// </value>
|
||||
public int AudioBitrate {
|
||||
get {
|
||||
TimeSpan d = Duration;
|
||||
if (d <= TimeSpan.Zero)
|
||||
return 0;
|
||||
|
||||
return (int)((stream_length * 8L) / d.TotalSeconds) / 1000;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sample rate of the audio represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the sample rate of
|
||||
/// the audio represented by the current instance.
|
||||
/// </value>
|
||||
public int AudioSampleRate {
|
||||
get { return (int)sample_rate; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of channels in the audio represented by
|
||||
/// the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the number of
|
||||
/// channels in the audio represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public int AudioChannels {
|
||||
get { return channels; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the APE version of the audio represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="double" /> value containing the APE version
|
||||
/// of the audio represented by the current instance.
|
||||
/// </value>
|
||||
public double Version {
|
||||
get { return version / (double)1000; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of bits per sample in the audio
|
||||
/// represented by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the number of bits
|
||||
/// per sample in the audio represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public int BitsPerSample {
|
||||
get { return bits_per_sample; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the level of compression used when encoding the
|
||||
/// audio represented by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="CompressionLevel" /> value indicating the
|
||||
/// level of compression used when encoding the audio
|
||||
/// represented by the current instance.
|
||||
/// </value>
|
||||
public CompressionLevel Compression { get; private set; }
|
||||
|
||||
#endregion
|
||||
}␍}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d8234dea7db8f83ed86cb702f3474bbe
|
||||
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: e937bf4e5ed85bb70b1660583e8eb5dc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5551302f5547e0525a891b390866fb18
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,263 @@
|
||||
//
|
||||
// ContentDescriptionObject.cs: Provides a representation of an ASF Content
|
||||
// Description object which can be read from and written to disk.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Object" /> to provide a
|
||||
/// representation of an ASF Content Description object which can be
|
||||
/// read from and written to disk.
|
||||
/// </summary>
|
||||
public class ContentDescriptionObject : Object
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the media title.
|
||||
/// </summary>
|
||||
string title = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the author/performer.
|
||||
/// </summary>
|
||||
string author = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the copyright information.
|
||||
/// </summary>
|
||||
string copyright = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the description of the media.
|
||||
/// </summary>
|
||||
string description = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the rating of the media.
|
||||
/// </summary>
|
||||
string rating = string.Empty;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ContentDescriptionObject" /> by reading the
|
||||
/// contents from a specified position in a specified file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object containing the file from
|
||||
/// which the contents of the new instance are to be read.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specify at what position to
|
||||
/// read the object.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="position" /> is less than zero or greater
|
||||
/// than the size of the file.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// The object read from disk does not have the correct GUID
|
||||
/// or smaller than the minimum size.
|
||||
/// </exception>
|
||||
public ContentDescriptionObject (File file, long position)
|
||||
: base (file, position)
|
||||
{
|
||||
if (Guid != Asf.Guid.AsfContentDescriptionObject)
|
||||
throw new CorruptFileException ("Object GUID incorrect.");
|
||||
|
||||
if (OriginalSize < 34)
|
||||
throw new CorruptFileException ("Object size too small.");
|
||||
|
||||
ushort title_length = file.ReadWord ();
|
||||
ushort author_length = file.ReadWord ();
|
||||
ushort copyright_length = file.ReadWord ();
|
||||
ushort description_length = file.ReadWord ();
|
||||
ushort rating_length = file.ReadWord ();
|
||||
|
||||
title = file.ReadUnicode (title_length);
|
||||
author = file.ReadUnicode (author_length);
|
||||
copyright = file.ReadUnicode (copyright_length);
|
||||
description = file.ReadUnicode (description_length);
|
||||
rating = file.ReadUnicode (rating_length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ContentDescriptionObject" /> with no contents.
|
||||
/// </summary>
|
||||
public ContentDescriptionObject ()
|
||||
: base (Asf.Guid.AsfContentDescriptionObject)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Region
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the title of the media described by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing the title of
|
||||
/// the media or <see langword="null" /> if it is not set.
|
||||
/// </value>
|
||||
public string Title {
|
||||
get { return title.Length == 0 ? null : title; }
|
||||
set {
|
||||
title = string.IsNullOrEmpty (value) ? string.Empty : value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the author or performer of the media
|
||||
/// described by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing the author of
|
||||
/// the media or <see langword="null" /> if it is not set.
|
||||
/// </value>
|
||||
public string Author {
|
||||
get { return author.Length == 0 ? null : author; }
|
||||
set {
|
||||
author = string.IsNullOrEmpty (value) ? string.Empty : value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the copyright information for the media
|
||||
/// described by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing the copyright
|
||||
/// information for the media or <see langword="null" /> if
|
||||
/// it is not set.
|
||||
/// </value>
|
||||
public string Copyright {
|
||||
get { return copyright.Length == 0 ? null : copyright; }
|
||||
set {
|
||||
copyright = string.IsNullOrEmpty (value) ? string.Empty : value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the description of the media described by
|
||||
/// the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing a description
|
||||
/// of the media or <see langword="null" /> if it is not set.
|
||||
/// </value>
|
||||
public string Description {
|
||||
get {
|
||||
return description.Length == 0 ? null : description;
|
||||
}
|
||||
set {
|
||||
description = string.IsNullOrEmpty (value) ? string.Empty : value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the rating of the media described by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing a rating of the
|
||||
/// media or <see langword="null" /> if it is not set.
|
||||
/// </value>
|
||||
public string Rating {
|
||||
get { return rating.Length == 0 ? null : rating; }
|
||||
set {
|
||||
rating = string.IsNullOrEmpty (value) ? string.Empty : value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not the current instance is empty.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <see langword="true" /> if all the values are cleared.
|
||||
/// Otherwise <see langword="false" />.
|
||||
/// </value>
|
||||
public bool IsEmpty {
|
||||
get {
|
||||
return title.Length == 0 &&
|
||||
author.Length == 0 &&
|
||||
copyright.Length == 0 &&
|
||||
description.Length == 0 &&
|
||||
rating.Length == 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Region
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ASF object.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public override ByteVector Render ()
|
||||
{
|
||||
ByteVector title_bytes = RenderUnicode (title);
|
||||
ByteVector author_bytes = RenderUnicode (author);
|
||||
ByteVector copyright_bytes = RenderUnicode (copyright);
|
||||
ByteVector description_bytes =
|
||||
RenderUnicode (description);
|
||||
ByteVector rating_bytes = RenderUnicode (rating);
|
||||
|
||||
ByteVector output = RenderWord ((ushort)
|
||||
title_bytes.Count);
|
||||
output.Add (RenderWord ((ushort)author_bytes.Count));
|
||||
output.Add (RenderWord ((ushort)copyright_bytes.Count));
|
||||
output.Add (RenderWord ((ushort)
|
||||
description_bytes.Count));
|
||||
output.Add (RenderWord ((ushort)rating_bytes.Count));
|
||||
output.Add (title_bytes);
|
||||
output.Add (author_bytes);
|
||||
output.Add (copyright_bytes);
|
||||
output.Add (description_bytes);
|
||||
output.Add (rating_bytes);
|
||||
|
||||
return Render (output);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f526cfb69af160d3c9edf6227f73e985
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,474 @@
|
||||
//
|
||||
// ContentDescriptor.cs: Provides a representation of an ASF Content Descriptor
|
||||
// to be used in combination with ExtendedContentDescriptionObject.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the type of data stored in a <see
|
||||
/// cref="ContentDescriptor" /> or <see cref="DescriptionRecord" />
|
||||
/// object.
|
||||
/// </summary>
|
||||
public enum DataType
|
||||
{
|
||||
/// <summary>
|
||||
/// The descriptor contains Unicode (UTF-16LE) text.
|
||||
/// </summary>
|
||||
Unicode = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The descriptor contains binary data.
|
||||
/// </summary>
|
||||
Bytes = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The descriptor contains a boolean value.
|
||||
/// </summary>
|
||||
Bool = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The descriptor contains a 4-byte DWORD value.
|
||||
/// </summary>
|
||||
DWord = 3,
|
||||
|
||||
/// <summary>
|
||||
/// The descriptor contains a 8-byte QWORD value.
|
||||
/// </summary>
|
||||
QWord = 4,
|
||||
|
||||
/// <summary>
|
||||
/// The descriptor contains a 2-byte WORD value.
|
||||
/// </summary>
|
||||
Word = 5,
|
||||
|
||||
/// <summary>
|
||||
/// The descriptor contains a 16-byte GUID value.
|
||||
/// </summary>
|
||||
Guid = 6
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This class provides a representation of an ASF Content
|
||||
/// Descriptor to be used in combination with <see
|
||||
/// cref="ExtendedContentDescriptionObject" />.
|
||||
/// </summary>
|
||||
public class ContentDescriptor
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the string value.
|
||||
/// </summary>
|
||||
string strValue;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the byte value.
|
||||
/// </summary>
|
||||
ByteVector byteValue;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the long value.
|
||||
/// </summary>
|
||||
ulong longValue;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ContentDescriptor" /> with a specified name and
|
||||
/// and value.
|
||||
/// </summary>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// new instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="string" /> object containing the value for
|
||||
/// the new instance.
|
||||
/// </param>
|
||||
public ContentDescriptor (string name, string value)
|
||||
{
|
||||
Name = name;
|
||||
strValue = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ContentDescriptor" /> with a specified name and
|
||||
/// and value.
|
||||
/// </summary>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// new instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="ByteVector" /> object containing the value
|
||||
/// for the new instance.
|
||||
/// </param>
|
||||
public ContentDescriptor (string name, ByteVector value)
|
||||
{
|
||||
Name = name;
|
||||
Type = DataType.Bytes;
|
||||
byteValue = new ByteVector (value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ContentDescriptor" /> with a specified name and
|
||||
/// and value.
|
||||
/// </summary>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// new instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="uint" /> value containing the value
|
||||
/// for the new instance.
|
||||
/// </param>
|
||||
public ContentDescriptor (string name, uint value)
|
||||
{
|
||||
Name = name;
|
||||
Type = DataType.DWord;
|
||||
longValue = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ContentDescriptor" /> with a specified name and
|
||||
/// and value.
|
||||
/// </summary>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// new instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="ulong" /> value containing the value
|
||||
/// for the new instance.
|
||||
/// </param>
|
||||
public ContentDescriptor (string name, ulong value)
|
||||
{
|
||||
Name = name;
|
||||
Type = DataType.QWord;
|
||||
longValue = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ContentDescriptor" /> with a specified name and
|
||||
/// and value.
|
||||
/// </summary>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// new instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="ushort" /> value containing the value
|
||||
/// for the new instance.
|
||||
/// </param>
|
||||
public ContentDescriptor (string name, ushort value)
|
||||
{
|
||||
Name = name;
|
||||
Type = DataType.Word;
|
||||
longValue = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ContentDescriptor" /> with a specified name and
|
||||
/// and value.
|
||||
/// </summary>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// new instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="bool" /> value containing the value
|
||||
/// for the new instance.
|
||||
/// </param>
|
||||
public ContentDescriptor (string name, bool value)
|
||||
{
|
||||
Name = name;
|
||||
Type = DataType.Bool;
|
||||
longValue = value ? 1uL : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ContentDescriptor" /> by reading its contents from
|
||||
/// a file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object to read the raw ASF
|
||||
/// Description Record from.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// A valid descriptor could not be read.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// <paramref name="file" /> must be at a seek position at
|
||||
/// which the descriptor can be read.
|
||||
/// </remarks>
|
||||
protected internal ContentDescriptor (File file)
|
||||
{
|
||||
if (file == null)
|
||||
throw new ArgumentNullException (nameof (file));
|
||||
|
||||
if (!Parse (file))
|
||||
throw new CorruptFileException ("Failed to parse content descriptor.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// current instance.
|
||||
/// </value>
|
||||
public string Name { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of data contained in the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="DataType" /> value indicating type of data
|
||||
/// contained in the current instance.
|
||||
/// </value>
|
||||
public DataType Type { get; private set; } = DataType.Unicode;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string representation of the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="string" /> object containing the value of
|
||||
/// the current instance.
|
||||
/// </returns>
|
||||
public override string ToString ()
|
||||
{
|
||||
if (Type == DataType.Unicode)
|
||||
return strValue;
|
||||
|
||||
if (Type == DataType.Bytes)
|
||||
return byteValue.ToString (StringType.UTF16LE);
|
||||
|
||||
return longValue.ToString ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the binary contents of the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// contents of the current instance, or <see langword="null"
|
||||
/// /> if <see cref="Type" /> is unequal to <see
|
||||
/// cref="DataType.Bytes" />.
|
||||
/// </returns>
|
||||
public ByteVector ToByteVector ()
|
||||
{
|
||||
return byteValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the boolean value contained in the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="bool" /> value containing the value of the
|
||||
/// current instance.
|
||||
/// </returns>
|
||||
public bool ToBool ()
|
||||
{
|
||||
return longValue != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the DWORD value contained in the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="uint" /> value containing the value of the
|
||||
/// current instance.
|
||||
/// </returns>
|
||||
public uint ToDWord ()
|
||||
{
|
||||
if (Type == DataType.Unicode && strValue != null && uint.TryParse (strValue, out var value))
|
||||
return value;
|
||||
|
||||
return (uint)longValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the QWORD value contained in the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ulong" /> value containing the value of the
|
||||
/// current instance.
|
||||
/// </returns>
|
||||
public ulong ToQWord ()
|
||||
{
|
||||
if (Type == DataType.Unicode && strValue != null && ulong.TryParse (strValue, out var value))
|
||||
return value;
|
||||
|
||||
return longValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the WORD value contained in the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ushort" /> value containing the value of the
|
||||
/// current instance.
|
||||
/// </returns>
|
||||
public ushort ToWord ()
|
||||
{
|
||||
if (Type == DataType.Unicode && strValue != null && ushort.TryParse (strValue, out var value))
|
||||
return value;
|
||||
|
||||
return (ushort)longValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ASF Description
|
||||
/// Record.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public ByteVector Render ()
|
||||
{
|
||||
ByteVector value;
|
||||
|
||||
switch (Type) {
|
||||
case DataType.Unicode:
|
||||
value = Object.RenderUnicode (strValue);
|
||||
break;
|
||||
case DataType.Bytes:
|
||||
value = byteValue;
|
||||
break;
|
||||
case DataType.Bool:
|
||||
case DataType.DWord:
|
||||
value = Object.RenderDWord ((uint)longValue);
|
||||
break;
|
||||
case DataType.QWord:
|
||||
value = Object.RenderQWord (longValue);
|
||||
break;
|
||||
case DataType.Word:
|
||||
value = Object.RenderWord ((ushort)longValue);
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
ByteVector name = Object.RenderUnicode (Name);
|
||||
|
||||
var output = new ByteVector {
|
||||
Object.RenderWord ((ushort)name.Count),
|
||||
name,
|
||||
Object.RenderWord ((ushort)Type),
|
||||
Object.RenderWord ((ushort)value.Count),
|
||||
value
|
||||
};
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Populates the current instance by reading in the contents
|
||||
/// from a file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object to read the raw ASF
|
||||
/// Content Descriptor from.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if the data was read correctly.
|
||||
/// Otherwise <see langword="false" />.
|
||||
/// </returns>
|
||||
protected bool Parse (File file)
|
||||
{
|
||||
int name_count = file.ReadWord ();
|
||||
Name = file.ReadUnicode (name_count);
|
||||
|
||||
Type = (DataType)file.ReadWord ();
|
||||
|
||||
int value_count = file.ReadWord ();
|
||||
switch (Type) {
|
||||
case DataType.Word:
|
||||
longValue = file.ReadWord ();
|
||||
break;
|
||||
|
||||
case DataType.Bool:
|
||||
longValue = file.ReadDWord ();
|
||||
break;
|
||||
|
||||
case DataType.DWord:
|
||||
longValue = file.ReadDWord ();
|
||||
break;
|
||||
|
||||
case DataType.QWord:
|
||||
longValue = file.ReadQWord ();
|
||||
break;
|
||||
|
||||
case DataType.Unicode:
|
||||
strValue = file.ReadUnicode (value_count);
|
||||
break;
|
||||
|
||||
case DataType.Bytes:
|
||||
byteValue = file.ReadBlock (value_count);
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 12848f0d0cefe0dd3864fc18248f7482
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,568 @@
|
||||
//
|
||||
// DescriptionRecord.cs: Provides a representation of an ASF Description Record
|
||||
// to be used in combination with MetadataLibaryObject.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// This class provides a representation of an ASF Description Record
|
||||
/// to be used in combination with <see cref="MetadataLibraryObject"
|
||||
/// />.
|
||||
/// </summary>
|
||||
public class DescriptionRecord
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the string value.
|
||||
/// </summary>
|
||||
string strValue;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the byte value.
|
||||
/// </summary>
|
||||
ByteVector byteValue;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the long value.
|
||||
/// </summary>
|
||||
ulong longValue;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the GUID value.
|
||||
/// </summary>
|
||||
System.Guid guidValue = System.Guid.Empty;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="DescriptionRecord" /> with a specified language,
|
||||
/// stream, name, and value.
|
||||
/// </summary>
|
||||
/// <param name="languageListIndex">
|
||||
/// A <see cref="ushort" /> value containing the language
|
||||
/// list index of the new instance.
|
||||
/// </param>
|
||||
/// <param name="streamNumber">
|
||||
/// A <see cref="ushort" /> value containing the stream
|
||||
/// number of the new instance.
|
||||
/// </param>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// new instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="string" /> object containing the value for
|
||||
/// the new instance.
|
||||
/// </param>
|
||||
public DescriptionRecord (ushort languageListIndex, ushort streamNumber, string name, string value)
|
||||
{
|
||||
LanguageListIndex = languageListIndex;
|
||||
StreamNumber = streamNumber;
|
||||
Name = name;
|
||||
strValue = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="DescriptionRecord" /> with a specified language,
|
||||
/// stream, name, and value.
|
||||
/// </summary>
|
||||
/// <param name="languageListIndex">
|
||||
/// A <see cref="ushort" /> value containing the language
|
||||
/// list index of the new instance.
|
||||
/// </param>
|
||||
/// <param name="streamNumber">
|
||||
/// A <see cref="ushort" /> value containing the stream
|
||||
/// number of the new instance.
|
||||
/// </param>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// new instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="ByteVector" /> object containing the value
|
||||
/// for the new instance.
|
||||
/// </param>
|
||||
public DescriptionRecord (ushort languageListIndex, ushort streamNumber, string name, ByteVector value)
|
||||
{
|
||||
LanguageListIndex = languageListIndex;
|
||||
StreamNumber = streamNumber;
|
||||
Name = name;
|
||||
Type = DataType.Bytes;
|
||||
byteValue = new ByteVector (value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="DescriptionRecord" /> with a specified language,
|
||||
/// stream, name, and value.
|
||||
/// </summary>
|
||||
/// <param name="languageListIndex">
|
||||
/// A <see cref="ushort" /> value containing the language
|
||||
/// list index of the new instance.
|
||||
/// </param>
|
||||
/// <param name="streamNumber">
|
||||
/// A <see cref="ushort" /> value containing the stream
|
||||
/// number of the new instance.
|
||||
/// </param>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// new instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="uint" /> value containing the value
|
||||
/// for the new instance.
|
||||
/// </param>
|
||||
public DescriptionRecord (ushort languageListIndex, ushort streamNumber, string name, uint value)
|
||||
{
|
||||
LanguageListIndex = languageListIndex;
|
||||
StreamNumber = streamNumber;
|
||||
Name = name;
|
||||
Type = DataType.DWord;
|
||||
longValue = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="DescriptionRecord" /> with a specified language,
|
||||
/// stream, name, and value.
|
||||
/// </summary>
|
||||
/// <param name="languageListIndex">
|
||||
/// A <see cref="ushort" /> value containing the language
|
||||
/// list index of the new instance.
|
||||
/// </param>
|
||||
/// <param name="streamNumber">
|
||||
/// A <see cref="ushort" /> value containing the stream
|
||||
/// number of the new instance.
|
||||
/// </param>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// new instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="ulong" /> value containing the value
|
||||
/// for the new instance.
|
||||
/// </param>
|
||||
public DescriptionRecord (ushort languageListIndex, ushort streamNumber, string name, ulong value)
|
||||
{
|
||||
LanguageListIndex = languageListIndex;
|
||||
StreamNumber = streamNumber;
|
||||
Name = name;
|
||||
Type = DataType.QWord;
|
||||
longValue = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="DescriptionRecord" /> with a specified language,
|
||||
/// stream, name, and value.
|
||||
/// </summary>
|
||||
/// <param name="languageListIndex">
|
||||
/// A <see cref="ushort" /> value containing the language
|
||||
/// list index of the new instance.
|
||||
/// </param>
|
||||
/// <param name="streamNumber">
|
||||
/// A <see cref="ushort" /> value containing the stream
|
||||
/// number of the new instance.
|
||||
/// </param>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// new instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="ushort" /> value containing the value
|
||||
/// for the new instance.
|
||||
/// </param>
|
||||
public DescriptionRecord (ushort languageListIndex, ushort streamNumber, string name, ushort value)
|
||||
{
|
||||
LanguageListIndex = languageListIndex;
|
||||
StreamNumber = streamNumber;
|
||||
Name = name;
|
||||
Type = DataType.Word;
|
||||
longValue = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="DescriptionRecord" /> with a specified language,
|
||||
/// stream, name, and value.
|
||||
/// </summary>
|
||||
/// <param name="languageListIndex">
|
||||
/// A <see cref="ushort" /> value containing the language
|
||||
/// list index of the new instance.
|
||||
/// </param>
|
||||
/// <param name="streamNumber">
|
||||
/// A <see cref="ushort" /> value containing the stream
|
||||
/// number of the new instance.
|
||||
/// </param>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// new instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="bool" /> value containing the value
|
||||
/// for the new instance.
|
||||
/// </param>
|
||||
public DescriptionRecord (ushort languageListIndex, ushort streamNumber, string name, bool value)
|
||||
{
|
||||
LanguageListIndex = languageListIndex;
|
||||
StreamNumber = streamNumber;
|
||||
Name = name;
|
||||
Type = DataType.Bool;
|
||||
longValue = value ? 1uL : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="DescriptionRecord" /> with a specified language,
|
||||
/// stream, name, and value.
|
||||
/// </summary>
|
||||
/// <param name="languageListIndex">
|
||||
/// A <see cref="ushort" /> value containing the language
|
||||
/// list index of the new instance.
|
||||
/// </param>
|
||||
/// <param name="streamNumber">
|
||||
/// A <see cref="ushort" /> value containing the stream
|
||||
/// number of the new instance.
|
||||
/// </param>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// new instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="System.Guid" /> value containing the value
|
||||
/// for the new instance.
|
||||
/// </param>
|
||||
public DescriptionRecord (ushort languageListIndex, ushort streamNumber, string name, System.Guid value)
|
||||
{
|
||||
LanguageListIndex = languageListIndex;
|
||||
StreamNumber = streamNumber;
|
||||
Name = name;
|
||||
Type = DataType.Guid;
|
||||
guidValue = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="DescriptionRecord" /> by reading its contents from
|
||||
/// a file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object to read the raw ASF
|
||||
/// Description Record from.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// A valid record could not be read.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// <paramref name="file" /> must be at a seek position at
|
||||
/// which the record can be read.
|
||||
/// </remarks>
|
||||
protected internal DescriptionRecord (File file)
|
||||
{
|
||||
if (file == null)
|
||||
throw new ArgumentNullException (nameof (file));
|
||||
|
||||
if (!Parse (file))
|
||||
throw new CorruptFileException ("Failed to parse description record.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the index of the language associated with the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ushort" /> value containing the index of the
|
||||
/// language associated with the current instance.
|
||||
/// </value>
|
||||
public ushort LanguageListIndex { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the index of the stream associated with the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ushort" /> value containing the index of the
|
||||
/// stream associated with the current instance.
|
||||
/// </value>
|
||||
public ushort StreamNumber { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// current instance.
|
||||
/// </value>
|
||||
public string Name { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of data contained in the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="DataType" /> value indicating type of data
|
||||
/// contained in the current instance.
|
||||
/// </value>
|
||||
public DataType Type { get; private set; } = DataType.Unicode;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string representation of the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="string" /> object containing the value of
|
||||
/// the current instance.
|
||||
/// </returns>
|
||||
public override string ToString ()
|
||||
{
|
||||
if (Type == DataType.Unicode)
|
||||
return strValue;
|
||||
|
||||
if (Type == DataType.Bytes)
|
||||
return byteValue.ToString (StringType.UTF16LE);
|
||||
|
||||
return longValue.ToString ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the binary contents of the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// contents of the current instance, or <see langword="null"
|
||||
/// /> if <see cref="Type" /> is unequal to <see
|
||||
/// cref="DataType.Bytes" />.
|
||||
/// </returns>
|
||||
public ByteVector ToByteVector ()
|
||||
{
|
||||
return byteValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the boolean value contained in the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="bool" /> value containing the value of the
|
||||
/// current instance.
|
||||
/// </returns>
|
||||
public bool ToBool ()
|
||||
{
|
||||
return longValue != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the DWORD value contained in the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="uint" /> value containing the value of the
|
||||
/// current instance.
|
||||
/// </returns>
|
||||
public uint ToDWord ()
|
||||
{
|
||||
if (Type == DataType.Unicode && strValue != null && uint.TryParse (strValue, out var value))
|
||||
return value;
|
||||
|
||||
return (uint)longValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the QWORD value contained in the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ulong" /> value containing the value of the
|
||||
/// current instance.
|
||||
/// </returns>
|
||||
public ulong ToQWord ()
|
||||
{
|
||||
if (Type == DataType.Unicode && strValue != null && ulong.TryParse (strValue, out var value))
|
||||
return value;
|
||||
|
||||
return longValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the WORD value contained in the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ushort" /> value containing the value of the
|
||||
/// current instance.
|
||||
/// </returns>
|
||||
public ushort ToWord ()
|
||||
{
|
||||
if (Type == DataType.Unicode && strValue != null && ushort.TryParse (strValue, out var value))
|
||||
return value;
|
||||
|
||||
return (ushort)longValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the GUID value contained in the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="System.Guid" /> value containing the value
|
||||
/// of the current instance.
|
||||
/// </returns>
|
||||
public System.Guid ToGuid ()
|
||||
{
|
||||
return guidValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ASF Description
|
||||
/// Record.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public ByteVector Render ()
|
||||
{
|
||||
ByteVector value;
|
||||
|
||||
switch (Type) {
|
||||
case DataType.Unicode:
|
||||
value = Object.RenderUnicode (strValue);
|
||||
break;
|
||||
case DataType.Bytes:
|
||||
value = byteValue;
|
||||
break;
|
||||
case DataType.Bool:
|
||||
case DataType.DWord:
|
||||
value = Object.RenderDWord ((uint)longValue);
|
||||
break;
|
||||
case DataType.QWord:
|
||||
value = Object.RenderQWord (longValue);
|
||||
break;
|
||||
case DataType.Word:
|
||||
value = Object.RenderWord ((ushort)longValue);
|
||||
break;
|
||||
case DataType.Guid:
|
||||
value = guidValue.ToByteArray ();
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
ByteVector name = Object.RenderUnicode (Name);
|
||||
|
||||
var output = new ByteVector {
|
||||
Object.RenderWord (LanguageListIndex),
|
||||
Object.RenderWord (StreamNumber),
|
||||
Object.RenderWord ((ushort)name.Count),
|
||||
Object.RenderWord ((ushort)Type),
|
||||
Object.RenderDWord ((uint)value.Count),
|
||||
name,
|
||||
value
|
||||
};
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Populates the current instance by reading in the contents
|
||||
/// from a file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object to read the raw ASF
|
||||
/// Description Record from.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if the data was read correctly.
|
||||
/// Otherwise <see langword="false" />.
|
||||
/// </returns>
|
||||
protected bool Parse (File file)
|
||||
{
|
||||
// Field name Field type Size (bits)
|
||||
// Language List Index WORD 16
|
||||
// Stream Number WORD 16
|
||||
// Name Length WORD 16
|
||||
// Data Type WORD 16
|
||||
// Data Length DWORD 32
|
||||
// Name WCHAR varies
|
||||
// Data See below varies
|
||||
|
||||
LanguageListIndex = file.ReadWord ();
|
||||
StreamNumber = file.ReadWord ();
|
||||
ushort name_length = file.ReadWord ();
|
||||
Type = (DataType)file.ReadWord ();
|
||||
int data_length = (int)file.ReadDWord ();
|
||||
Name = file.ReadUnicode (name_length);
|
||||
|
||||
switch (Type) {
|
||||
case DataType.Word:
|
||||
longValue = file.ReadWord ();
|
||||
break;
|
||||
case DataType.Bool:
|
||||
case DataType.DWord:
|
||||
longValue = file.ReadDWord ();
|
||||
break;
|
||||
case DataType.QWord:
|
||||
longValue = file.ReadQWord ();
|
||||
break;
|
||||
case DataType.Unicode:
|
||||
strValue = file.ReadUnicode (data_length);
|
||||
break;
|
||||
case DataType.Bytes:
|
||||
byteValue = file.ReadBlock (data_length);
|
||||
break;
|
||||
case DataType.Guid:
|
||||
guidValue = file.ReadGuid ();
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b240cea38450eb09286babb6fd6d82c7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,270 @@
|
||||
//
|
||||
// ExtendedContentDescriptionObject.cs: Provides a representation of an ASF
|
||||
// Extended Content Description object which can be read from and written to
|
||||
// disk.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Object" /> to provide a
|
||||
/// representation of an ASF Extended Content Description object
|
||||
/// which can be read from and written to disk.
|
||||
/// </summary>
|
||||
public class ExtendedContentDescriptionObject : Object, IEnumerable<ContentDescriptor>
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the content descriptors.
|
||||
/// </summary>
|
||||
readonly List<ContentDescriptor> descriptors = new List<ContentDescriptor> ();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ExtendedContentDescriptionObject" /> by reading the
|
||||
/// contents from a specified position in a specified file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object containing the file from
|
||||
/// which the contents of the new instance are to be read.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specify at what position to
|
||||
/// read the object.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="position" /> is less than zero or greater
|
||||
/// than the size of the file.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// The object read from disk does not have the correct GUID
|
||||
/// or smaller than the minimum size.
|
||||
/// </exception>
|
||||
public ExtendedContentDescriptionObject (File file, long position)
|
||||
: base (file, position)
|
||||
{
|
||||
if (!Guid.Equals (Asf.Guid.AsfExtendedContentDescriptionObject))
|
||||
throw new CorruptFileException ("Object GUID incorrect.");
|
||||
|
||||
if (OriginalSize < 26)
|
||||
throw new CorruptFileException ("Object size too small.");
|
||||
|
||||
ushort count = file.ReadWord ();
|
||||
|
||||
for (ushort i = 0; i < count; i++)
|
||||
AddDescriptor (new ContentDescriptor (file));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ExtendedContentDescriptionObject" /> with no
|
||||
/// contents.
|
||||
/// </summary>
|
||||
public ExtendedContentDescriptionObject ()
|
||||
: base (Asf.Guid.AsfExtendedContentDescriptionObject)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not the current instance is empty.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <see langword="true" /> if the current instance doesn't
|
||||
/// contain any <see cref="ContentDescriptor" /> objects.
|
||||
/// Otherwise <see langword="false" />.
|
||||
/// </value>
|
||||
public bool IsEmpty {
|
||||
get { return descriptors.Count == 0; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ASF object.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public override ByteVector Render ()
|
||||
{
|
||||
ByteVector output = new ByteVector ();
|
||||
ushort count = 0;
|
||||
|
||||
foreach (ContentDescriptor desc in descriptors) {
|
||||
count++;
|
||||
output.Add (desc.Render ());
|
||||
}
|
||||
|
||||
return Render (RenderWord (count) + output);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all descriptors with a given name from the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// descriptors to be removed.
|
||||
/// </param>
|
||||
public void RemoveDescriptors (string name)
|
||||
{
|
||||
for (int i = descriptors.Count - 1; i >= 0; i--)
|
||||
if (name == descriptors[i].Name)
|
||||
descriptors.RemoveAt (i);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all descriptors with any of a collection of names
|
||||
/// from the current instance.
|
||||
/// </summary>
|
||||
/// <param name="names">
|
||||
/// A <see cref="T:string[]" /> containing the names of the
|
||||
/// descriptors to be retrieved.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="names" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <returns>
|
||||
/// A <see cref="T:System.Collections.Generic.IEnumerable`1" /> object enumerating
|
||||
/// through the <see cref="ContentDescriptor" /> objects
|
||||
/// retrieved from the current instance.
|
||||
/// </returns>
|
||||
public IEnumerable<ContentDescriptor> GetDescriptors (params string[] names)
|
||||
{
|
||||
if (names == null)
|
||||
throw new ArgumentNullException (nameof (names));
|
||||
|
||||
foreach (string name in names)
|
||||
foreach (ContentDescriptor desc in descriptors)
|
||||
if (desc.Name == name)
|
||||
yield return desc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a descriptor to the current instance.
|
||||
/// </summary>
|
||||
/// <param name="descriptor">
|
||||
/// A <see cref="ContentDescriptor" /> object to add to the
|
||||
/// current instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="descriptor" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public void AddDescriptor (ContentDescriptor descriptor)
|
||||
{
|
||||
if (descriptor == null)
|
||||
throw new ArgumentNullException (nameof (descriptor));
|
||||
|
||||
descriptors.Add (descriptor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the a collection of desciptors for a given name,
|
||||
/// removing the existing matching records.
|
||||
/// </summary>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// descriptors to be added.
|
||||
/// </param>
|
||||
/// <param name="descriptors">
|
||||
/// A <see cref="T:ContentDescriptor[]" /> containing
|
||||
/// descriptors to add to the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="name" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// All added entries in <paramref name="descriptors" />
|
||||
/// should match <paramref name="name" /> but it is not
|
||||
/// verified by the method. The descriptors will be added
|
||||
/// with their own names and not the one provided in this
|
||||
/// method, which are used for removing existing values and
|
||||
/// determining where to position the new objects.
|
||||
/// </remarks>
|
||||
public void SetDescriptors (string name, params ContentDescriptor[] descriptors)
|
||||
{
|
||||
if (name == null)
|
||||
throw new ArgumentNullException (nameof (name));
|
||||
|
||||
int position = this.descriptors.Count;
|
||||
for (int i = this.descriptors.Count - 1; i >= 0; i--) {
|
||||
if (name == this.descriptors[i].Name) {
|
||||
this.descriptors.RemoveAt (i);
|
||||
position = i;
|
||||
}
|
||||
}
|
||||
this.descriptors.InsertRange (position, descriptors);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region IEnumerable
|
||||
|
||||
/// <summary>
|
||||
/// Gets an enumerator for enumerating through the content
|
||||
/// descriptors.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="T:System.Collections.IEnumerator`1" /> for
|
||||
/// enumerating through the content descriptors.
|
||||
/// </returns>
|
||||
public IEnumerator<ContentDescriptor> GetEnumerator ()
|
||||
{
|
||||
return descriptors.GetEnumerator ();
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator
|
||||
System.Collections.IEnumerable.GetEnumerator ()
|
||||
{
|
||||
return descriptors.GetEnumerator ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d284fb627fd9b464a993ff8f4769b52c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,436 @@
|
||||
//
|
||||
// File.cs: Provides tagging and properties support for Microsoft's ASF files.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="TagLib.File" /> to provide tagging
|
||||
/// and properties support for Microsoft's ASF files.
|
||||
/// </summary>
|
||||
[SupportedMimeType ("taglib/wma", "wma")]
|
||||
[SupportedMimeType ("taglib/wmv", "wmv")]
|
||||
[SupportedMimeType ("taglib/asf", "asf")]
|
||||
[SupportedMimeType ("audio/x-ms-wma")]
|
||||
[SupportedMimeType ("audio/x-ms-asf")]
|
||||
[SupportedMimeType ("video/x-ms-asf")]
|
||||
public class File : TagLib.File
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the file's tag.
|
||||
/// </summary>
|
||||
Tag asf_tag;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the file's properties.
|
||||
/// </summary>
|
||||
Properties properties;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local file
|
||||
/// system and specified read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path, ReadStyle propertiesStyle)
|
||||
: base (path)
|
||||
{
|
||||
Read (propertiesStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local file
|
||||
/// system with an average read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path)
|
||||
: this (path, ReadStyle.Average)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction and
|
||||
/// specified read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction, ReadStyle propertiesStyle)
|
||||
: base (abstraction)
|
||||
{
|
||||
Read (propertiesStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction with an
|
||||
/// average read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction)
|
||||
: this (abstraction, ReadStyle.Average)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets a abstract representation of all tags stored in the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TagLib.Tag" /> object representing all tags
|
||||
/// stored in the current instance.
|
||||
/// </value>
|
||||
public override TagLib.Tag Tag {
|
||||
get { return asf_tag; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the media properties of the file represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TagLib.Properties" /> object containing the
|
||||
/// media properties of the file represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public override Properties Properties {
|
||||
get { return properties; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Saves the changes made in the current instance to the
|
||||
/// file it represents.
|
||||
/// </summary>
|
||||
public override void Save ()
|
||||
{
|
||||
// Boilerplate
|
||||
PreSave ();
|
||||
|
||||
Mode = AccessMode.Write;
|
||||
try {
|
||||
var header = new HeaderObject (this, 0);
|
||||
|
||||
if (asf_tag == null) {
|
||||
header.RemoveContentDescriptors ();
|
||||
TagTypesOnDisk &= ~TagTypes.Asf;
|
||||
} else {
|
||||
TagTypesOnDisk |= TagTypes.Asf;
|
||||
header.AddUniqueObject (
|
||||
asf_tag.ContentDescriptionObject);
|
||||
header.AddUniqueObject (
|
||||
asf_tag.ExtendedContentDescriptionObject);
|
||||
header.Extension.AddUniqueObject (
|
||||
asf_tag.MetadataLibraryObject);
|
||||
}
|
||||
|
||||
var output = header.Render ();
|
||||
long diff = output.Count - (long)header.OriginalSize;
|
||||
Insert (output, 0, (long)header.OriginalSize);
|
||||
|
||||
InvariantStartPosition += diff;
|
||||
InvariantEndPosition += diff;
|
||||
} finally {
|
||||
Mode = AccessMode.Closed;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a tag of a specified type from the current instance,
|
||||
/// optionally creating a new tag if possible.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="TagLib.TagTypes" /> value indicating the
|
||||
/// type of tag to read.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> value specifying whether or not to
|
||||
/// try and create the tag if one is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="Tag" /> object containing the tag that was
|
||||
/// found in or added to the current instance. If no
|
||||
/// matching tag was found and none was created, <see
|
||||
/// langword="null" /> is returned.
|
||||
/// </returns>
|
||||
public override TagLib.Tag GetTag (TagTypes type, bool create)
|
||||
{
|
||||
if (type == TagTypes.Asf)
|
||||
return asf_tag;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a set of tag types from the current instance.
|
||||
/// </summary>
|
||||
/// <param name="types">
|
||||
/// A bitwise combined <see cref="TagLib.TagTypes" /> value
|
||||
/// containing tag types to be removed from the file.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// In order to remove all tags from a file, pass <see
|
||||
/// cref="TagTypes.AllTags" /> as <paramref name="types" />.
|
||||
/// </remarks>
|
||||
public override void RemoveTags (TagTypes types)
|
||||
{
|
||||
if ((types & TagTypes.Asf) == TagTypes.Asf)
|
||||
asf_tag.Clear ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 2-byte WORD from the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ushort" /> value containing the WORD read
|
||||
/// from the current instance.
|
||||
/// </returns>
|
||||
public ushort ReadWord ()
|
||||
{
|
||||
return ReadBlock (2).ToUShort (false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 4-byte DWORD from the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="uint" /> value containing the DWORD read
|
||||
/// from the current instance.
|
||||
/// </returns>
|
||||
public uint ReadDWord ()
|
||||
{
|
||||
return ReadBlock (4).ToUInt (false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 8-byte QWORD from the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ulong" /> value containing the QWORD read
|
||||
/// from the current instance.
|
||||
/// </returns>
|
||||
public ulong ReadQWord ()
|
||||
{
|
||||
return ReadBlock (8).ToULong (false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 16-byte GUID from the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="System.Guid" /> value containing the GUID
|
||||
/// read from the current instance.
|
||||
/// </returns>
|
||||
public System.Guid ReadGuid ()
|
||||
{
|
||||
return new System.Guid (ReadBlock (16).Data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a Unicode (UTF-16LE) string of specified length
|
||||
/// from the current instance.
|
||||
/// </summary>
|
||||
/// <param name="length">
|
||||
/// A <see cref="int" /> value specifying the number of bytes
|
||||
/// to read. This should always be an even number.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="string" /> object containing the Unicode
|
||||
/// string read from the current instance.
|
||||
/// </returns>
|
||||
public string ReadUnicode (int length)
|
||||
{
|
||||
ByteVector data = ReadBlock (length);
|
||||
string output = data.ToString (StringType.UTF16LE);
|
||||
int i = output.IndexOf ('\0');
|
||||
return (i >= 0) ? output.Substring (0, i) : output;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a collection of objects from the current instance.
|
||||
/// </summary>
|
||||
/// <param name="count">
|
||||
/// A <see cref="uint" /> value specifying the number of
|
||||
/// objects to read.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specifying the seek position
|
||||
/// at which to start reading.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A new <see cref="T:System.Collections.Generic.IEnumerable`1" /> object enumerating
|
||||
/// through the <see cref="Object" /> objects read from the
|
||||
/// current instance.
|
||||
/// </returns>
|
||||
public IEnumerable<Object> ReadObjects (uint count,
|
||||
long position)
|
||||
{
|
||||
for (int i = 0; i < (int)count; i++) {
|
||||
Object obj = ReadObject (position);
|
||||
position += (long)obj.OriginalSize;
|
||||
yield return obj;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a <see cref="Object" /> from the current instance.
|
||||
/// </summary>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specifying the seek position
|
||||
/// at which to start reading.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A new <see cref="Object" /> object of appropriate type as
|
||||
/// read from the current instance.
|
||||
/// </returns>
|
||||
public Object ReadObject (long position)
|
||||
{
|
||||
Seek (position);
|
||||
System.Guid id = ReadGuid ();
|
||||
|
||||
if (id.Equals (Guid.AsfFilePropertiesObject))
|
||||
return new FilePropertiesObject (this,
|
||||
position);
|
||||
|
||||
if (id.Equals (Guid.AsfStreamPropertiesObject))
|
||||
return new StreamPropertiesObject (this,
|
||||
position);
|
||||
|
||||
if (id.Equals (Guid.AsfContentDescriptionObject))
|
||||
return new ContentDescriptionObject (this,
|
||||
position);
|
||||
|
||||
if (id.Equals (
|
||||
Guid.AsfExtendedContentDescriptionObject))
|
||||
return new ExtendedContentDescriptionObject (
|
||||
this, position);
|
||||
|
||||
if (id.Equals (Guid.AsfPaddingObject))
|
||||
return new PaddingObject (this, position);
|
||||
|
||||
if (id.Equals (Guid.AsfHeaderExtensionObject))
|
||||
return new HeaderExtensionObject (this,
|
||||
position);
|
||||
|
||||
if (id.Equals (Guid.AsfMetadataLibraryObject))
|
||||
return new MetadataLibraryObject (this,
|
||||
position);
|
||||
|
||||
return new UnknownObject (this, position);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Reads the contents of the current instance.
|
||||
/// </summary>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
void Read (ReadStyle propertiesStyle)
|
||||
{
|
||||
Mode = AccessMode.Read;
|
||||
try {
|
||||
HeaderObject header = new HeaderObject (this, 0);
|
||||
|
||||
if (header.HasContentDescriptors)
|
||||
TagTypesOnDisk |= TagTypes.Asf;
|
||||
|
||||
asf_tag = new Tag (header);
|
||||
|
||||
InvariantStartPosition = (long)header.OriginalSize;
|
||||
InvariantEndPosition = Length;
|
||||
|
||||
if ((propertiesStyle & ReadStyle.Average) != 0)
|
||||
properties = header.Properties;
|
||||
} finally {
|
||||
Mode = AccessMode.Closed;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 230597e1f22d7c4048805f50836d30b1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,275 @@
|
||||
//
|
||||
// FilePropertiesObject.cs: Provides a representation of an ASF File Properties
|
||||
// object which can be read from and written to disk.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Object" /> to provide a
|
||||
/// representation of an ASF File Properties object which can be read
|
||||
/// from and written to disk.
|
||||
/// </summary>
|
||||
public class FilePropertiesObject : Object
|
||||
{
|
||||
#region Constant Values
|
||||
|
||||
static readonly DateTime FileTimeOffset = new DateTime (1601, 1, 1);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the GUID for the file.
|
||||
/// </summary>
|
||||
System.Guid file_id;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the creation date.
|
||||
/// </summary>
|
||||
readonly ulong creation_date;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the play duration.
|
||||
/// </summary>
|
||||
readonly ulong play_duration;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the send duration.
|
||||
/// </summary>
|
||||
readonly ulong send_duration;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="FilePropertiesObject" /> by reading the contents
|
||||
/// from a specified position in a specified file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object containing the file from
|
||||
/// which the contents of the new instance are to be read.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specify at what position to
|
||||
/// read the object.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="position" /> is less than zero or greater
|
||||
/// than the size of the file.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// The object read from disk does not have the correct GUID
|
||||
/// or smaller than the minimum size.
|
||||
/// </exception>
|
||||
public FilePropertiesObject (File file, long position)
|
||||
: base (file, position)
|
||||
{
|
||||
if (!Guid.Equals (Asf.Guid.AsfFilePropertiesObject))
|
||||
throw new CorruptFileException ("Object GUID incorrect.");
|
||||
|
||||
if (OriginalSize < 104)
|
||||
throw new CorruptFileException ("Object size too small.");
|
||||
|
||||
file_id = file.ReadGuid ();
|
||||
FileSize = file.ReadQWord ();
|
||||
creation_date = file.ReadQWord ();
|
||||
DataPacketsCount = file.ReadQWord ();
|
||||
play_duration = file.ReadQWord ();
|
||||
send_duration = file.ReadQWord ();
|
||||
Preroll = file.ReadQWord ();
|
||||
Flags = file.ReadDWord ();
|
||||
MinimumDataPacketSize = file.ReadDWord ();
|
||||
MaximumDataPacketSize = file.ReadDWord ();
|
||||
MaximumBitrate = file.ReadDWord ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the GUID for the file described by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="System.Guid" /> value containing the GUID
|
||||
/// for the file described by the current instance.
|
||||
/// </value>
|
||||
public System.Guid FileId {
|
||||
get { return file_id; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the file described by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ulong" /> value containing the size of the
|
||||
/// file described by the current instance.
|
||||
/// </value>
|
||||
public ulong FileSize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the creation date of the file described by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="DateTime" /> value containing the creation
|
||||
/// date of the file described by the current instance.
|
||||
/// </value>
|
||||
public DateTime CreationDate {
|
||||
get { return new DateTime ((long)creation_date + FileTimeOffset.Ticks); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of data packets in the file described by
|
||||
/// the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ulong" /> value containing the number of
|
||||
/// data packets in the file described by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public ulong DataPacketsCount { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the play duration of the file described by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TimeSpan" /> value containing the play
|
||||
/// duration of the file described by the current instance.
|
||||
/// </value>
|
||||
public TimeSpan PlayDuration {
|
||||
get { return new TimeSpan ((long)play_duration); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the send duration of the file described by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TimeSpan" /> value containing the send
|
||||
/// duration of the file described by the current instance.
|
||||
/// </value>
|
||||
public TimeSpan SendDuration {
|
||||
get { return new TimeSpan ((long)send_duration); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the pre-roll of the file described by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ulong" /> value containing the pre-roll of
|
||||
/// the file described by the current instance.
|
||||
/// </value>
|
||||
public ulong Preroll { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the flags of the file described by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the flags of the
|
||||
/// file described by the current instance.
|
||||
/// </value>
|
||||
public uint Flags { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the minimum data packet size of the file described
|
||||
/// by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the minimum data
|
||||
/// packet size of the file described by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public uint MinimumDataPacketSize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum data packet size of the file described
|
||||
/// by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the maximum data
|
||||
/// packet size of the file described by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public uint MaximumDataPacketSize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum bitrate of the file described by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the maximum
|
||||
/// bitrate of the file described by the current instance.
|
||||
/// </value>
|
||||
public uint MaximumBitrate { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ASF object.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public override ByteVector Render ()
|
||||
{
|
||||
ByteVector output = file_id.ToByteArray ();
|
||||
output.Add (RenderQWord (FileSize));
|
||||
output.Add (RenderQWord (creation_date));
|
||||
output.Add (RenderQWord (DataPacketsCount));
|
||||
output.Add (RenderQWord (play_duration));
|
||||
output.Add (RenderQWord (send_duration));
|
||||
output.Add (RenderQWord (Preroll));
|
||||
output.Add (RenderDWord (Flags));
|
||||
output.Add (RenderDWord (MinimumDataPacketSize));
|
||||
output.Add (RenderDWord (MaximumDataPacketSize));
|
||||
output.Add (RenderDWord (MaximumBitrate));
|
||||
|
||||
return Render (output);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aadef2fcac80345fe8d8d585ba22aed5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,110 @@
|
||||
//
|
||||
// Guid.cs: Provides common GUID values used by ASF Objects.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// This static class contains common <see cref="System.Guid" />
|
||||
/// values used by ASF Objects.
|
||||
/// </summary>
|
||||
public static class Guid
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that an object is a <see
|
||||
/// cref="ContentDescriptionObject" />.
|
||||
/// </summary>
|
||||
public static readonly System.Guid AsfContentDescriptionObject =
|
||||
new System.Guid ("75B22633-668E-11CF-A6D9-00AA0062CE6C");
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that an object is a <see
|
||||
/// cref="ExtendedContentDescriptionObject" />.
|
||||
/// </summary>
|
||||
public static readonly System.Guid AsfExtendedContentDescriptionObject =
|
||||
new System.Guid ("D2D0A440-E307-11D2-97F0-00A0C95EA850");
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that an object is a <see
|
||||
/// cref="FilePropertiesObject" />.
|
||||
/// </summary>
|
||||
public static readonly System.Guid AsfFilePropertiesObject =
|
||||
new System.Guid ("8CABDCA1-A947-11CF-8EE4-00C00C205365");
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that an object is a <see
|
||||
/// cref="HeaderExtensionObject" />.
|
||||
/// </summary>
|
||||
public static readonly System.Guid AsfHeaderExtensionObject =
|
||||
new System.Guid ("5FBF03B5-A92E-11CF-8EE3-00C00C205365");
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that an object is a <see
|
||||
/// cref="HeaderObject" />.
|
||||
/// </summary>
|
||||
public static readonly System.Guid AsfHeaderObject =
|
||||
new System.Guid ("75B22630-668E-11CF-A6D9-00AA0062CE6C");
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that an object is a <see
|
||||
/// cref="MetadataLibraryObject" />.
|
||||
/// </summary>
|
||||
public static readonly System.Guid AsfMetadataLibraryObject =
|
||||
new System.Guid ("44231C94-9498-49D1-A141-1D134E457054");
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that an object is a <see
|
||||
/// cref="PaddingObject" />.
|
||||
/// </summary>
|
||||
public static readonly System.Guid AsfPaddingObject =
|
||||
new System.Guid ("1806D474-CADF-4509-A4BA-9AABCB96AAE8");
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that an object is a <see
|
||||
/// cref="StreamPropertiesObject" />.
|
||||
/// </summary>
|
||||
public static readonly System.Guid AsfStreamPropertiesObject =
|
||||
new System.Guid ("B7DC0791-A9B7-11CF-8EE6-00C00C205365");
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that a <see cref="StreamPropertiesObject" />
|
||||
/// contains information about an audio stream.
|
||||
/// </summary>
|
||||
public static readonly System.Guid AsfAudioMedia =
|
||||
new System.Guid ("F8699E40-5B4D-11CF-A8FD-00805F5C442B");
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that a <see cref="StreamPropertiesObject" />
|
||||
/// contains information about an video stream.
|
||||
/// </summary>
|
||||
public static readonly System.Guid AsfVideoMedia =
|
||||
new System.Guid ("BC19EFC0-5B4D-11CF-A8FD-00805F5C442B");
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a placeholder portion of a file is correctly
|
||||
/// encoded.
|
||||
/// </summary>
|
||||
public static readonly System.Guid AsfReserved1 =
|
||||
new System.Guid ("ABD3D211-A9BA-11cf-8EE6-00C00C205365");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 106d81de03690f00d9a5574b209c688b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,174 @@
|
||||
//
|
||||
// HeaderExtensionObject.cs: Provides a representation of an ASF Header
|
||||
// Extension object which can be read from and written to disk.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Object" /> to provide a
|
||||
/// representation of an ASF Header Extension object which can be
|
||||
/// read from and written to disk.
|
||||
/// </summary>
|
||||
public class HeaderExtensionObject : Object
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the child objects.
|
||||
/// </summary>
|
||||
readonly List<Object> children = new List<Object> ();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="HeaderExtensionObject" /> by reading the contents
|
||||
/// from a specified position in a specified file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object containing the file from
|
||||
/// which the contents of the new instance are to be read.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specify at what position to
|
||||
/// read the object.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="position" /> is less than zero or greater
|
||||
/// than the size of the file.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// The object read from disk does not have the correct GUID
|
||||
/// or contents.
|
||||
/// </exception>
|
||||
public HeaderExtensionObject (File file, long position)
|
||||
: base (file, position)
|
||||
{
|
||||
if (!Guid.Equals (Asf.Guid.AsfHeaderExtensionObject))
|
||||
throw new CorruptFileException ("Object GUID incorrect.");
|
||||
|
||||
if (file.ReadGuid () != Asf.Guid.AsfReserved1)
|
||||
throw new CorruptFileException ("Reserved1 GUID expected.");
|
||||
|
||||
if (file.ReadWord () != 6)
|
||||
throw new CorruptFileException ("Invalid reserved WORD. Expected '6'.");
|
||||
|
||||
uint size_remaining = file.ReadDWord ();
|
||||
position += 0x170 / 8;
|
||||
|
||||
while (size_remaining > 0) {
|
||||
Object obj = file.ReadObject (position);
|
||||
position += (long)obj.OriginalSize;
|
||||
size_remaining -= (uint)obj.OriginalSize;
|
||||
children.Add (obj);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the child objects contained in the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="T:System.Collections.Generic.IEnumerable`1" /> object enumerating
|
||||
/// through the children of the current instance.
|
||||
/// </value>
|
||||
public IEnumerable<Object> Children {
|
||||
get { return children; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ASF object.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public override ByteVector Render ()
|
||||
{
|
||||
ByteVector output = new ByteVector ();
|
||||
|
||||
foreach (var child in children)
|
||||
output.Add (child.Render ());
|
||||
|
||||
output.Insert (0, RenderDWord ((uint)output.Count));
|
||||
output.Insert (0, RenderWord (6));
|
||||
output.Insert (0, Asf.Guid.AsfReserved1.ToByteArray ());
|
||||
|
||||
return Render (output);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a child object to the current instance.
|
||||
/// </summary>
|
||||
/// <param name="obj">
|
||||
/// A <see cref="Object" /> object to add to the current
|
||||
/// instance.
|
||||
/// </param>
|
||||
public void AddObject (Object obj)
|
||||
{
|
||||
children.Add (obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a child unique child object to the current instance,
|
||||
/// replacing and existing child if present.
|
||||
/// </summary>
|
||||
/// <param name="obj">
|
||||
/// A <see cref="Object" /> object to add to the current
|
||||
/// instance.
|
||||
/// </param>
|
||||
public void AddUniqueObject (Object obj)
|
||||
{
|
||||
for (int i = 0; i < children.Count; i++)
|
||||
if (children[i].Guid == obj.Guid) {
|
||||
children[i] = obj;
|
||||
return;
|
||||
}
|
||||
|
||||
children.Add (obj);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc8a5039b8de0c71c9af979086ce9378
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,265 @@
|
||||
//
|
||||
// HeaderObject.cs: Provides a representation of an ASF Header object which can
|
||||
// be read from and written to disk.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Object" /> to provide a
|
||||
/// representation of an ASF Header object which can be read from and
|
||||
/// written to disk.
|
||||
/// </summary>
|
||||
public class HeaderObject : Object
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the reserved header data.
|
||||
/// </summary>
|
||||
readonly ByteVector reserved;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the child objects.
|
||||
/// </summary>
|
||||
readonly List<Object> children;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="HeaderObject" /> by reading the contents from a
|
||||
/// specified position in a specified file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object containing the file from
|
||||
/// which the contents of the new instance are to be read.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specify at what position to
|
||||
/// read the object.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="position" /> is less than zero or greater
|
||||
/// than the size of the file.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// The object read from disk does not have the correct GUID
|
||||
/// or smaller than the minimum size.
|
||||
/// </exception>
|
||||
public HeaderObject (File file, long position)
|
||||
: base (file, position)
|
||||
{
|
||||
if (!Guid.Equals (Asf.Guid.AsfHeaderObject))
|
||||
throw new CorruptFileException ("Object GUID incorrect.");
|
||||
|
||||
if (OriginalSize < 26)
|
||||
throw new CorruptFileException ("Object size too small.");
|
||||
|
||||
children = new List<Object> ();
|
||||
|
||||
uint child_count = file.ReadDWord ();
|
||||
|
||||
reserved = file.ReadBlock (2);
|
||||
|
||||
children.AddRange (file.ReadObjects (child_count,
|
||||
file.Tell));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the header extension object contained in the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="HeaderExtensionObject" /> object containing
|
||||
/// the header extension object.
|
||||
/// </value>
|
||||
public HeaderExtensionObject Extension {
|
||||
get {
|
||||
foreach (Object child in children)
|
||||
if (child is HeaderExtensionObject)
|
||||
return child as HeaderExtensionObject;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the child objects contained in the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="T:System.Collections.Generic.IEnumerable`1" /> object enumerating
|
||||
/// through the children of the current instance.
|
||||
/// </value>
|
||||
public IEnumerable<Object> Children {
|
||||
get { return children; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the media properties contained within the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="Properties" /> object containing the media
|
||||
/// properties of the current instance.
|
||||
/// </value>
|
||||
public Properties Properties {
|
||||
get {
|
||||
TimeSpan duration = TimeSpan.Zero;
|
||||
var codecs = new List<ICodec> ();
|
||||
|
||||
foreach (var obj in Children) {
|
||||
if (obj is FilePropertiesObject fpobj) {
|
||||
duration = fpobj.PlayDuration - TimeSpan.FromMilliseconds (fpobj.Preroll);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (obj is StreamPropertiesObject spobj) {
|
||||
codecs.Add (spobj.Codec);
|
||||
}
|
||||
}
|
||||
|
||||
return new Properties (duration, codecs);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not the current instance contains either
|
||||
/// type of content descriptiors.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <see langword="true" /> if the current instance contains
|
||||
/// a <see cref="ContentDescriptionObject" /> or a <see
|
||||
/// cref="ExtendedContentDescriptionObject" />. Otherwise
|
||||
/// <see langword="false" />.
|
||||
/// </value>
|
||||
public bool HasContentDescriptors {
|
||||
get {
|
||||
foreach (Object child in children)
|
||||
if (child.Guid == Asf.Guid.AsfContentDescriptionObject ||
|
||||
child.Guid == Asf.Guid.AsfExtendedContentDescriptionObject)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ASF object.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public override ByteVector Render ()
|
||||
{
|
||||
var output = new ByteVector ();
|
||||
uint child_count = 0;
|
||||
|
||||
foreach (var child in children)
|
||||
if (child.Guid != Asf.Guid.AsfPaddingObject) {
|
||||
output.Add (child.Render ());
|
||||
child_count++;
|
||||
}
|
||||
|
||||
long size_diff = (long)output.Count + 30 -
|
||||
(long)OriginalSize;
|
||||
|
||||
if (size_diff != 0) {
|
||||
var obj = new PaddingObject ((uint)(size_diff > 0 ? 4096 : -size_diff));
|
||||
|
||||
output.Add (obj.Render ());
|
||||
child_count++;
|
||||
}
|
||||
|
||||
output.Insert (0, reserved);
|
||||
output.Insert (0, RenderDWord (child_count));
|
||||
return Render (output);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a child object to the current instance.
|
||||
/// </summary>
|
||||
/// <param name="obj">
|
||||
/// A <see cref="Object" /> object to add to the current
|
||||
/// instance.
|
||||
/// </param>
|
||||
public void AddObject (Object obj)
|
||||
{
|
||||
children.Add (obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a child unique child object to the current instance,
|
||||
/// replacing and existing child if present.
|
||||
/// </summary>
|
||||
/// <param name="obj">
|
||||
/// A <see cref="Object" /> object to add to the current
|
||||
/// instance.
|
||||
/// </param>
|
||||
public void AddUniqueObject (Object obj)
|
||||
{
|
||||
for (int i = 0; i < children.Count; i++)
|
||||
if (children[i].Guid == obj.Guid) {
|
||||
children[i] = obj;
|
||||
return;
|
||||
}
|
||||
|
||||
children.Add (obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the content description objects from the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
public void RemoveContentDescriptors ()
|
||||
{
|
||||
for (int i = children.Count - 1; i >= 0; i--)
|
||||
if (children[i].Guid == Asf.Guid.AsfContentDescriptionObject ||
|
||||
children[i].Guid == Asf.Guid.AsfExtendedContentDescriptionObject)
|
||||
children.RemoveAt (i);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 28f74c9348168792da3d31feb083107a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,288 @@
|
||||
//
|
||||
// MetadataLibraryObject.cs: Provides a representation of an ASF Metadata
|
||||
// Library object which can be read from and written to disk.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Object" /> to provide a
|
||||
/// representation of an ASF Metadata Library object which can be
|
||||
/// read from and written to disk.
|
||||
/// </summary>
|
||||
public class MetadataLibraryObject : Object, IEnumerable<DescriptionRecord>
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the description records.
|
||||
/// </summary>
|
||||
readonly List<DescriptionRecord> records = new List<DescriptionRecord> ();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="MetadataLibraryObject" /> by reading the contents
|
||||
/// from a specified position in a specified file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object containing the file from
|
||||
/// which the contents of the new instance are to be read.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specify at what position to
|
||||
/// read the object.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="position" /> is less than zero or greater
|
||||
/// than the size of the file.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// The object read from disk does not have the correct GUID
|
||||
/// or smaller than the minimum size.
|
||||
/// </exception>
|
||||
public MetadataLibraryObject (File file, long position)
|
||||
: base (file, position)
|
||||
{
|
||||
if (!Guid.Equals (Asf.Guid.AsfMetadataLibraryObject))
|
||||
throw new CorruptFileException ("Object GUID incorrect.");
|
||||
|
||||
if (OriginalSize < 26)
|
||||
throw new CorruptFileException ("Object size too small.");
|
||||
|
||||
ushort count = file.ReadWord ();
|
||||
|
||||
for (ushort i = 0; i < count; i++) {
|
||||
var rec = new DescriptionRecord (file);
|
||||
AddRecord (rec);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="MetadataLibraryObject" /> with no contents.
|
||||
/// </summary>
|
||||
public MetadataLibraryObject ()
|
||||
: base (Asf.Guid.AsfMetadataLibraryObject)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not the current instance is empty.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <see langword="true" /> if the current instance doesn't
|
||||
/// contain any <see cref="DescriptionRecord" /> objects.
|
||||
/// Otherwise <see langword="false" />.
|
||||
/// </value>
|
||||
public bool IsEmpty {
|
||||
get { return records.Count == 0; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ASF object.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public override ByteVector Render ()
|
||||
{
|
||||
ByteVector output = new ByteVector ();
|
||||
ushort count = 0;
|
||||
|
||||
foreach (DescriptionRecord rec in records) {
|
||||
count++;
|
||||
output.Add (rec.Render ());
|
||||
}
|
||||
|
||||
return Render (RenderWord (count) + output);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all records with a given language, stream, and
|
||||
/// name from the current instance.
|
||||
/// </summary>
|
||||
/// <param name="languageListIndex">
|
||||
/// A <see cref="ushort" /> value containing the language
|
||||
/// list index of the records to be removed.
|
||||
/// </param>
|
||||
/// <param name="streamNumber">
|
||||
/// A <see cref="ushort" /> value containing the stream
|
||||
/// number of the records to be removed.
|
||||
/// </param>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// records to be removed.
|
||||
/// </param>
|
||||
public void RemoveRecords (ushort languageListIndex, ushort streamNumber, string name)
|
||||
{
|
||||
for (int i = records.Count - 1; i >= 0; i--) {
|
||||
DescriptionRecord rec = records[i];
|
||||
if (rec.LanguageListIndex == languageListIndex &&
|
||||
rec.StreamNumber == streamNumber &&
|
||||
rec.Name == name)
|
||||
records.RemoveAt (i);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all records with a given language, stream, and any
|
||||
/// of a collection of names from the current instance.
|
||||
/// </summary>
|
||||
/// <param name="languageListIndex">
|
||||
/// A <see cref="ushort" /> value containing the language
|
||||
/// list index of the records to be retrieved.
|
||||
/// </param>
|
||||
/// <param name="streamNumber">
|
||||
/// A <see cref="ushort" /> value containing the stream
|
||||
/// number of the records to be retrieved.
|
||||
/// </param>
|
||||
/// <param name="names">
|
||||
/// A <see cref="T:string[]" /> containing the names of the
|
||||
/// records to be retrieved.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="T:System.Collections.Generic.IEnumerable`1" /> object enumerating
|
||||
/// through the <see cref="DescriptionRecord" /> objects
|
||||
/// retrieved from the current instance.
|
||||
/// </returns>
|
||||
public IEnumerable<DescriptionRecord> GetRecords (ushort languageListIndex, ushort streamNumber, params string[] names)
|
||||
{
|
||||
foreach (DescriptionRecord rec in records) {
|
||||
if (rec.LanguageListIndex != languageListIndex ||
|
||||
rec.StreamNumber != streamNumber)
|
||||
continue;
|
||||
|
||||
foreach (string name in names)
|
||||
if (rec.Name == name)
|
||||
yield return rec;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a record to the current instance.
|
||||
/// </summary>
|
||||
/// <param name="record">
|
||||
/// A <see cref="DescriptionRecord" /> object to add to the
|
||||
/// current instance.
|
||||
/// </param>
|
||||
public void AddRecord (DescriptionRecord record)
|
||||
{
|
||||
records.Add (record);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the a collection of records for a given language,
|
||||
/// stream, and name, removing the existing matching records.
|
||||
/// </summary>
|
||||
/// <param name="languageListIndex">
|
||||
/// A <see cref="ushort" /> value containing the language
|
||||
/// list index of the records to be added.
|
||||
/// </param>
|
||||
/// <param name="streamNumber">
|
||||
/// A <see cref="ushort" /> value containing the stream
|
||||
/// number of the records to be added.
|
||||
/// </param>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// records to be added.
|
||||
/// </param>
|
||||
/// <param name="records">
|
||||
/// A <see cref="T:DescriptionRecord[]" /> containing records
|
||||
/// to add to the new instance.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// All added entries in <paramref name="records" /> should
|
||||
/// match <paramref name="languageListIndex" />, <paramref
|
||||
/// name="streamNumber" /> and <paramref name="name" /> but
|
||||
/// it is not verified by the method. The records will be
|
||||
/// added with their own values and not those provided in
|
||||
/// this method, which are used for removing existing values
|
||||
/// and determining where to position the new object.
|
||||
/// </remarks>
|
||||
public void SetRecords (ushort languageListIndex, ushort streamNumber, string name, params DescriptionRecord[] records)
|
||||
{
|
||||
int position = this.records.Count;
|
||||
for (int i = this.records.Count - 1; i >= 0; i--) {
|
||||
DescriptionRecord rec = this.records[i];
|
||||
if (rec.LanguageListIndex == languageListIndex &&
|
||||
rec.StreamNumber == streamNumber &&
|
||||
rec.Name == name) {
|
||||
this.records.RemoveAt (i);
|
||||
position = i;
|
||||
}
|
||||
}
|
||||
this.records.InsertRange (position, records);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region IEnumerable
|
||||
|
||||
/// <summary>
|
||||
/// Gets an enumerator for enumerating through the
|
||||
/// description records.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="T:System.Collections.IEnumerator`1" /> for
|
||||
/// enumerating through the description records.
|
||||
/// </returns>
|
||||
public IEnumerator<DescriptionRecord> GetEnumerator ()
|
||||
{
|
||||
return records.GetEnumerator ();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator ()
|
||||
{
|
||||
return records.GetEnumerator ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 60b732db7695db75682664625a7c9288
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,244 @@
|
||||
//
|
||||
// Object.cs: Provides a basic representation of an ASF object which can be read
|
||||
// from and written to disk.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// This abstract class provides a basic representation of an ASF
|
||||
/// object which can be read from and written to disk.
|
||||
/// </summary>
|
||||
public abstract class Object
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the GUID of the object.
|
||||
/// </summary>
|
||||
readonly System.Guid id;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Object" /> by reading the contents from a
|
||||
/// specified position in a specified file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object containing the file from
|
||||
/// which the contents of the new instance are to be read.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specify at what position to
|
||||
/// read the object.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="position" /> is less than zero or greater
|
||||
/// than the size of the file.
|
||||
/// </exception>
|
||||
protected Object (File file, long position)
|
||||
{
|
||||
if (file == null)
|
||||
throw new ArgumentNullException (nameof (file));
|
||||
|
||||
if (position < 0 ||
|
||||
position > file.Length - 24)
|
||||
throw new ArgumentOutOfRangeException (nameof (position));
|
||||
|
||||
file.Seek (position);
|
||||
id = file.ReadGuid ();
|
||||
OriginalSize = file.ReadQWord ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Object" /> with a specified GUID.
|
||||
/// </summary>
|
||||
/// <param name="guid">
|
||||
/// A <see cref="System.Guid" /> value containing the GUID to
|
||||
/// use for the new instance.
|
||||
/// </param>
|
||||
protected Object (System.Guid guid)
|
||||
{
|
||||
id = guid;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the GUID for the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="System.Guid" /> object containing the GUID
|
||||
/// of the current instance.
|
||||
/// </value>
|
||||
public System.Guid Guid {
|
||||
get { return id; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the original size of the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ulong" /> value containing the size of the
|
||||
/// current instance as it originally appeared on disk.
|
||||
/// </value>
|
||||
public ulong OriginalSize { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ASF object.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
/// <seealso cref="Render(ByteVector)" />
|
||||
public abstract ByteVector Render ();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Static Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders a Unicode (wide) string.
|
||||
/// </summary>
|
||||
/// <param name="value">
|
||||
/// A <see cref="string" /> object containing the text to
|
||||
/// render.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered value.
|
||||
/// </returns>
|
||||
public static ByteVector RenderUnicode (string value)
|
||||
{
|
||||
ByteVector v = ByteVector.FromString (value, StringType.UTF16LE);
|
||||
v.Add (RenderWord (0));
|
||||
return v;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders a 4-byte DWORD.
|
||||
/// </summary>
|
||||
/// <param name="value">
|
||||
/// A <see cref="uint" /> value containing the DWORD to
|
||||
/// render.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered value.
|
||||
/// </returns>
|
||||
public static ByteVector RenderDWord (uint value)
|
||||
{
|
||||
return ByteVector.FromUInt (value, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders a 8-byte QWORD.
|
||||
/// </summary>
|
||||
/// <param name="value">
|
||||
/// A <see cref="ulong" /> value containing the QWORD to
|
||||
/// render.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered value.
|
||||
/// </returns>
|
||||
public static ByteVector RenderQWord (ulong value)
|
||||
{
|
||||
return ByteVector.FromULong (value, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders a 2-byte WORD.
|
||||
/// </summary>
|
||||
/// <param name="value">
|
||||
/// A <see cref="ushort" /> value containing the WORD to
|
||||
/// render.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered value.
|
||||
/// </returns>
|
||||
public static ByteVector RenderWord (ushort value)
|
||||
{
|
||||
return ByteVector.FromUShort (value, false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ASF object
|
||||
/// containing specified data.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the data to
|
||||
/// contained in the rendered version of the current
|
||||
/// instance.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Child classes implementing <see cref="Render()" /> should
|
||||
/// render their contents and then send the data through this
|
||||
/// method to produce the final output.
|
||||
/// </remarks>
|
||||
protected ByteVector Render (ByteVector data)
|
||||
{
|
||||
ulong length = (ulong)((data != null ? data.Count : 0) + 24);
|
||||
ByteVector v = id.ToByteArray ();
|
||||
v.Add (RenderQWord (length));
|
||||
v.Add (data);
|
||||
return v;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de6647e25247fb396826cf683998e204
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,125 @@
|
||||
//
|
||||
// PaddingObject.cs: Provides a representation of an ASF Padding object which
|
||||
// can be read from and written to disk.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Object" /> to provide a
|
||||
/// representation of an ASF Padding object which can be read from
|
||||
/// and written to disk.
|
||||
/// </summary>
|
||||
public class PaddingObject : Object
|
||||
{
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="PaddingObject" /> by reading the contents from a
|
||||
/// specified position in a specified file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object containing the file from
|
||||
/// which the contents of the new instance are to be read.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specify at what position to
|
||||
/// read the object.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="position" /> is less than zero or greater
|
||||
/// than the size of the file.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// The object read from disk does not have the correct GUID
|
||||
/// or smaller than the minimum size.
|
||||
/// </exception>
|
||||
public PaddingObject (File file, long position)
|
||||
: base (file, position)
|
||||
{
|
||||
if (!Guid.Equals (Asf.Guid.AsfPaddingObject))
|
||||
throw new CorruptFileException ("Object GUID incorrect.");
|
||||
|
||||
if (OriginalSize < 24)
|
||||
throw new CorruptFileException ("Object size too small.");
|
||||
|
||||
Size = OriginalSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="PaddingObject" /> of a specified size.
|
||||
/// </summary>
|
||||
/// <param name="size">
|
||||
/// A <see cref="uint" /> value specifying the number of
|
||||
/// bytes the new instance is to take up on disk.
|
||||
/// </param>
|
||||
public PaddingObject (uint size)
|
||||
: base (Asf.Guid.AsfPaddingObject)
|
||||
{
|
||||
Size = size;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Prublic Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the number of bytes the current instance
|
||||
/// will take up on disk.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ulong" /> value containing the size of the
|
||||
/// current instance on disk.
|
||||
/// </value>
|
||||
public ulong Size { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ASF object.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public override ByteVector Render ()
|
||||
{
|
||||
return Render (new ByteVector ((int)(Size - 24)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 57cc0edc0b79695a69d3f10c7d65944f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,226 @@
|
||||
//
|
||||
// StreamPropertiesObject.cs: Provides a representation of an ASF Stream
|
||||
// Properties object which can be read from and written to disk.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Object" /> to provide a
|
||||
/// representation of an ASF Stream Properties object which can be
|
||||
/// read from and written to disk.
|
||||
/// </summary>
|
||||
public class StreamPropertiesObject : Object
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the time offset of the stream.
|
||||
/// </summary>
|
||||
readonly ulong time_offset;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the reserved data.
|
||||
/// </summary>
|
||||
readonly uint reserved;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="PaddingObject" /> by reading the contents from a
|
||||
/// specified position in a specified file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object containing the file from
|
||||
/// which the contents of the new instance are to be read.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specify at what position to
|
||||
/// read the object.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="position" /> is less than zero or greater
|
||||
/// than the size of the file.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// The object read from disk does not have the correct GUID
|
||||
/// or smaller than the minimum size.
|
||||
/// </exception>
|
||||
public StreamPropertiesObject (File file, long position)
|
||||
: base (file, position)
|
||||
{
|
||||
if (!Guid.Equals (Asf.Guid.AsfStreamPropertiesObject))
|
||||
throw new CorruptFileException ("Object GUID incorrect.");
|
||||
|
||||
if (OriginalSize < 78)
|
||||
throw new CorruptFileException ("Object size too small.");
|
||||
|
||||
StreamType = file.ReadGuid ();
|
||||
ErrorCorrectionType = file.ReadGuid ();
|
||||
time_offset = file.ReadQWord ();
|
||||
|
||||
int type_specific_data_length = (int)file.ReadDWord ();
|
||||
int error_correction_data_length = (int)file.ReadDWord ();
|
||||
|
||||
Flags = file.ReadWord ();
|
||||
reserved = file.ReadDWord ();
|
||||
TypeSpecificData = file.ReadBlock (type_specific_data_length);
|
||||
ErrorCorrectionData = file.ReadBlock (error_correction_data_length);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the codec information contained in the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ICodec" /> object containing the codec
|
||||
/// information read from <see cref="TypeSpecificData" /> or
|
||||
/// <see langword="null" /> if the data could not be decoded.
|
||||
/// </value>
|
||||
public ICodec Codec {
|
||||
get {
|
||||
if (StreamType == Asf.Guid.AsfAudioMedia)
|
||||
return new Riff.WaveFormatEx (TypeSpecificData, 0);
|
||||
|
||||
if (StreamType == Asf.Guid.AsfVideoMedia)
|
||||
return new Riff.BitmapInfoHeader (TypeSpecificData, 11);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the stream type GUID of the current instance.
|
||||
/// </summary>
|
||||
/// <summary>
|
||||
/// A <see cref="System.Guid" /> object containing the stream
|
||||
/// type GUID of the current instance.
|
||||
/// </summary>
|
||||
public System.Guid StreamType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the error correction type GUID of the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <summary>
|
||||
/// A <see cref="System.Guid" /> object containing the error
|
||||
/// correction type GUID of the current instance.
|
||||
/// </summary>
|
||||
public System.Guid ErrorCorrectionType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the time offset at which the stream described by the
|
||||
/// current instance begins.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TimeSpan" /> value containing the time
|
||||
/// offset at which the stream described by the current
|
||||
/// instance begins.
|
||||
/// </value>
|
||||
public TimeSpan TimeOffset {
|
||||
get { return new TimeSpan ((long)time_offset); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the flags that apply to the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ushort" /> value containing the flags that
|
||||
/// apply to the current instance.
|
||||
/// </value>
|
||||
public ushort Flags { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type specific data contained in the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ByteVector" /> object containing the type
|
||||
/// specific data contained in the current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// The contents of this value are dependant on the type
|
||||
/// contained in <see cref="StreamType" />.
|
||||
/// </remarks>
|
||||
public ByteVector TypeSpecificData { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the error correction data contained in the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ByteVector" /> object containing the error
|
||||
/// correction data contained in the current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// The contents of this value are dependant on the type
|
||||
/// contained in <see cref="ErrorCorrectionType" />.
|
||||
/// </remarks>
|
||||
public ByteVector ErrorCorrectionData { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ASF object.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public override ByteVector Render ()
|
||||
{
|
||||
ByteVector output = StreamType.ToByteArray ();
|
||||
output.Add (ErrorCorrectionType.ToByteArray ());
|
||||
output.Add (RenderQWord (time_offset));
|
||||
output.Add (RenderDWord ((uint)TypeSpecificData.Count));
|
||||
output.Add (RenderDWord ((uint)ErrorCorrectionData.Count));
|
||||
output.Add (RenderWord (Flags));
|
||||
output.Add (RenderDWord (reserved));
|
||||
output.Add (TypeSpecificData);
|
||||
output.Add (ErrorCorrectionData);
|
||||
|
||||
return Render (output);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f4fa10f38049b3e2499e7f713daf6b9a
|
||||
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: d734ffb9edf169961b4e181c03effffd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,99 @@
|
||||
//
|
||||
// UnknownObject.cs: Provides a simple and generic representation of an object
|
||||
// not identified by TagLib# so that its contents may be preserved.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Object" /> to provide a
|
||||
/// representation of an unknown object which can be read from and
|
||||
/// written to disk.
|
||||
/// </summary>
|
||||
public class UnknownObject : Object
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="UnknownObject" /> by reading the contents from a
|
||||
/// specified position in a specified file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object containing the file from
|
||||
/// which the contents of the new instance are to be read.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specify at what position to
|
||||
/// read the object.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="position" /> is less than zero or greater
|
||||
/// than the size of the file.
|
||||
/// </exception>
|
||||
public UnknownObject (File file, long position)
|
||||
: base (file, position)
|
||||
{
|
||||
Data = file.ReadBlock ((int)(OriginalSize - 24));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the data contained in the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ByteVector" /> object containing the data
|
||||
/// contained in the current instance.
|
||||
/// </value>
|
||||
public ByteVector Data { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ASF object.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public override ByteVector Render ()
|
||||
{
|
||||
return Render (Data);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 91aaa7eb7ea3bc7638ef1a9a9bb9f898
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f2cec2ef40ccecd7ba6d1a7e546abf8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,262 @@
|
||||
//
|
||||
// File.cs:
|
||||
//
|
||||
// Author:
|
||||
// Guy Taylor (s0700260@sms.ed.ac.uk) (thebigguy.co.uk@gmail.com)
|
||||
//
|
||||
// Original Source:
|
||||
// Ogg/File.cs from TagLib-sharp
|
||||
//
|
||||
// Copyright (C) 2009 Guy Taylor (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.Audible
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="TagLib.File" /> to provide tagging
|
||||
/// and properties support for Audible inc's aa file format.
|
||||
/// </summary>
|
||||
[SupportedMimeType ("audio/x-audible")]
|
||||
[SupportedMimeType ("taglib/aa", "aa")]
|
||||
[SupportedMimeType ("taglib/aax", "aax")]
|
||||
public class File : TagLib.File
|
||||
{
|
||||
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the tags for the file.
|
||||
/// </summary>
|
||||
readonly TagLib.Tag tag;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Static Fields
|
||||
|
||||
/// <summary>
|
||||
/// The offset to the tag block.
|
||||
/// </summary>
|
||||
public const short TagBlockOffset = 0xBD;
|
||||
|
||||
/// <summary>
|
||||
/// The offset to the end of tag pointer.
|
||||
/// </summary>
|
||||
public const short OffsetToEndTagPointer = 0x38;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local file
|
||||
/// system and specified read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path, ReadStyle propertiesStyle)
|
||||
: this (new LocalFileAbstraction (path), propertiesStyle)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local file
|
||||
/// system with an average read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path)
|
||||
: this (path, ReadStyle.Average)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction and
|
||||
/// specified read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// The file is not the write length.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction, ReadStyle propertiesStyle)
|
||||
: base (abstraction)
|
||||
{
|
||||
|
||||
Mode = AccessMode.Read;
|
||||
|
||||
try {
|
||||
// get the pointer to the end of the tag block
|
||||
// and calculate the tag block length
|
||||
Seek (OffsetToEndTagPointer);
|
||||
int tagLen = ((int)ReadBlock (4).ToUInt (true)) - TagBlockOffset;
|
||||
|
||||
// read the whole tag and send to Tag class
|
||||
Seek (TagBlockOffset);
|
||||
ByteVector bv = ReadBlock (tagLen);
|
||||
|
||||
tag = new Tag (bv);
|
||||
|
||||
} finally {
|
||||
Mode = AccessMode.Closed;
|
||||
}
|
||||
|
||||
// ??
|
||||
TagTypesOnDisk = TagTypes;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction with an
|
||||
/// average read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction)
|
||||
: this (abstraction, ReadStyle.Average)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Saves the changes made in the current instance to the
|
||||
/// file it represents.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Currently this does not work as there is not enough
|
||||
/// information about the file format
|
||||
/// </remarks>
|
||||
public override void Save ()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a set of tag types from the current instance.
|
||||
/// </summary>
|
||||
/// <param name="types">
|
||||
/// A bitwise combined <see cref="TagLib.TagTypes" /> value
|
||||
/// containing tag types to be removed from the file.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// In order to remove all tags from a file, pass <see
|
||||
/// cref="TagTypes.AllTags" /> as <paramref name="types" />.
|
||||
/// </remarks>
|
||||
/// <remarks>
|
||||
/// Currently this does not work as there is not enough
|
||||
/// information about the file format
|
||||
/// </remarks>
|
||||
public override void RemoveTags (TagTypes types)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a tag of a specified type from the current instance,
|
||||
/// optionally creating a new tag if possible.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="TagLib.TagTypes" /> value indicating the
|
||||
/// type of tag to read.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> value specifying whether or not to
|
||||
/// try and create the tag if one is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="Tag" /> object containing the tag that was
|
||||
/// found in or added to the current instance. If no
|
||||
/// matching tag was found and none was created, <see
|
||||
/// langword="null" /> is returned.
|
||||
/// </returns>
|
||||
public override TagLib.Tag GetTag (TagTypes type, bool create)
|
||||
{
|
||||
if (type == TagTypes.AudibleMetadata)
|
||||
return tag;
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets a abstract representation of all tags stored in the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TagLib.Tag" /> object representing all tags
|
||||
/// stored in the current instance.
|
||||
/// </value>
|
||||
public override TagLib.Tag Tag {
|
||||
get { return tag; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the media properties of the file represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TagLib.Properties" /> object containing the
|
||||
/// media properties of the file represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public override Properties Properties { get; } = new Properties ();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 006f7fb1983a3a1a89f28703d552cbc6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,320 @@
|
||||
//
|
||||
// Tag.cs:
|
||||
//
|
||||
// Author:
|
||||
// Guy Taylor (s0700260@sms.ed.ac.uk) (thebigguy.co.uk@gmail.com)
|
||||
//
|
||||
// Original Source:
|
||||
// Id3v1/Tag.cs from TagLib-sharp
|
||||
//
|
||||
// Copyright (C) 2009 Guy Taylor (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;
|
||||
|
||||
namespace TagLib.Audible
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Tag" /> to provide support for
|
||||
/// reading tags stored in the Audible Metadata format.
|
||||
/// </summary>
|
||||
public class Tag : TagLib.Tag
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
List<KeyValuePair<string, string>> tags;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Tag" /> with no contents.
|
||||
/// </summary>
|
||||
public Tag ()
|
||||
{
|
||||
Clear ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Tag" /> by reading the contents from a specified
|
||||
/// position in a specified file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="File" /> object containing the file from
|
||||
/// which the contents of the new instance is to be read.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specify at what position to
|
||||
/// read the tag.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="position" /> is less than zero or greater
|
||||
/// than the size of the file.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// The file does not contain FileIdentifier
|
||||
/// at the given position.
|
||||
/// </exception>
|
||||
public Tag (File file, long position)
|
||||
{
|
||||
// TODO: can we read from file
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Tag" /> by reading the contents from a specified
|
||||
/// <see cref="ByteVector" /> object.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object to read the tag from.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="data" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// <paramref name="data" /> is less than 128 bytes or does
|
||||
/// not start with FileIdentifier.
|
||||
/// </exception>
|
||||
public Tag (ByteVector data)
|
||||
{
|
||||
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
Clear ();
|
||||
Parse (data);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Populates the current instance by parsing the contents of
|
||||
/// a raw AudibleMetadata tag.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the whole tag
|
||||
/// object
|
||||
/// </param>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// <paramref name="data" /> is less than 128 bytes or does
|
||||
/// not start with FileIdentifier.
|
||||
/// </exception>
|
||||
void Parse (ByteVector data)
|
||||
{
|
||||
string currentKey, currentValue;
|
||||
int keyLen, valueLen;
|
||||
|
||||
try {
|
||||
do {
|
||||
keyLen = (int)data.ToUInt (true);
|
||||
data.RemoveRange (0, 4);
|
||||
valueLen = (int)data.ToUInt (true);
|
||||
data.RemoveRange (0, 4);
|
||||
currentKey = data.ToString (StringType.UTF8, 0, keyLen);
|
||||
data.RemoveRange (0, keyLen);
|
||||
currentValue = data.ToString (StringType.UTF8, 0, valueLen);
|
||||
data.RemoveRange (0, valueLen);
|
||||
|
||||
tags.Add (new KeyValuePair<string, string> (currentKey, currentValue));
|
||||
|
||||
//StringHandle (currentKey, currentValue);
|
||||
|
||||
// if it is not the last item remove the end byte (null terminated)
|
||||
if (data.Count != 0)
|
||||
data.RemoveRange (0, 1);
|
||||
}
|
||||
while (data.Count >= 4);
|
||||
} catch (Exception) {
|
||||
//
|
||||
}
|
||||
|
||||
if (data.Count != 0)
|
||||
throw new CorruptFileException ();
|
||||
}
|
||||
|
||||
void setTag (string tagName, string value)
|
||||
{
|
||||
for (int i = 0; i < tags.Count; i++) {
|
||||
if (tags[i].Key == tagName)
|
||||
tags[i] = new KeyValuePair<string, string> (tags[i].Key, value);
|
||||
}
|
||||
}
|
||||
|
||||
string getTag (string tagName)
|
||||
{
|
||||
foreach (KeyValuePair<string, string> tag in tags) {
|
||||
if (tag.Key == tagName)
|
||||
return tag.Value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// Given a key and value pair it will update the
|
||||
/// present metadata.
|
||||
/// </summary>
|
||||
/// <param name="key">
|
||||
/// A <see cref="String" /> containing the key.
|
||||
/// </param>
|
||||
/// <param name="strValue">
|
||||
/// A <see cref="String" /> containing the value.
|
||||
/// </param>
|
||||
private void StringHandle (String key, String strValue)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case "title":
|
||||
title = strValue;
|
||||
break;
|
||||
case "author":
|
||||
artist = strValue;
|
||||
break;
|
||||
case "provider":
|
||||
album = strValue;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
#region TagLib.Tag
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tag types contained in the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Always <see cref="TagTypes.AudibleMetadata" />.
|
||||
/// </value>
|
||||
public override TagTypes TagTypes {
|
||||
get { return TagTypes.AudibleMetadata; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get or Set the Author Tag
|
||||
/// </summary>
|
||||
|
||||
public string Author {
|
||||
get {
|
||||
return getTag ("author");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get or Set the Copyright Tag
|
||||
/// </summary>
|
||||
|
||||
public override string Copyright {
|
||||
get {
|
||||
return getTag ("copyright");
|
||||
}
|
||||
set {
|
||||
setTag ("copyright", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get or Set the Description Tag
|
||||
/// </summary>
|
||||
|
||||
public override string Description {
|
||||
get { return getTag ("description"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get or Set the Narrator Tag
|
||||
/// </summary>
|
||||
public string Narrator {
|
||||
get {
|
||||
return getTag ("narrator");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the title for the media described by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing the title for
|
||||
/// the media described by the current instance or <see
|
||||
/// langword="null" /> if no value is present.
|
||||
/// </value>
|
||||
public override string Title {
|
||||
get {
|
||||
return getTag ("title");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the album for the media described by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing the album for
|
||||
/// the media described by the current instance or <see
|
||||
/// langword="null" /> if no value is present.
|
||||
/// </value>
|
||||
public override string Album {
|
||||
get {
|
||||
return getTag ("provider");
|
||||
//return string.IsNullOrEmpty (album) ?
|
||||
// null : album;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the album artist for the media described by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="T:string[]" /> object containing a single
|
||||
/// artist described by the current instance or <see
|
||||
/// langword="null" /> if no value is present.
|
||||
/// </value>
|
||||
public override string[] AlbumArtists {
|
||||
get {
|
||||
var artist = getTag ("provider");
|
||||
|
||||
return string.IsNullOrEmpty (artist) ?
|
||||
null : new [] { artist };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the values stored in the current instance.
|
||||
/// </summary>
|
||||
public override void Clear ()
|
||||
{
|
||||
tags = new List<KeyValuePair<string, string>> ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c399f58c554dc5479a139a58c8a72b80
|
||||
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: fd4901c34711c7eaba954926fa92969f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,273 @@
|
||||
//
|
||||
// ByteVectorList.cs:
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
// Aaron Bockover (abockover@novell.com)
|
||||
//
|
||||
// Original Source:
|
||||
// tbytevectorlist.cpp from TagLib
|
||||
//
|
||||
// Copyright (C) 2005-2007 Brian Nickel
|
||||
// Copyright (C) 2006 Novell, Inc.
|
||||
// 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.Runtime.InteropServices;
|
||||
|
||||
namespace TagLib
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="T:TagLib.ListBase`1"/> to represent
|
||||
/// a collection of <see cref="ByteVector" /> objects.
|
||||
/// </summary>
|
||||
[ComVisible (false)]
|
||||
public class ByteVectorCollection : ListBase<ByteVector>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ByteVectorCollection" /> with no contents.
|
||||
/// </summary>
|
||||
public ByteVectorCollection ()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ByteVectorCollection" /> with specified contents.
|
||||
/// </summary>
|
||||
/// <param name="list">
|
||||
/// A <see cref="T:System.Collections.Generic.IEnumerable`1"
|
||||
/// /> containing <see cref="ByteVector" /> objects to add to
|
||||
/// the current instance.
|
||||
/// </param>
|
||||
public ByteVectorCollection (IEnumerable<ByteVector> list)
|
||||
{
|
||||
if (list != null)
|
||||
Add (list);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ByteVectorCollection" /> with specified contents.
|
||||
/// </summary>
|
||||
/// <param name="list">
|
||||
/// A <see cref="T:ByteVector[]" /> containing objects to add to
|
||||
/// the current instance.
|
||||
/// </param>
|
||||
public ByteVectorCollection (params ByteVector[] list)
|
||||
{
|
||||
if (list != null)
|
||||
Add (list);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a sorted insert of a <see cref="ByteVector" />
|
||||
/// object into the current instance, optionally only adding
|
||||
/// if the item is unique.
|
||||
/// </summary>
|
||||
/// <param name="item">
|
||||
/// A <see cref="ByteVector" /> object to add to the current
|
||||
/// instance.
|
||||
/// </param>
|
||||
/// <param name="unique">
|
||||
/// If <see langword="true" />, the object will only be added
|
||||
/// if an identical value is not already contained in the
|
||||
/// current instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="item" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public override void SortedInsert (ByteVector item, bool unique)
|
||||
{
|
||||
if (item == null)
|
||||
throw new ArgumentNullException (nameof (item));
|
||||
|
||||
// FIXME: This is not used, but if it is a faster
|
||||
// method could be used.
|
||||
int i = 0;
|
||||
for (; i < Count; i++) {
|
||||
if (item == this[i] && unique)
|
||||
return;
|
||||
|
||||
if (item >= this[i])
|
||||
break;
|
||||
}
|
||||
|
||||
Insert (i + 1, item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the current instance to a <see cref="ByteVector"
|
||||
/// /> by joining the contents together with a specified
|
||||
/// separator.
|
||||
/// </summary>
|
||||
/// <param name="separator">
|
||||
/// A <see cref="ByteVector"/> object to separate the
|
||||
/// combined contents of the current instance.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A new <see cref="ByteVector"/> object containing the
|
||||
/// joined contents of the current instance.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="separator" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public ByteVector ToByteVector (ByteVector separator)
|
||||
{
|
||||
if (separator == null)
|
||||
throw new ArgumentNullException (nameof (separator));
|
||||
|
||||
var vector = new ByteVector ();
|
||||
|
||||
for (int i = 0; i < Count; i++) {
|
||||
if (i != 0 && separator.Count > 0)
|
||||
vector.Add (separator);
|
||||
|
||||
vector.Add (this[i]);
|
||||
}
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits a <see cref="ByteVector" /> object using a
|
||||
/// pattern.
|
||||
/// </summary>
|
||||
/// <param name="vector">
|
||||
/// A <see cref="ByteVector"/> object to split.
|
||||
/// </param>
|
||||
/// <param name="pattern">
|
||||
/// A <see cref="ByteVector"/> object to use to split
|
||||
/// <paramref name="vector" /> with.
|
||||
/// </param>
|
||||
/// <param name="byteAlign">
|
||||
/// A <see cref="int" /> specifying the byte align to use
|
||||
/// when splitting. In order to split when a pattern is
|
||||
/// encountered, the index at which it is found must be
|
||||
/// divisible by <paramref name="byteAlign" />.
|
||||
/// </param>
|
||||
/// <param name="max">
|
||||
/// A <see cref="int" /> value specifying the maximum number
|
||||
/// of objects to return, or zero to not to limit the number.
|
||||
/// If that that number is reached, the last value will
|
||||
/// contain the remainder of the file even if it contains
|
||||
/// more instances of <paramref name="pattern" />.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVectorCollection" /> object containing
|
||||
/// the split contents of the current instance.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="vector" /> or <paramref name="pattern" />
|
||||
/// is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="byteAlign" /> is less than 1.
|
||||
/// </exception>
|
||||
public static ByteVectorCollection Split (ByteVector vector, ByteVector pattern, int byteAlign, int max)
|
||||
{
|
||||
if (vector == null)
|
||||
throw new ArgumentNullException (nameof (vector));
|
||||
|
||||
if (pattern == null)
|
||||
throw new ArgumentNullException (nameof (pattern));
|
||||
|
||||
if (byteAlign < 1)
|
||||
throw new ArgumentOutOfRangeException (nameof (byteAlign), "byteAlign must be at least 1.");
|
||||
|
||||
var list = new ByteVectorCollection ();
|
||||
int previous_offset = 0;
|
||||
|
||||
for (int offset = vector.Find (pattern, 0, byteAlign);
|
||||
offset != -1 && (max < 1 ||
|
||||
max > list.Count + 1);
|
||||
offset = vector.Find (pattern,
|
||||
offset + pattern.Count, byteAlign)) {
|
||||
list.Add (vector.Mid (previous_offset,
|
||||
offset - previous_offset));
|
||||
previous_offset = offset + pattern.Count;
|
||||
}
|
||||
|
||||
if (previous_offset < vector.Count)
|
||||
list.Add (vector.Mid (previous_offset,
|
||||
vector.Count - previous_offset));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits a <see cref="ByteVector" /> object using a
|
||||
/// pattern.
|
||||
/// </summary>
|
||||
/// <param name="vector">
|
||||
/// A <see cref="ByteVector"/> object to split.
|
||||
/// </param>
|
||||
/// <param name="pattern">
|
||||
/// A <see cref="ByteVector"/> object to use to split
|
||||
/// <paramref name="vector" /> with.
|
||||
/// </param>
|
||||
/// <param name="byteAlign">
|
||||
/// A <see cref="int" /> specifying the byte align to use
|
||||
/// when splitting. In order to split when a pattern is
|
||||
/// encountered, the index at which it is found must be
|
||||
/// divisible by <paramref name="byteAlign" />.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVectorCollection" /> object containing
|
||||
/// the split contents of the current instance.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="vector" /> or <paramref name="pattern" />
|
||||
/// is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="byteAlign" /> is less than 1.
|
||||
/// </exception>
|
||||
public static ByteVectorCollection Split (ByteVector vector, ByteVector pattern, int byteAlign)
|
||||
{
|
||||
return Split (vector, pattern, byteAlign, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits a <see cref="ByteVector" /> object using a
|
||||
/// pattern.
|
||||
/// </summary>
|
||||
/// <param name="vector">
|
||||
/// A <see cref="ByteVector"/> object to split.
|
||||
/// </param>
|
||||
/// <param name="pattern">
|
||||
/// A <see cref="ByteVector"/> object to use to split
|
||||
/// <paramref name="vector" /> with.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVectorCollection" /> object containing
|
||||
/// the split contents of the current instance.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="vector" /> or <paramref name="pattern" />
|
||||
/// is <see langword="null" />.
|
||||
/// </exception>
|
||||
public static ByteVectorCollection Split (ByteVector vector, ByteVector pattern)
|
||||
{
|
||||
return Split (vector, pattern, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 13ce76148d2aedf098df14fcf5195df7
|
||||
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: 0fcfda10f765f9bf0b754fb38b66878e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,167 @@
|
||||
//
|
||||
// CorruptFileException.cs:
|
||||
//
|
||||
// Author:
|
||||
// Aaron Bockover (abockover@novell.com)
|
||||
//
|
||||
// Original Source:
|
||||
// Entagged#
|
||||
//
|
||||
// Copyright (C) 2006 Novell, Inc.
|
||||
//
|
||||
// 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.Runtime.Serialization;
|
||||
|
||||
namespace TagLib
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Exception" /> and is used to
|
||||
/// indicate that a file or tag is corrupt.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This exception will be thrown if invalid data interferes with the
|
||||
/// reading of the file or tag. One common example is in the (legal)
|
||||
/// downloading of media files with BitTorrent, in which case large
|
||||
/// portions of the file will contain zeroed bytes.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <para>Catching an exception when creating a <see
|
||||
/// cref="File" />.</para>
|
||||
/// <code lang="C#">
|
||||
/// using System;
|
||||
/// using TagLib;
|
||||
///
|
||||
/// public class ExceptionTest
|
||||
/// {
|
||||
/// public static void Main ()
|
||||
/// {
|
||||
/// try {
|
||||
/// File file = File.Create ("partial.mp3"); // Partial download.
|
||||
/// } catch (CorruptFileException e) {
|
||||
/// Console.WriteLine ("That file is corrupt: {0}", e.ToString ());
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// <code lang="C++">
|
||||
/// #using <System.dll>
|
||||
/// #using <taglib-sharp.dll>
|
||||
///
|
||||
/// using System;
|
||||
/// using TagLib;
|
||||
///
|
||||
/// void main ()
|
||||
/// {
|
||||
/// try {
|
||||
/// File file = File::Create ("partial.mp3"); // Partial download.
|
||||
/// } catch (CorruptFileException^ e) {
|
||||
/// Console::WriteLine ("That file is corrupt: {0}", e);
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// <code lang="VB">
|
||||
/// Imports System
|
||||
/// Imports TagLib
|
||||
///
|
||||
/// Public Class ExceptionTest
|
||||
/// Public Shared Sub Main ()
|
||||
/// Try
|
||||
/// file As File = File.Create ("partial.mp3") ' Partial download.
|
||||
/// Catch e As CorruptFileException
|
||||
/// Console.WriteLine ("That file is corrupt: {0}", e.ToString ());
|
||||
/// End Try
|
||||
/// End Sub
|
||||
/// End Class
|
||||
/// </code>
|
||||
/// <code lang="Boo">
|
||||
/// import System
|
||||
/// import TagLib
|
||||
///
|
||||
/// try:
|
||||
/// file As File = File.Create ("partial.mp3") # Partial download.
|
||||
/// catch e as CorruptFileException:
|
||||
/// Console.WriteLine ("That file is corrupt: {0}", e.ToString ());
|
||||
/// </code>
|
||||
/// </example>
|
||||
[Serializable]
|
||||
public class CorruptFileException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="CorruptFileException" /> with a specified
|
||||
/// message.
|
||||
/// </summary>
|
||||
/// <param name="message">
|
||||
/// A <see cref="string" /> containing a message explaining
|
||||
/// the reason for the exception.
|
||||
/// </param>
|
||||
public CorruptFileException (string message) : base (message)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="CorruptFileException" /> with the default
|
||||
/// values.
|
||||
/// </summary>
|
||||
public CorruptFileException ()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="CorruptFileException" /> with a specified
|
||||
/// message containing a specified exception.
|
||||
/// </summary>
|
||||
/// <param name="message">
|
||||
/// A <see cref="string" /> containing a message explaining
|
||||
/// the reason for the exception.
|
||||
/// </param>
|
||||
/// <param name="innerException">
|
||||
/// A <see cref="Exception" /> object to be contained in the
|
||||
/// new exception. For example, previously caught exception.
|
||||
/// </param>
|
||||
public CorruptFileException (string message, Exception innerException)
|
||||
: base (message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="CorruptFileException" /> from a specified
|
||||
/// serialization info and streaming context.
|
||||
/// </summary>
|
||||
/// <param name="info">
|
||||
/// A <see cref="SerializationInfo" /> object containing the
|
||||
/// serialized data to be used for the new instance.
|
||||
/// </param>
|
||||
/// <param name="context">
|
||||
/// A <see cref="StreamingContext" /> object containing the
|
||||
/// streaming context information for the new instance.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// This constructor is implemented because <see
|
||||
/// cref="CorruptFileException" /> implements the <see
|
||||
/// cref="ISerializable" /> interface.
|
||||
/// </remarks>
|
||||
protected CorruptFileException (SerializationInfo info, StreamingContext context)
|
||||
: base (info, context)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b3d4c56812fd17788a353ae122bb5c53
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,137 @@
|
||||
//
|
||||
// Debugger.cs:
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TagLib
|
||||
{
|
||||
static class Debugger
|
||||
{
|
||||
public delegate void DebugMessageSentHandler (string message);
|
||||
|
||||
public static event DebugMessageSentHandler DebugMessageSent;
|
||||
|
||||
public static void Debug (string message)
|
||||
{
|
||||
DebugMessageSent?.Invoke (message);
|
||||
}
|
||||
|
||||
public static void DumpHex (ByteVector data)
|
||||
{
|
||||
DumpHex (data.Data);
|
||||
}
|
||||
|
||||
public static void DumpHex (byte[] data)
|
||||
{
|
||||
int cols = 16;
|
||||
int rows = data.Length / cols + (data.Length % cols != 0 ? 1 : 0);
|
||||
|
||||
for (int row = 0; row < rows; row++) {
|
||||
for (int col = 0; col < cols; col++) {
|
||||
if (row == rows - 1 && data.Length % cols != 0 && col >= data.Length % cols)
|
||||
Console.Write (" ");
|
||||
else
|
||||
Console.Write (" {0:x2}", data[row * cols + col]);
|
||||
}
|
||||
|
||||
Console.Write (" | ");
|
||||
|
||||
for (int col = 0; col < cols; col++) {
|
||||
if (row == rows - 1 && data.Length % cols != 0 && col >= data.Length % cols)
|
||||
Console.Write (" ");
|
||||
else
|
||||
WriteByte2 (data[row * cols + col]);
|
||||
}
|
||||
|
||||
Console.WriteLine ();
|
||||
}
|
||||
Console.WriteLine ();
|
||||
}
|
||||
|
||||
static void WriteByte2 (byte data)
|
||||
{
|
||||
foreach (char c in allowed)
|
||||
if (c == data) {
|
||||
Console.Write (c);
|
||||
return;
|
||||
}
|
||||
|
||||
Console.Write (".");
|
||||
}
|
||||
|
||||
static readonly string allowed = "0123456789abcdefghijklmnopqr" +
|
||||
"stuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`~!@#$%^&*()_+-={}" +
|
||||
"[];:'\",.<>?/\\|";
|
||||
|
||||
|
||||
static readonly Dictionary<object, Dictionary<object, DebugTimeData>>
|
||||
debug_times = new Dictionary<object, Dictionary<object, DebugTimeData>> ();
|
||||
|
||||
public static void AddDebugTime (object o1, object o2, DateTime start)
|
||||
{
|
||||
var data = new DebugTimeData (DateTime.Now - start, 1);
|
||||
if (debug_times.ContainsKey (o1) && debug_times[o1].ContainsKey (o2)) {
|
||||
data.time += debug_times[o1][o2].time;
|
||||
data.occurances += debug_times[o1][o2].occurances;
|
||||
}
|
||||
|
||||
if (!debug_times.ContainsKey (o1))
|
||||
debug_times.Add (o1, new Dictionary<object, DebugTimeData> ());
|
||||
|
||||
if (!debug_times[o1].ContainsKey (o2))
|
||||
debug_times[o1].Add (o2, data);
|
||||
else
|
||||
debug_times[o1][o2] = data;
|
||||
}
|
||||
|
||||
public static void DumpDebugTime (object o1)
|
||||
{
|
||||
Console.WriteLine (o1.ToString ());
|
||||
if (!debug_times.ContainsKey (o1))
|
||||
return;
|
||||
|
||||
foreach (var pair in debug_times[o1]) {
|
||||
Console.WriteLine (" {0}", pair.Key);
|
||||
Console.WriteLine (" Objects: {0}", pair.Value.time);
|
||||
Console.WriteLine (" Total: {0}", pair.Value.occurances);
|
||||
Console.WriteLine (" Average: {0}", new TimeSpan (pair.Value.time.Ticks / pair.Value.occurances));
|
||||
Console.WriteLine ();
|
||||
}
|
||||
|
||||
debug_times.Remove (o1);
|
||||
}
|
||||
|
||||
struct DebugTimeData
|
||||
{
|
||||
public TimeSpan time;
|
||||
public long occurances;
|
||||
|
||||
public DebugTimeData (TimeSpan time, int occurances)
|
||||
{
|
||||
this.time = time;
|
||||
this.occurances = occurances;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 43d149150f84518598c6d2c5500d9244
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 90815a5b58495074885ff707abaacda7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,411 @@
|
||||
//
|
||||
// File.cs: Provides tagging and properties support for the DSD (Direct Stream Digital) DSF
|
||||
// file Format.
|
||||
//
|
||||
// Author:
|
||||
// Helmut Wahrmann
|
||||
//
|
||||
// Copyright (C) 2014 Helmut Wahrmann
|
||||
//
|
||||
// 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 TagLib.Id3v2;
|
||||
|
||||
namespace TagLib.Dsf
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="TagLib.File" /> to provide
|
||||
/// support for reading and writing tags and properties for files
|
||||
/// using the AIFF file format.
|
||||
/// </summary>
|
||||
[SupportedMimeType ("taglib/dsf", "dsf")]
|
||||
[SupportedMimeType ("audio/x-dsf")]
|
||||
[SupportedMimeType ("audio/dsf")]
|
||||
[SupportedMimeType ("sound/dsf")]
|
||||
[SupportedMimeType ("application/x-dsf")]
|
||||
public class File : TagLib.File
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the address of the DSF header block.
|
||||
/// </summary>
|
||||
ByteVector header_block;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the Id3v2 tag.
|
||||
/// </summary>
|
||||
Id3v2.Tag tag;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the media properties.
|
||||
/// </summary>
|
||||
Properties properties;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the size of the DSF File
|
||||
/// </summary>
|
||||
readonly uint dsf_size;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the start position of the Tag
|
||||
/// </summary>
|
||||
long tag_start;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the end position of the Tag
|
||||
/// </summary>
|
||||
long tag_end;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Static Fields
|
||||
|
||||
/// <summary>
|
||||
/// The identifier used to recognize a DSF file.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "DSD "
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector FileIdentifier = "DSD ";
|
||||
|
||||
/// <summary>
|
||||
/// The identifier used to recognize a Format chunk.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "fmt "
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector FormatIdentifier = "fmt ";
|
||||
|
||||
/// <summary>
|
||||
/// The identifier used to recognize a DSF ID3 chunk.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "ID3 "
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector ID3Identifier = "ID3";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local file
|
||||
/// system and specified read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path, ReadStyle propertiesStyle)
|
||||
: this (new LocalFileAbstraction (path), propertiesStyle)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local file
|
||||
/// system with an average read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path) : this (path, ReadStyle.Average)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction and
|
||||
/// specified read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction, ReadStyle propertiesStyle)
|
||||
: base (abstraction)
|
||||
{
|
||||
Mode = AccessMode.Read;
|
||||
try {
|
||||
Read (true, propertiesStyle, out dsf_size, out tag_start, out tag_end);
|
||||
} finally {
|
||||
Mode = AccessMode.Closed;
|
||||
}
|
||||
|
||||
TagTypesOnDisk = TagTypes;
|
||||
GetTag (TagTypes.Id3v2, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction with an
|
||||
/// average read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction)
|
||||
: this (abstraction, ReadStyle.Average)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets a abstract representation of all tags stored in the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TagLib.Tag" /> object representing all tags
|
||||
/// stored in the current instance.
|
||||
/// </value>
|
||||
public override Tag Tag {
|
||||
get { return tag; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the media properties of the file represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TagLib.Properties" /> object containing the
|
||||
/// media properties of the file represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public override Properties Properties {
|
||||
get { return properties; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Saves the changes made in the current instance to the
|
||||
/// file it represents.
|
||||
/// </summary>
|
||||
public override void Save ()
|
||||
{
|
||||
// Boilerplate
|
||||
PreSave ();
|
||||
|
||||
Mode = AccessMode.Write;
|
||||
try {
|
||||
long original_tag_length = tag_end - tag_start;
|
||||
ByteVector data = new ByteVector ();
|
||||
|
||||
if (tag == null) {
|
||||
// The tag has been removed
|
||||
RemoveBlock (tag_start, original_tag_length);
|
||||
Insert (ByteVector.FromULong (0, false), 20, 8);
|
||||
} else {
|
||||
data = tag.Render ();
|
||||
|
||||
// If tagging info cannot be found, place it at
|
||||
// the end of the file.
|
||||
if (tag_start == 0 || tag_end < tag_start) {
|
||||
tag_start = tag_end = Length;
|
||||
// Update the New Tag start
|
||||
Insert (ByteVector.FromULong ((ulong)(tag_start), false), 20, 8);
|
||||
}
|
||||
|
||||
// Insert the tagging data.
|
||||
Insert (data, tag_start, data.Count);
|
||||
}
|
||||
|
||||
long length = dsf_size + data.Count - original_tag_length;
|
||||
|
||||
// If the data size changed update the dsf size.
|
||||
if (data.Count - original_tag_length != 0 && tag_start <= dsf_size) {
|
||||
Insert (ByteVector.FromULong ((ulong)(length), false), 12, 8);
|
||||
}
|
||||
// Update the tag types.
|
||||
TagTypesOnDisk = TagTypes;
|
||||
} finally {
|
||||
Mode = AccessMode.Closed;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a set of tag types from the current instance.
|
||||
/// </summary>
|
||||
/// <param name="types">
|
||||
/// A bitwise combined <see cref="TagLib.TagTypes" /> value
|
||||
/// containing tag types to be removed from the file.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// In order to remove all tags from a file, pass <see
|
||||
/// cref="TagTypes.AllTags" /> as <paramref name="types" />.
|
||||
/// </remarks>
|
||||
public override void RemoveTags (TagTypes types)
|
||||
{
|
||||
if (types == TagTypes.Id3v2 ||
|
||||
types == TagTypes.AllTags) {
|
||||
tag = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a tag of a specified type from the current instance,
|
||||
/// optionally creating a new tag if possible.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="TagLib.TagTypes" /> value indicating the
|
||||
/// type of tag to read.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> value specifying whether or not to
|
||||
/// try and create the tag if one is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="Tag" /> object containing the tag that was
|
||||
/// found in or added to the current instance. If no
|
||||
/// matching tag was found and none was created, <see
|
||||
/// langword="null" /> is returned.
|
||||
/// </returns>
|
||||
public override Tag GetTag (TagTypes type, bool create)
|
||||
{
|
||||
Tag id32_tag = null;
|
||||
|
||||
switch (type) {
|
||||
case TagTypes.Id3v2:
|
||||
if (tag == null && create) {
|
||||
tag = new Id3v2.Tag {
|
||||
Version = 2
|
||||
};
|
||||
}
|
||||
|
||||
id32_tag = tag;
|
||||
break;
|
||||
}
|
||||
|
||||
return id32_tag;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Reads the contents of the current instance determining
|
||||
/// the size of the dsf data, the area the tagging is in,
|
||||
/// and optionally reading in the tags and media properties.
|
||||
/// </summary>
|
||||
/// <param name="read_tags">
|
||||
/// If <see langword="true" />, any tags found will be read
|
||||
/// into the current instance.
|
||||
/// </param>
|
||||
/// <param name="style">
|
||||
/// A <see cref="ReadStyle"/> value specifying how the media
|
||||
/// data is to be read into the current instance.
|
||||
/// </param>
|
||||
/// <param name="dsf_size">
|
||||
/// A <see cref="uint"/> value reference to be filled with
|
||||
/// the size of the RIFF data as read from the file.
|
||||
/// </param>
|
||||
/// <param name="tag_start">
|
||||
/// A <see cref="long" /> value reference to be filled with
|
||||
/// the absolute seek position at which the tagging data
|
||||
/// starts.
|
||||
/// </param>
|
||||
/// <param name="tag_end">
|
||||
/// A <see cref="long" /> value reference to be filled with
|
||||
/// the absolute seek position at which the tagging data
|
||||
/// ends.
|
||||
/// </param>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// The file does not begin with <see cref="FileIdentifier"
|
||||
/// />.
|
||||
/// </exception>
|
||||
void Read (bool read_tags, ReadStyle style, out uint dsf_size, out long tag_start, out long tag_end)
|
||||
{
|
||||
Seek (0);
|
||||
if (ReadBlock (4) != FileIdentifier)
|
||||
throw new CorruptFileException ("File does not begin with DSF identifier");
|
||||
|
||||
Seek (12);
|
||||
dsf_size = ReadBlock (8).ToUInt (false);
|
||||
|
||||
tag_start = (long)ReadBlock (8).ToULong (false);
|
||||
tag_end = -1;
|
||||
|
||||
// Get the properties of the file
|
||||
if (header_block == null && style != ReadStyle.None) {
|
||||
long fmt_chunk_pos = Find (FormatIdentifier, 0);
|
||||
|
||||
if (fmt_chunk_pos == -1) {
|
||||
throw new CorruptFileException ("No Format chunk available in DSF file.");
|
||||
}
|
||||
|
||||
Seek (fmt_chunk_pos);
|
||||
header_block = ReadBlock ((int)StreamHeader.Size);
|
||||
|
||||
var header = new StreamHeader (header_block, dsf_size);
|
||||
properties = new Properties (TimeSpan.Zero, header);
|
||||
}
|
||||
|
||||
// Now position to the ID3 chunk, which we read before
|
||||
if (tag_start > 0) {
|
||||
Seek (tag_start);
|
||||
if (ReadBlock (3) == ID3Identifier) {
|
||||
if (read_tags && tag == null) {
|
||||
tag = new Id3v2.Tag (this, tag_start, style);
|
||||
}
|
||||
|
||||
// Get the length of the tag out of the ID3 chunk
|
||||
Seek (tag_start + 6);
|
||||
uint tag_size = SynchData.ToUInt (ReadBlock (4)) + 10;
|
||||
|
||||
InvariantStartPosition = tag_start;
|
||||
tag_end = InvariantEndPosition = tag_start + tag_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8b09427e5619eec8580e4b303b312ac9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,292 @@
|
||||
//
|
||||
// StreamHeader.cs: Provides tagging and properties support for the DSD
|
||||
// (Direct Stream Digital) DSF properties.
|
||||
//
|
||||
// Author:
|
||||
// Helmut Wahrmann
|
||||
//
|
||||
// Copyright (C) 2014 Helmut Wahrmann
|
||||
//
|
||||
// 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.Dsf
|
||||
{
|
||||
/// <summary>
|
||||
/// This struct implements <see cref="IAudioCodec" /> to provide
|
||||
/// support for reading DSF stream properties.
|
||||
/// </summary>
|
||||
public struct StreamHeader : IAudioCodec, ILosslessAudioCodec
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the version.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (12-15).
|
||||
/// Currently only value of 1 is valid.
|
||||
/// </remarks>
|
||||
readonly ushort version;
|
||||
|
||||
/// <summary>
|
||||
/// The Format Id.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (16-19).
|
||||
/// 0: DSD Raw
|
||||
/// </remarks>
|
||||
readonly ushort format_id;
|
||||
|
||||
/// <summary>
|
||||
/// The Channel Type.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (20-23).
|
||||
/// 1: mono
|
||||
/// 2:stereo
|
||||
/// 3:3 channels
|
||||
/// 4: quad
|
||||
/// 5: 4 channels
|
||||
/// 6: 5 channels
|
||||
/// 7: 5.1 channels
|
||||
/// </remarks>
|
||||
readonly ushort channel_type;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of channels.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (24-27).
|
||||
/// 1 is monophonic, 2 is stereo, 4 means 4 channels, etc..
|
||||
/// up to 6 channels may be represented
|
||||
/// </remarks>
|
||||
readonly ushort channels;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the sample rate.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (28-31).
|
||||
/// the sample rate at which the sound is to be played back,
|
||||
/// in Hz: 2822400, 5644800
|
||||
/// </remarks>
|
||||
readonly ulong sample_rate;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of bits per sample.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (32-35).
|
||||
/// It can be any number from 1 to 8.
|
||||
/// </remarks>
|
||||
readonly ushort bits_per_sample;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of sample frames per channel.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (36-43).
|
||||
/// </remarks>
|
||||
readonly ulong sample_count;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the Block size per channel.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (44-47).
|
||||
/// Always: 4096
|
||||
/// </remarks>
|
||||
readonly uint channel_blksize;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the length of the audio stream.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is provided by the constructor.
|
||||
/// </remarks>
|
||||
readonly long stream_length;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Static Fields
|
||||
|
||||
/// <summary>
|
||||
/// The size of an DSF Format chunk
|
||||
/// </summary>
|
||||
public const uint Size = 52;
|
||||
|
||||
/// <summary>
|
||||
/// The identifier used to recognize a DSF file.
|
||||
/// Altough an DSF file start with "DSD ", we're interested
|
||||
/// in the Format chunk only, which contains the properties we need.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "fmt "
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector FileIdentifier = "fmt ";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="StreamHeader" /> for a specified header block and
|
||||
/// stream length.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the stream
|
||||
/// header data.
|
||||
/// </param>
|
||||
/// <param name="streamLength">
|
||||
/// A <see cref="long" /> value containing the length of the
|
||||
/// DSF Audio stream in bytes.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="data" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// <paramref name="data" /> does not begin with <see
|
||||
/// cref="FileIdentifier" />
|
||||
/// </exception>
|
||||
public StreamHeader (ByteVector data, long streamLength)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
|
||||
if (!data.StartsWith (FileIdentifier))
|
||||
throw new CorruptFileException ("Data does not begin with identifier.");
|
||||
|
||||
stream_length = streamLength;
|
||||
|
||||
// The first 12 bytes contain the Format chunk identifier "fmt "
|
||||
// And the size of the format chunk, which is always 52
|
||||
version = data.Mid (12, 4).ToUShort (false);
|
||||
format_id = data.Mid (16, 4).ToUShort (false);
|
||||
channel_type = data.Mid (20, 4).ToUShort (false);
|
||||
channels = data.Mid (24, 4).ToUShort (false);
|
||||
sample_rate = data.Mid (28, 4).ToULong (false);
|
||||
bits_per_sample = data.Mid (32, 4).ToUShort (false);
|
||||
sample_count = data.Mid (36, 8).ToULong (false);
|
||||
channel_blksize = data.Mid (44, 4).ToUShort (false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the duration of the media represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TimeSpan" /> containing the duration of the
|
||||
/// media represented by the current instance.
|
||||
/// </value>
|
||||
public TimeSpan Duration {
|
||||
get {
|
||||
if (sample_rate <= 0 || sample_count <= 0)
|
||||
return TimeSpan.Zero;
|
||||
|
||||
return TimeSpan.FromSeconds (sample_count / (double)sample_rate);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the types of media represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Always <see cref="MediaTypes.Audio" />.
|
||||
/// </value>
|
||||
public MediaTypes MediaTypes {
|
||||
get { return MediaTypes.Audio; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a text description of the media represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing a description
|
||||
/// of the media represented by the current instance.
|
||||
/// </value>
|
||||
public string Description {
|
||||
get { return "DSF Audio"; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bitrate of the audio represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing a bitrate of the
|
||||
/// audio represented by the current instance.
|
||||
/// </value>
|
||||
public int AudioBitrate {
|
||||
get {
|
||||
TimeSpan d = Duration;
|
||||
if (d <= TimeSpan.Zero)
|
||||
return 0;
|
||||
|
||||
return (int)((stream_length * 8L) / d.TotalSeconds) / 1000;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sample rate of the audio represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the sample rate of
|
||||
/// the audio represented by the current instance.
|
||||
/// </value>
|
||||
public int AudioSampleRate {
|
||||
get { return (int)sample_rate; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of channels in the audio represented by
|
||||
/// the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the number of
|
||||
/// channels in the audio represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public int AudioChannels {
|
||||
get { return channels; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of bits per sample in the audio
|
||||
/// represented by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the number of bits
|
||||
/// per sample in the audio represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public int BitsPerSample {
|
||||
get { return bits_per_sample; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fc1f0cf5be62d57ad8e4d430c9afeff8
|
||||
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: 52c28e7dd422cc99f9c2e90fa020cc88
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,150 @@
|
||||
//
|
||||
// FileTypes.cs: Provides a mechanism for registering file classes and mime-
|
||||
// types, to be used when constructing a class via TagLib.File.Create.
|
||||
//
|
||||
// Author:
|
||||
// Aaron Bockover (abockover@novell.com)
|
||||
//
|
||||
// Copyright (C) 2006 Novell, Inc.
|
||||
//
|
||||
// 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;
|
||||
|
||||
namespace TagLib
|
||||
{
|
||||
/// <summary>
|
||||
/// This static class provides a mechanism for registering file
|
||||
/// classes and mime-types, to be used when constructing a class via
|
||||
/// <see cref="File.Create(string)" />.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>The default types built into the taglib-sharp.dll assembly
|
||||
/// are registered automatically when the class is initialized. To
|
||||
/// register your own custom types, use <see cref="Register"
|
||||
/// />.</para>
|
||||
/// </remarks>
|
||||
/// <seealso cref="SupportedMimeType" />
|
||||
public static class FileTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains a mapping between mime-types and the <see
|
||||
/// cref="File" /> subclasses that support them.
|
||||
/// </summary>
|
||||
static Dictionary<string, Type> file_types;
|
||||
|
||||
/// <summary>
|
||||
/// Contains a static array of file types contained in the
|
||||
/// TagLib# assembly.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A static Type array is used instead of getting types by
|
||||
/// reflecting the executing assembly as Assembly.GetTypes is
|
||||
/// very inefficient and leaks every type instance under
|
||||
/// Mono. Not reflecting taglib-sharp.dll saves about 120KB
|
||||
/// of heap.
|
||||
/// </remarks>
|
||||
static readonly Type[] static_file_types = new[] {
|
||||
typeof(Aac.File),
|
||||
typeof(Aiff.File),
|
||||
typeof(Ape.File),
|
||||
typeof(Asf.File),
|
||||
typeof(Audible.File),
|
||||
typeof(Dsf.File),
|
||||
typeof(Flac.File),
|
||||
typeof(Matroska.File),
|
||||
typeof(Gif.File),
|
||||
typeof(Image.NoMetadata.File),
|
||||
typeof(Jpeg.File),
|
||||
typeof(Mpeg4.File),
|
||||
typeof(Mpeg.AudioFile),
|
||||
typeof(Mpeg.File),
|
||||
typeof(MusePack.File),
|
||||
typeof(Ogg.File),
|
||||
typeof(Png.File),
|
||||
typeof(Riff.File),
|
||||
typeof(Tiff.Arw.File),
|
||||
typeof(Tiff.Cr2.File),
|
||||
typeof(Tiff.Dng.File),
|
||||
typeof(Tiff.File),
|
||||
typeof(Tiff.Nef.File),
|
||||
typeof(Tiff.Pef.File),
|
||||
typeof(Tiff.Rw2.File),
|
||||
typeof(WavPack.File)
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes the <see cref="FileTypes" />
|
||||
/// class by registering the default types.
|
||||
/// </summary>
|
||||
static FileTypes ()
|
||||
{
|
||||
Init ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the class by registering the default types.
|
||||
/// </summary>
|
||||
internal static void Init ()
|
||||
{
|
||||
if (file_types != null)
|
||||
return;
|
||||
|
||||
file_types = new Dictionary<string, Type> ();
|
||||
|
||||
foreach (Type type in static_file_types)
|
||||
Register (type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a <see cref="File" /> subclass to be used when
|
||||
/// creating files via <see cref="File.Create(string)" />.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="Type" /> object for the class to register.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// In order to register mime-types, the class represented by
|
||||
/// <paramref name="type" /> should use the <see
|
||||
/// cref="SupportedMimeType" /> custom attribute.
|
||||
/// </remarks>
|
||||
public static void Register (Type type)
|
||||
{
|
||||
Attribute[] attrs = Attribute.GetCustomAttributes (type, typeof (SupportedMimeType), false);
|
||||
|
||||
if (attrs.Length == 0)
|
||||
return;
|
||||
|
||||
foreach (SupportedMimeType attr in attrs)
|
||||
file_types.Add (attr.MimeType, type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a dictionary containing all the supported mime-types
|
||||
/// and file classes used by <see cref="File.Create(string)"
|
||||
/// />.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="T:System.Collections.Generic.IDictionary`2" /> object containing the
|
||||
/// supported mime-types.
|
||||
/// </value>
|
||||
public static IDictionary<string, Type> AvailableTypes {
|
||||
get { return file_types; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 23e93de1fe905f6eabb3e07e3c9aa3f0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8148a9d853e5e63c9887d255e17b38f8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,191 @@
|
||||
//
|
||||
// Block.cs: Represents a Flac metadata block.
|
||||
//
|
||||
// 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;
|
||||
|
||||
namespace TagLib.Flac
|
||||
{
|
||||
/// <summary>
|
||||
/// This class represents a Flac metadata block.
|
||||
/// </summary>
|
||||
public class Block
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the block header.
|
||||
/// </summary>
|
||||
readonly BlockHeader header;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Block" /> with a specified header and internal
|
||||
/// data.
|
||||
/// </summary>
|
||||
/// <param name="header">
|
||||
/// A <see cref="BlockHeader" /> object containing the
|
||||
/// header to use for the new instance.
|
||||
/// </param>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the data
|
||||
/// to be contained in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="data" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// The size of <paramref name="data" /> does not match the
|
||||
/// size specified in <paramref name="header" />.
|
||||
/// </exception>
|
||||
public Block (BlockHeader header, ByteVector data)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
if (header.BlockSize != data.Count)
|
||||
throw new CorruptFileException ("Data count not equal to block size.");
|
||||
|
||||
this.header = header;
|
||||
Data = data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Block" /> with of a specified type and internal
|
||||
/// data.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="BlockType" /> value indicating the type of
|
||||
/// data stored in <paramref name="data" />.
|
||||
/// </param>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the data
|
||||
/// to be contained in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="data" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public Block (BlockType type, ByteVector data)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
header = new BlockHeader (type, (uint)data.Count);
|
||||
|
||||
Data = data;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of data contained in the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="BlockType" /> value indicating the type of
|
||||
/// data contained in <see cref="Data" />.
|
||||
/// </value>
|
||||
public BlockType Type {
|
||||
get { return header.BlockType; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not the block represented by the current
|
||||
/// instance is the last metadata block in the Flac stream.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <see langword="true" /> if the block represented by the
|
||||
/// current instance was the last one to appear in the file
|
||||
/// and is followed immediately by the audio data, or <see
|
||||
/// langword="false" /> if another block appears after the
|
||||
/// current one or the block was not read from disk.
|
||||
/// </value>
|
||||
public bool IsLastBlock {
|
||||
get { return header.IsLastBlock; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the data contained in the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
public uint DataSize {
|
||||
get { return header.BlockSize; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total size of the block represented by the
|
||||
/// current instance as it appears on disk.
|
||||
/// </summary>
|
||||
public uint TotalSize {
|
||||
get { return DataSize + BlockHeader.Size; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data contained in the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ByteVector" /> object containing the data
|
||||
/// stored in the current instance.
|
||||
/// </value>
|
||||
public ByteVector Data { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw Flac metadata
|
||||
/// block.
|
||||
/// </summary>
|
||||
/// <param name="isLastBlock">
|
||||
/// A <see cref="bool" /> value indicating whether or not the
|
||||
/// block is to be marked as the last metadata block.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public ByteVector Render (bool isLastBlock)
|
||||
{
|
||||
if (Data == null)
|
||||
throw new InvalidOperationException ("Cannot render empty blocks.");
|
||||
|
||||
ByteVector data = header.Render (isLastBlock);
|
||||
data.Add (Data);
|
||||
return data;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b85066ddbb2e476dacfb9957cb823bc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,175 @@
|
||||
//
|
||||
// BlockHeader.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;
|
||||
|
||||
namespace TagLib.Flac
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the contents of a Flac block in <see cref="BlockHeader"
|
||||
/// />.
|
||||
/// </summary>
|
||||
public enum BlockType
|
||||
{
|
||||
/// <summary>
|
||||
/// The block contains stream information.
|
||||
/// </summary>
|
||||
StreamInfo = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The block contains padding.
|
||||
/// </summary>
|
||||
Padding,
|
||||
|
||||
/// <summary>
|
||||
/// The block contains application data.
|
||||
/// </summary>
|
||||
Application,
|
||||
|
||||
/// <summary>
|
||||
/// The block contains seek table.
|
||||
/// </summary>
|
||||
SeekTable,
|
||||
|
||||
/// <summary>
|
||||
/// The block contains a Xipp comment.
|
||||
/// </summary>
|
||||
XiphComment,
|
||||
|
||||
/// <summary>
|
||||
/// The block contains a cue sheet.
|
||||
/// </summary>
|
||||
CueSheet,
|
||||
|
||||
/// <summary>
|
||||
/// The block contains a picture.
|
||||
/// </summary>
|
||||
Picture
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This structure provides a representation of a Flac metadata block
|
||||
/// header structure.
|
||||
/// </summary>
|
||||
public struct BlockHeader
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The size of a block header.
|
||||
/// </summary>
|
||||
public const uint Size = 4;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="BlockHeader" /> by reading a raw header from a <see
|
||||
/// cref="ByteVector" /> object.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing a raw
|
||||
/// block header.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="data" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// <paramref name="data" /> contains less than 4 bytes.
|
||||
/// </exception>
|
||||
public BlockHeader (ByteVector data)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
if (data.Count < Size)
|
||||
throw new CorruptFileException ("Not enough data in Flac header.");
|
||||
|
||||
BlockType = (BlockType)(data[0] & 0x7f);
|
||||
IsLastBlock = (data[0] & 0x80) != 0;
|
||||
BlockSize = data.Mid (1, 3).ToUInt ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="BlockHeader" /> for a specified block type and size.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="BlockType" /> value describing the contents
|
||||
/// of the block.
|
||||
/// </param>
|
||||
/// <param name="blockSize">
|
||||
/// A <see cref="uint" /> value containing the block data
|
||||
/// size minus the size of the header.
|
||||
/// </param>
|
||||
public BlockHeader (BlockType type, uint blockSize)
|
||||
{
|
||||
BlockType = type;
|
||||
IsLastBlock = false;
|
||||
BlockSize = blockSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renderes the current instance as a raw Flac block header.
|
||||
/// </summary>
|
||||
/// <param name="isLastBlock">
|
||||
/// A <see cref="bool" /> value specifying whether or not the
|
||||
/// header is the last header of the file.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered header.
|
||||
/// </returns>
|
||||
public ByteVector Render (bool isLastBlock)
|
||||
{
|
||||
ByteVector data = ByteVector.FromUInt (BlockSize);
|
||||
data[0] = (byte)(BlockType + (isLastBlock ? 0x80 : 0));
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of block described by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="BlockType" /> value describing the block
|
||||
/// type.
|
||||
/// </value>
|
||||
public BlockType BlockType { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not the block is the last in the file.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <see langword="true" /> if the block is the last in the
|
||||
/// file; otherwise <see langword="false" />.
|
||||
/// </value>
|
||||
public bool IsLastBlock { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the block described by the current
|
||||
/// instance, minus the block header.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the size of the
|
||||
/// block, minus the header.
|
||||
/// </value>
|
||||
public uint BlockSize { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bdff34f1d4c26490c97cebf8fd90d80d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,665 @@
|
||||
//
|
||||
// File.cs: Provides tagging and properties support for Xiph's Flac audio files.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Original Source:
|
||||
// flacfile.cpp from TagLib
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
// Copyright (C) 2003-2004 Allan Sandfeld Jensen (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;
|
||||
|
||||
namespace TagLib.Flac
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="TagLib.NonContainer.File" /> to
|
||||
/// provide tagging and properties support for Xiph's Flac audio
|
||||
/// files.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A <see cref="TagLib.Ogg.XiphComment" /> will be added
|
||||
/// automatically to any file that doesn't contain one. This change
|
||||
/// does not effect the physical file until <see cref="Save" /> is
|
||||
/// called and can be reversed using the following method:
|
||||
/// <code>file.RemoveTags (file.TagTypes & ~file.TagTypesOnDisk);</code>
|
||||
/// </remarks>
|
||||
[SupportedMimeType ("taglib/flac", "flac")]
|
||||
[SupportedMimeType ("audio/x-flac")]
|
||||
[SupportedMimeType ("application/x-flac")]
|
||||
[SupportedMimeType ("audio/flac")]
|
||||
public class File : TagLib.NonContainer.File
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the Flac metadata tag.
|
||||
/// </summary>
|
||||
Metadata metadata;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the combination of all file tags.
|
||||
/// </summary>
|
||||
CombinedTag tag;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the Flac header block.
|
||||
/// </summary>
|
||||
ByteVector header_block;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the stream start position.
|
||||
/// </summary>
|
||||
long stream_start;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local file
|
||||
/// system and specified read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path, ReadStyle propertiesStyle)
|
||||
: base (path, propertiesStyle)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local file
|
||||
/// system with an average read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path)
|
||||
: base (path)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction and
|
||||
/// specified read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction,
|
||||
ReadStyle propertiesStyle)
|
||||
: base (abstraction, propertiesStyle)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction with an
|
||||
/// average read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction)
|
||||
: base (abstraction)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets a abstract representation of all tags stored in the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TagLib.Tag" /> object representing all tags
|
||||
/// stored in the current instance.
|
||||
/// </value>
|
||||
public override Tag Tag {
|
||||
get { return tag; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Saves the changes made in the current instance to the
|
||||
/// file it represents.
|
||||
/// </summary>
|
||||
public override void Save ()
|
||||
{
|
||||
// Boilerplate
|
||||
PreSave ();
|
||||
|
||||
Mode = AccessMode.Write;
|
||||
try {
|
||||
// Update the tags at the beginning of the file.
|
||||
long metadata_start = StartTag.Write ();
|
||||
|
||||
// Get all the blocks, but don't read the data for ones
|
||||
// we're filling with stored data.
|
||||
IList<Block> old_blocks = ReadBlocks (ref metadata_start,
|
||||
out var metadata_end, BlockMode.Blacklist,
|
||||
BlockType.XiphComment, BlockType.Picture);
|
||||
|
||||
// Create new vorbis comments is they don't exist.
|
||||
GetTag (TagTypes.Xiph, true);
|
||||
|
||||
// Create new blocks and add the basics.
|
||||
var new_blocks = new List<Block> ();
|
||||
new_blocks.Add (old_blocks[0]);
|
||||
|
||||
// Add blocks we don't deal with from the file.
|
||||
foreach (Block block in old_blocks)
|
||||
if (block.Type != BlockType.StreamInfo &&
|
||||
block.Type != BlockType.XiphComment &&
|
||||
block.Type != BlockType.Picture &&
|
||||
block.Type != BlockType.Padding)
|
||||
new_blocks.Add (block);
|
||||
|
||||
new_blocks.Add (new Block (BlockType.XiphComment,
|
||||
(GetTag (TagTypes.Xiph, true) as Ogg.XiphComment).Render (false)));
|
||||
|
||||
foreach (IPicture picture in metadata.Pictures) {
|
||||
if (picture == null)
|
||||
continue;
|
||||
|
||||
new_blocks.Add (new Block (BlockType.Picture,
|
||||
new Picture (picture).Render ()));
|
||||
}
|
||||
|
||||
// Get the length of the blocks.
|
||||
long length = 0;
|
||||
foreach (Block block in new_blocks)
|
||||
length += block.TotalSize;
|
||||
|
||||
// Find the padding size to avoid trouble. If that fails
|
||||
// make some.
|
||||
long padding_size = metadata_end - metadata_start -
|
||||
BlockHeader.Size - length;
|
||||
if (padding_size < 0)
|
||||
padding_size = 1024 * 4;
|
||||
|
||||
// Add a padding block.
|
||||
if (padding_size != 0)
|
||||
new_blocks.Add (new Block (BlockType.Padding,
|
||||
new ByteVector ((int)padding_size)));
|
||||
|
||||
// Render the blocks.
|
||||
ByteVector block_data = new ByteVector ();
|
||||
for (int i = 0; i < new_blocks.Count; i++)
|
||||
block_data.Add (new_blocks[i].Render (
|
||||
i == new_blocks.Count - 1));
|
||||
|
||||
// Update the blocks.
|
||||
Insert (block_data, metadata_start, metadata_end -
|
||||
metadata_start);
|
||||
|
||||
// Update the tags at the end of the file.
|
||||
EndTag.Write ();
|
||||
|
||||
TagTypesOnDisk = TagTypes;
|
||||
} finally {
|
||||
Mode = AccessMode.Closed;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a tag of a specified type from the current instance,
|
||||
/// optionally creating a new tag if possible.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="TagLib.TagTypes" /> value indicating the
|
||||
/// type of tag to read.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> value specifying whether or not to
|
||||
/// try and create the tag if one is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="Tag" /> object containing the tag that was
|
||||
/// found in or added to the current instance. If no
|
||||
/// matching tag was found and none was created, <see
|
||||
/// langword="null" /> is returned.
|
||||
/// </returns>
|
||||
public override Tag GetTag (TagTypes type, bool create)
|
||||
{
|
||||
switch (type) {
|
||||
case TagTypes.Xiph:
|
||||
return metadata.GetComment (create, tag);
|
||||
|
||||
case TagTypes.FlacMetadata:
|
||||
return metadata;
|
||||
}
|
||||
|
||||
Tag t = (base.Tag as TagLib.NonContainer.Tag).GetTag (type);
|
||||
|
||||
if (t != null || !create)
|
||||
return t;
|
||||
|
||||
switch (type) {
|
||||
case TagTypes.Id3v1:
|
||||
return EndTag.AddTag (type, Tag);
|
||||
|
||||
case TagTypes.Id3v2:
|
||||
return StartTag.AddTag (type, Tag);
|
||||
|
||||
case TagTypes.Ape:
|
||||
return EndTag.AddTag (type, Tag);
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a set of tag types from the current instance.
|
||||
/// </summary>
|
||||
/// <param name="types">
|
||||
/// A bitwise combined <see cref="TagLib.TagTypes" /> value
|
||||
/// containing tag types to be removed from the file.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// In order to remove all tags from a file, pass <see
|
||||
/// cref="TagTypes.AllTags" /> as <paramref name="types" />.
|
||||
/// </remarks>
|
||||
public override void RemoveTags (TagTypes types)
|
||||
{
|
||||
if ((types & TagTypes.Xiph) != 0)
|
||||
metadata.RemoveComment ();
|
||||
|
||||
if ((types & TagTypes.FlacMetadata) != 0)
|
||||
metadata.Clear ();
|
||||
|
||||
base.RemoveTags (types);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Reads format specific information at the start of the
|
||||
/// file.
|
||||
/// </summary>
|
||||
/// <param name="start">
|
||||
/// A <see cref="long" /> value containing the seek position
|
||||
/// at which the tags end and the media data begins.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
protected override void ReadStart (long start, ReadStyle propertiesStyle)
|
||||
{
|
||||
var blocks = ReadBlocks (ref start, out var end, BlockMode.Whitelist, BlockType.StreamInfo, BlockType.XiphComment, BlockType.Picture);
|
||||
metadata = new Metadata (blocks);
|
||||
|
||||
TagTypesOnDisk |= metadata.TagTypes;
|
||||
|
||||
if ((propertiesStyle & ReadStyle.Average) != 0) {
|
||||
// Check that the first block is a
|
||||
// METADATA_BLOCK_STREAMINFO.
|
||||
if (blocks.Count == 0 || blocks[0].Type != BlockType.StreamInfo)
|
||||
throw new CorruptFileException ("FLAC stream does not begin with StreamInfo.");
|
||||
|
||||
// The stream exists from the end of the last
|
||||
// block to the end of the file.
|
||||
stream_start = end;
|
||||
header_block = blocks[0].Data;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads format specific information at the end of the
|
||||
/// file.
|
||||
/// </summary>
|
||||
/// <param name="end">
|
||||
/// A <see cref="long" /> value containing the seek position
|
||||
/// at which the media data ends and the tags begin.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
protected override void ReadEnd (long end, ReadStyle propertiesStyle)
|
||||
{
|
||||
tag = new CombinedTag (metadata, base.Tag);
|
||||
GetTag (TagTypes.Xiph, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the audio properties from the file represented by
|
||||
/// the current instance.
|
||||
/// </summary>
|
||||
/// <param name="start">
|
||||
/// A <see cref="long" /> value containing the seek position
|
||||
/// at which the tags end and the media data begins.
|
||||
/// </param>
|
||||
/// <param name="end">
|
||||
/// A <see cref="long" /> value containing the seek position
|
||||
/// at which the media data ends and the tags begin.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="TagLib.Properties" /> object describing the
|
||||
/// media properties of the file represented by the current
|
||||
/// instance.
|
||||
/// </returns>
|
||||
protected override Properties ReadProperties (long start, long end, ReadStyle propertiesStyle)
|
||||
{
|
||||
var header = new StreamHeader (header_block, end - stream_start);
|
||||
return new Properties (TimeSpan.Zero, header);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether or not the block types passed into
|
||||
/// <see cref="ReadBlocks" /> are to be white-listed or
|
||||
/// black-listed.
|
||||
/// </summary>
|
||||
enum BlockMode
|
||||
{
|
||||
/// <summary>
|
||||
/// All block types except those provided are to be
|
||||
/// returned.
|
||||
/// </summary>
|
||||
Blacklist,
|
||||
|
||||
/// <summary>
|
||||
/// Only those block types provides should be
|
||||
/// returned.
|
||||
/// </summary>
|
||||
Whitelist
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads all metadata blocks starting from the current
|
||||
/// instance, starting at a specified position.
|
||||
/// </summary>
|
||||
/// <param name="start">
|
||||
/// A <see cref="long" /> value reference specifying the
|
||||
/// position at which to start searching for the blocks. This
|
||||
/// will be updated to the position of the first block.
|
||||
/// </param>
|
||||
/// <param name="end">
|
||||
/// A <see cref="long" /> value reference updated to the
|
||||
/// position at which the last block ends.
|
||||
/// </param>
|
||||
/// <param name="mode">
|
||||
/// A <see cref="BlockMode" /> value indicating whether to
|
||||
/// white-list or black-list the contents of <paramref
|
||||
/// name="types" />.
|
||||
/// </param>
|
||||
/// <param name="types">
|
||||
/// A <see cref="T:BlockType[]" /> containing the types to look
|
||||
/// for or not look for as specified by <paramref name="mode"
|
||||
/// />.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="T:System.Collections.Generic.IList`1" /> object containing the blocks
|
||||
/// read from the current instance.
|
||||
/// </returns>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// "<c>fLaC</c>" could not be found.
|
||||
/// </exception>
|
||||
IList<Block> ReadBlocks (ref long start, out long end, BlockMode mode, params BlockType[] types)
|
||||
{
|
||||
List<Block> blocks = new List<Block> ();
|
||||
|
||||
long start_position = Find ("fLaC", start);
|
||||
|
||||
if (start_position < 0)
|
||||
throw new CorruptFileException ("FLAC stream not found at starting position.");
|
||||
|
||||
end = start = start_position + 4;
|
||||
|
||||
Seek (start);
|
||||
|
||||
BlockHeader header;
|
||||
|
||||
do {
|
||||
header = new BlockHeader (ReadBlock ((int)BlockHeader.Size));
|
||||
|
||||
bool found = false;
|
||||
foreach (BlockType type in types)
|
||||
if (header.BlockType == type) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((mode == BlockMode.Whitelist && found) ||
|
||||
(mode == BlockMode.Blacklist && !found))
|
||||
blocks.Add (new Block (header, ReadBlock ((int)header.BlockSize)));
|
||||
else
|
||||
Seek (header.BlockSize, System.IO.SeekOrigin.Current);
|
||||
|
||||
end += header.BlockSize + BlockHeader.Size;
|
||||
} while (!header.IsLastBlock);
|
||||
|
||||
return blocks;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This class extends <see cref="CombinedTag" /> to provide support
|
||||
/// for reading and writing FLAC metadata boxes.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// At this point, only Xiph Comments and pictures are supported.
|
||||
/// </remarks>
|
||||
public class Metadata : CombinedTag
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains the pictures.
|
||||
/// </summary>
|
||||
readonly List<IPicture> pictures = new List<IPicture> ();
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Metadata" /> using a collection of blocks.
|
||||
/// </summary>
|
||||
/// <param name="blocks">
|
||||
/// A <see cref="T:System.Collections.Generic.List`1" /> object containing <see
|
||||
/// cref="Block" /> objects to use in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="blocks" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
[Obsolete ("Use Metadata(IEnumerable<Block>)")]
|
||||
public Metadata (List<Block> blocks)
|
||||
: this (blocks as IEnumerable<Block>)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Metadata" /> using a collection of blocks.
|
||||
/// </summary>
|
||||
/// <param name="blocks">
|
||||
/// A <see cref="T:System.Collections.Generic.IEnumerable`1" /> object enumerating <see
|
||||
/// cref="Block" /> objects to use in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="blocks" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public Metadata (IEnumerable<Block> blocks)
|
||||
{
|
||||
if (blocks == null)
|
||||
throw new ArgumentNullException (nameof (blocks));
|
||||
|
||||
foreach (Block block in blocks) {
|
||||
if (block.Data.Count == 0)
|
||||
continue;
|
||||
|
||||
if (block.Type == BlockType.XiphComment)
|
||||
AddTag (new Ogg.XiphComment (block.Data));
|
||||
else if (block.Type == BlockType.Picture)
|
||||
pictures.Add (new Picture (block.Data));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the first Xiph comment stored in the current
|
||||
/// instance, optionally creating one if necessary.
|
||||
/// </summary>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> value indicating whether or not a
|
||||
/// comment should be added if one cannot be found.
|
||||
/// </param>
|
||||
/// <param name="copy">
|
||||
/// A <see cref="Tag" /> object containing the source tag to
|
||||
/// copy the values from, or <see langword="null" /> to not
|
||||
/// copy values.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="Ogg.XiphComment" /> object containing the
|
||||
/// tag that was found in or added to the current instance.
|
||||
/// If no matching tag was found and none was created, <see
|
||||
/// langword="null" /> is returned.
|
||||
/// </returns>
|
||||
public Ogg.XiphComment GetComment (bool create, Tag copy)
|
||||
{
|
||||
foreach (Tag t in Tags)
|
||||
if (t is Ogg.XiphComment)
|
||||
return t as Ogg.XiphComment;
|
||||
|
||||
if (!create)
|
||||
return null;
|
||||
|
||||
Ogg.XiphComment c = new Ogg.XiphComment ();
|
||||
|
||||
if (copy != null)
|
||||
copy.CopyTo (c, true);
|
||||
|
||||
AddTag (c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all child Xiph Comments from the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
public void RemoveComment ()
|
||||
{
|
||||
Ogg.XiphComment c;
|
||||
|
||||
while ((c = GetComment (false, null)) != null)
|
||||
RemoveTag (c);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tag types contained in the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A bitwise combined <see cref="TagLib.TagTypes" /> value
|
||||
/// containing the tag types stored in the current instance.
|
||||
/// </value>
|
||||
public override TagTypes TagTypes {
|
||||
get { return TagTypes.FlacMetadata | base.TagTypes; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets a collection of pictures associated with
|
||||
/// the media represented by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="T:IPicture[]" /> containing a collection of
|
||||
/// pictures associated with the media represented by the
|
||||
/// current instance or an empty array if none are present.
|
||||
/// </value>
|
||||
public override IPicture[] Pictures {
|
||||
get { return pictures.ToArray (); }
|
||||
set {
|
||||
pictures.Clear ();
|
||||
if (value != null)
|
||||
pictures.AddRange (value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the values stored in the current instance.
|
||||
/// </summary>
|
||||
public override void Clear ()
|
||||
{
|
||||
pictures.Clear ();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2398030dd33fc28e38d41d1975d6aa92
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,268 @@
|
||||
//
|
||||
// Picture.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;
|
||||
|
||||
namespace TagLib.Flac
|
||||
{
|
||||
/// <summary>
|
||||
/// This class implements <see cref="IPicture" /> to provide support
|
||||
/// for reading and writing Flac picture metadata.
|
||||
/// </summary>
|
||||
public class Picture : IPicture
|
||||
{
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Picture" /> by reading the contents of a raw Flac
|
||||
/// image structure.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the raw
|
||||
/// Flac image.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="data" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// <paramref name="data" /> contains less than 32 bytes.
|
||||
/// </exception>
|
||||
public Picture (ByteVector data)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
if (data.Count < 32)
|
||||
throw new CorruptFileException ("Data must be at least 32 bytes long");
|
||||
|
||||
int pos = 0;
|
||||
Type = (PictureType)data.Mid (pos, 4).ToUInt ();
|
||||
pos += 4;
|
||||
|
||||
int mimetype_length = (int)data.Mid (pos, 4).ToUInt ();
|
||||
pos += 4;
|
||||
|
||||
MimeType = data.ToString (StringType.Latin1, pos,
|
||||
mimetype_length);
|
||||
pos += mimetype_length;
|
||||
|
||||
int description_length = (int)data.Mid (pos, 4)
|
||||
.ToUInt ();
|
||||
pos += 4;
|
||||
|
||||
Description = data.ToString (StringType.UTF8, pos,
|
||||
description_length);
|
||||
pos += description_length;
|
||||
|
||||
Width = (int)data.Mid (pos, 4).ToUInt ();
|
||||
pos += 4;
|
||||
|
||||
Height = (int)data.Mid (pos, 4).ToUInt ();
|
||||
pos += 4;
|
||||
|
||||
ColorDepth = (int)data.Mid (pos, 4).ToUInt ();
|
||||
pos += 4;
|
||||
|
||||
IndexedColors = (int)data.Mid (pos, 4).ToUInt ();
|
||||
pos += 4;
|
||||
|
||||
int data_length = (int)data.Mid (pos, 4).ToUInt ();
|
||||
pos += 4;
|
||||
|
||||
Data = data.Mid (pos, data_length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Picture" /> by copying the properties of a <see
|
||||
/// cref="IPicture" /> object.
|
||||
/// </summary>
|
||||
/// <param name="picture">
|
||||
/// A <see cref="IPicture" /> object to use for the new
|
||||
/// instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="picture" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public Picture (IPicture picture)
|
||||
{
|
||||
if (picture == null)
|
||||
throw new ArgumentNullException (nameof (picture));
|
||||
|
||||
Type = picture.Type;
|
||||
MimeType = picture.MimeType;
|
||||
Filename = picture.Filename;
|
||||
Description = picture.Description;
|
||||
Data = picture.Data;
|
||||
|
||||
if (!(picture is Picture flac_picture))
|
||||
return;
|
||||
|
||||
Width = flac_picture.Width;
|
||||
Height = flac_picture.Height;
|
||||
ColorDepth = flac_picture.ColorDepth;
|
||||
IndexedColors = flac_picture.IndexedColors;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw Flac picture.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public ByteVector Render ()
|
||||
{
|
||||
var data = new ByteVector {
|
||||
ByteVector.FromUInt ((uint)Type)
|
||||
};
|
||||
|
||||
var mime_data = ByteVector.FromString (MimeType,
|
||||
StringType.Latin1);
|
||||
data.Add (ByteVector.FromUInt ((uint)mime_data.Count));
|
||||
data.Add (mime_data);
|
||||
|
||||
var decription_data = ByteVector.FromString (Description, StringType.UTF8);
|
||||
data.Add (ByteVector.FromUInt ((uint)decription_data.Count));
|
||||
data.Add (decription_data);
|
||||
|
||||
data.Add (ByteVector.FromUInt ((uint)Width));
|
||||
data.Add (ByteVector.FromUInt ((uint)Height));
|
||||
data.Add (ByteVector.FromUInt ((uint)ColorDepth));
|
||||
data.Add (ByteVector.FromUInt ((uint)IndexedColors));
|
||||
|
||||
data.Add (ByteVector.FromUInt ((uint)Data.Count));
|
||||
data.Add (Data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the mime-type of the picture data
|
||||
/// stored in the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing the mime-type
|
||||
/// of the picture data stored in the current instance.
|
||||
/// </value>
|
||||
public string MimeType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the type of content visible in the picture
|
||||
/// stored in the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="PictureType" /> containing the type of
|
||||
/// content visible in the picture stored in the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public PictureType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets a filename of the picture stored in the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing a fielname, with
|
||||
/// extension, of the picture stored in the current instance.
|
||||
/// </value>
|
||||
public string Filename { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets a description of the picture stored in the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing a description
|
||||
/// of the picture stored in the current instance.
|
||||
/// </value>
|
||||
public string Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the picture data stored in the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ByteVector" /> object containing the picture
|
||||
/// data stored in the current instance.
|
||||
/// </value>
|
||||
public ByteVector Data { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the width of the picture in the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing width of the
|
||||
/// picture stored in the current instance.
|
||||
/// </value>
|
||||
public int Width { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the height of the picture in the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing height of the
|
||||
/// picture stored in the current instance.
|
||||
/// </value>
|
||||
public int Height { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the color depth of the picture in the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing color depth of the
|
||||
/// picture stored in the current instance.
|
||||
/// </value>
|
||||
public int ColorDepth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the number of indexed colors in the picture
|
||||
/// in the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing number of indexed
|
||||
/// colors in the picture, or zero if the picture is not
|
||||
/// stored in an indexed format.
|
||||
/// </value>
|
||||
public int IndexedColors { get; set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 948078d7fd9adb2fe995d19ef3157a39
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,234 @@
|
||||
//
|
||||
// StreamHeader.cs:
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Original Source:
|
||||
// flagproperties.cpp from TagLib
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
// Copyright (C) 2003 Allan Sandfeld Jensen (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.Flac
|
||||
{
|
||||
/// <summary>
|
||||
/// This structure implements <see cref="IAudioCodec" /> and provides
|
||||
/// information about a Flac audio stream.
|
||||
/// </summary>
|
||||
public struct StreamHeader : IAudioCodec, ILosslessAudioCodec
|
||||
{
|
||||
#region Private Properties
|
||||
|
||||
/// <summary>
|
||||
/// Contains the flags.
|
||||
/// </summary>
|
||||
readonly uint flags;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the low portion of the length.
|
||||
/// </summary>
|
||||
readonly uint low_length;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the stream length.
|
||||
/// </summary>
|
||||
readonly long stream_length;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="StreamHeader" /> by reading a raw stream header
|
||||
/// structure and using the stream length.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the raw
|
||||
/// stream header.
|
||||
/// </param>
|
||||
/// <param name="streamLength">
|
||||
/// A <see cref="long" /> value containing the length of the
|
||||
/// stream.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="data" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// <paramref name="data" /> contains less than 18 bytes.
|
||||
/// </exception>
|
||||
public StreamHeader (ByteVector data, long streamLength)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
if (data.Count < 18)
|
||||
throw new CorruptFileException ("Not enough data in FLAC header.");
|
||||
|
||||
stream_length = streamLength;
|
||||
flags = data.Mid (10, 4).ToUInt (true);
|
||||
low_length = data.Mid (14, 4).ToUInt (true);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the duration of the media represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TimeSpan" /> containing the duration of the
|
||||
/// media represented by the current instance.
|
||||
/// </value>
|
||||
public TimeSpan Duration {
|
||||
get {
|
||||
return (AudioSampleRate > 0 && stream_length > 0)
|
||||
? TimeSpan.FromSeconds (
|
||||
low_length /
|
||||
(double)AudioSampleRate +
|
||||
HighLength) :
|
||||
TimeSpan.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bitrate of the audio represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing a bitrate of the
|
||||
/// audio represented by the current instance.
|
||||
/// </value>
|
||||
public int AudioBitrate {
|
||||
get {
|
||||
return (int)(Duration > TimeSpan.Zero ?
|
||||
((stream_length * 8L) / Duration.TotalSeconds) / 1000 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sample rate of the audio represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the sample rate of
|
||||
/// the audio represented by the current instance.
|
||||
/// </value>
|
||||
public int AudioSampleRate {
|
||||
get { return (int)(flags >> 12); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of channels in the audio represented by
|
||||
/// the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the number of
|
||||
/// channels in the audio represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public int AudioChannels {
|
||||
get { return (int)(((flags >> 9) & 7) + 1); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the types of media represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Always <see cref="MediaTypes.Audio" />.
|
||||
/// </value>
|
||||
public MediaTypes MediaTypes {
|
||||
get { return MediaTypes.Audio; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sample width of the audio represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the sample width of
|
||||
/// the audio represented by the current instance.
|
||||
/// </value>
|
||||
[Obsolete ("This property is depreciated, use BitsPerSample instead")]
|
||||
public int AudioSampleWidth {
|
||||
get { return BitsPerSample; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of bits per sample in the audio
|
||||
/// represented by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the number of bits
|
||||
/// per sample in the audio represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public int BitsPerSample {
|
||||
get { return (int)(((flags >> 4) & 31) + 1); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a text description of the media represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing a description
|
||||
/// of the media represented by the current instance.
|
||||
/// </value>
|
||||
public string Description {
|
||||
get { return "Flac Audio"; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Private Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets a high portion of the length of the audio
|
||||
/// represented by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the high portion
|
||||
/// of the length.
|
||||
/// </value>
|
||||
uint HighLength {
|
||||
get {
|
||||
// The last 4 bits are the most significant 4
|
||||
// bits for the 36 bit stream length in samples.
|
||||
// (Audio files measured in days)
|
||||
return (uint)(AudioSampleRate > 0 ?
|
||||
(((flags & 0xf) << 28) /
|
||||
AudioSampleRate) << 4 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 246c726d80e7bc9c68f191ac3d18e936
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,402 @@
|
||||
//
|
||||
// Genres.cs: Provides convenience functions for converting between String
|
||||
// genres and their respective audio and video indices as used by several
|
||||
// formats.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Original Source:
|
||||
// id3v1genres.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
|
||||
{
|
||||
/// <summary>
|
||||
/// This static class provides convenience functions for converting
|
||||
/// between <see cref="string" /> genres and their respective audio
|
||||
/// and video indices as used by several formats.
|
||||
/// </summary>
|
||||
public static class Genres
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains a list of ID3v1 audio generes.
|
||||
/// </summary>
|
||||
static readonly string[] audio = {
|
||||
"Blues",
|
||||
"Classic Rock",
|
||||
"Country",
|
||||
"Dance",
|
||||
"Disco",
|
||||
"Funk",
|
||||
"Grunge",
|
||||
"Hip-Hop",
|
||||
"Jazz",
|
||||
"Metal",
|
||||
"New Age",
|
||||
"Oldies",
|
||||
"Other",
|
||||
"Pop",
|
||||
"R&B",
|
||||
"Rap",
|
||||
"Reggae",
|
||||
"Rock",
|
||||
"Techno",
|
||||
"Industrial",
|
||||
"Alternative",
|
||||
"Ska",
|
||||
"Death Metal",
|
||||
"Pranks",
|
||||
"Soundtrack",
|
||||
"Euro-Techno",
|
||||
"Ambient",
|
||||
"Trip-Hop",
|
||||
"Vocal",
|
||||
"Jazz+Funk",
|
||||
"Fusion",
|
||||
"Trance",
|
||||
"Classical",
|
||||
"Instrumental",
|
||||
"Acid",
|
||||
"House",
|
||||
"Game",
|
||||
"Sound Clip",
|
||||
"Gospel",
|
||||
"Noise",
|
||||
"Alternative Rock",
|
||||
"Bass",
|
||||
"Soul",
|
||||
"Punk",
|
||||
"Space",
|
||||
"Meditative",
|
||||
"Instrumental Pop",
|
||||
"Instrumental Rock",
|
||||
"Ethnic",
|
||||
"Gothic",
|
||||
"Darkwave",
|
||||
"Techno-Industrial",
|
||||
"Electronic",
|
||||
"Pop-Folk",
|
||||
"Eurodance",
|
||||
"Dream",
|
||||
"Southern Rock",
|
||||
"Comedy",
|
||||
"Cult",
|
||||
"Gangsta",
|
||||
"Top 40",
|
||||
"Christian Rap",
|
||||
"Pop/Funk",
|
||||
"Jungle",
|
||||
"Native American",
|
||||
"Cabaret",
|
||||
"New Wave",
|
||||
"Psychedelic",
|
||||
"Rave",
|
||||
"Showtunes",
|
||||
"Trailer",
|
||||
"Lo-Fi",
|
||||
"Tribal",
|
||||
"Acid Punk",
|
||||
"Acid Jazz",
|
||||
"Polka",
|
||||
"Retro",
|
||||
"Musical",
|
||||
"Rock & Roll",
|
||||
"Hard Rock",
|
||||
"Folk",
|
||||
"Folk/Rock",
|
||||
"National Folk",
|
||||
"Swing",
|
||||
"Fusion",
|
||||
"Bebob",
|
||||
"Latin",
|
||||
"Revival",
|
||||
"Celtic",
|
||||
"Bluegrass",
|
||||
"Avantgarde",
|
||||
"Gothic Rock",
|
||||
"Progressive Rock",
|
||||
"Psychedelic Rock",
|
||||
"Symphonic Rock",
|
||||
"Slow Rock",
|
||||
"Big Band",
|
||||
"Chorus",
|
||||
"Easy Listening",
|
||||
"Acoustic",
|
||||
"Humour",
|
||||
"Speech",
|
||||
"Chanson",
|
||||
"Opera",
|
||||
"Chamber Music",
|
||||
"Sonata",
|
||||
"Symphony",
|
||||
"Booty Bass",
|
||||
"Primus",
|
||||
"Porn Groove",
|
||||
"Satire",
|
||||
"Slow Jam",
|
||||
"Club",
|
||||
"Tango",
|
||||
"Samba",
|
||||
"Folklore",
|
||||
"Ballad",
|
||||
"Power Ballad",
|
||||
"Rhythmic Soul",
|
||||
"Freestyle",
|
||||
"Duet",
|
||||
"Punk Rock",
|
||||
"Drum Solo",
|
||||
"A Cappella",
|
||||
"Euro-House",
|
||||
"Dance Hall",
|
||||
"Goa",
|
||||
"Drum & Bass",
|
||||
"Club-House",
|
||||
"Hardcore",
|
||||
"Terror",
|
||||
"Indie",
|
||||
"BritPop",
|
||||
"Negerpunk",
|
||||
"Polsk Punk",
|
||||
"Beat",
|
||||
"Christian Gangsta Rap",
|
||||
"Heavy Metal",
|
||||
"Black Metal",
|
||||
"Crossover",
|
||||
"Contemporary Christian",
|
||||
"Christian Rock",
|
||||
"Merengue",
|
||||
"Salsa",
|
||||
"Thrash Metal",
|
||||
"Anime",
|
||||
"Jpop",
|
||||
"Synthpop"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Contains a list of DivX audio generes.
|
||||
/// </summary>
|
||||
static readonly string[] video = new[] {
|
||||
"Action",
|
||||
"Action/Adventure",
|
||||
"Adult",
|
||||
"Adventure",
|
||||
"Catastrophe",
|
||||
"Child's",
|
||||
"Claymation",
|
||||
"Comedy",
|
||||
"Concert",
|
||||
"Documentary",
|
||||
"Drama",
|
||||
"Eastern",
|
||||
"Entertaining",
|
||||
"Erotic",
|
||||
"Extremal Sport",
|
||||
"Fantasy",
|
||||
"Fashion",
|
||||
"Historical",
|
||||
"Horror",
|
||||
"Horror/Mystic",
|
||||
"Humor",
|
||||
"Indian",
|
||||
"Informercial",
|
||||
"Melodrama",
|
||||
"Military & War",
|
||||
"Music Video",
|
||||
"Musical",
|
||||
"Mystery",
|
||||
"Nature",
|
||||
"Political Satire",
|
||||
"Popular Science",
|
||||
"Psychological Thriller",
|
||||
"Religion",
|
||||
"Science Fiction",
|
||||
"Scifi Action",
|
||||
"Slapstick",
|
||||
"Splatter",
|
||||
"Sports",
|
||||
"Thriller",
|
||||
"Western"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of standard audio generes.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="T:string[]" /> containing standard audio
|
||||
/// genres.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// The genres are stored in the same order and with the same
|
||||
/// values as in the ID3v1 format.
|
||||
/// </remarks>
|
||||
public static string[] Audio {
|
||||
get { return (string[])audio.Clone (); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of standard video generes.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="T:string[]" /> containing standard video
|
||||
/// genres.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// The genres are stored in the same order and with the same
|
||||
/// values as in the DivX format.
|
||||
/// </remarks>
|
||||
public static string[] Video {
|
||||
get { return (string[])video.Clone (); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the genre index for a specified audio genre.
|
||||
/// </summary>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// genre to look up.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="byte" /> value containing the index of the
|
||||
/// genre in the audio array or 255 if it could not be found.
|
||||
/// </returns>
|
||||
public static byte AudioToIndex (string name)
|
||||
{
|
||||
for (byte i = 0; i < audio.Length; i++)
|
||||
if (name == audio[i])
|
||||
return i;
|
||||
return 255;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the genre index for a specified video genre.
|
||||
/// </summary>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// genre to look up.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="byte" /> value containing the index of the
|
||||
/// genre in the video array or 255 if it could not be found.
|
||||
/// </returns>
|
||||
public static byte VideoToIndex (string name)
|
||||
{
|
||||
for (byte i = 0; i < video.Length; i++)
|
||||
if (name == video[i])
|
||||
return i;
|
||||
return 255;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the audio genre from its index in the array.
|
||||
/// </summary>
|
||||
/// <param name="index">
|
||||
/// A <see cref="byte" /> value containing the index to
|
||||
/// aquire the genre from.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="string" /> object containing the audio genre
|
||||
/// found at the index, or <see langword="null" /> if it does
|
||||
/// not exist.
|
||||
/// </returns>
|
||||
public static string IndexToAudio (byte index)
|
||||
{
|
||||
return (index < audio.Length) ? audio[index] : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the video genre from its index in the array.
|
||||
/// </summary>
|
||||
/// <param name="index">
|
||||
/// A <see cref="byte" /> value containing the index to
|
||||
/// aquire the genre from.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="string" /> object containing the video genre
|
||||
/// found at the index, or <see langword="null" /> if it does
|
||||
/// not exist.
|
||||
/// </returns>
|
||||
public static string IndexToVideo (byte index)
|
||||
{
|
||||
return (index < video.Length) ? video[index] : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the audio genre from its index in the array.
|
||||
/// </summary>
|
||||
/// <param name="text">
|
||||
/// A <see cref="string" /> object, either in the format
|
||||
/// <c>"(123)"</c> or <c>"123"</c>.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="string" /> object containing the audio genre
|
||||
/// found at the index, or <see langword="null" /> if it does
|
||||
/// not exist.
|
||||
/// </returns>
|
||||
public static string IndexToAudio (string text)
|
||||
{
|
||||
return IndexToAudio (StringToByte (text));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the video genre from its index in the array.
|
||||
/// </summary>
|
||||
/// <param name="text">
|
||||
/// A <see cref="string" /> object, either in the format
|
||||
/// <c>"(123)"</c> or <c>"123"</c>.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="string" /> object containing the video genre
|
||||
/// found at the index, or <see langword="null" /> if it does
|
||||
/// not exist.
|
||||
/// </returns>
|
||||
public static string IndexToVideo (string text)
|
||||
{
|
||||
return IndexToVideo (StringToByte (text));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a string, either in the format <c>"(123)"</c> or
|
||||
/// <c>"123"</c> into a byte or equal numeric value.
|
||||
/// </summary>
|
||||
/// <param name="text">
|
||||
/// A <see cref="string" /> object, either in the format
|
||||
/// <c>"(123)"</c> or <c>"123"</c>, to be converted.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="byte" /> value containing the numeric value
|
||||
/// of <paramref name="text" /> or 255 if no numeric value
|
||||
/// could be extracted.
|
||||
/// </returns>
|
||||
static byte StringToByte (string text)
|
||||
{
|
||||
int last_pos;
|
||||
if (text != null && text.Length > 2 && text[0] == '('
|
||||
&& (last_pos = text.IndexOf (')')) != -1
|
||||
&& byte.TryParse (text.Substring (1, last_pos - 1), out var value))
|
||||
return value;
|
||||
|
||||
if (text != null && byte.TryParse (text, out value))
|
||||
return value;
|
||||
|
||||
return 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 43e436b8e6a5ac91eb7992b11dd1e2c8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e80fdad1f70cff659bf3a310ada660df
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,60 @@
|
||||
//
|
||||
// Codec.cs:
|
||||
//
|
||||
// Author:
|
||||
// Mike Gemuende (mike@gemuende.be)
|
||||
//
|
||||
// Copyright (C) 2010 Mike Gemuende
|
||||
//
|
||||
// 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.Gif
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// A Gif photo codec. Contains basic photo details.
|
||||
/// </summary>
|
||||
public class Codec : Image.Codec
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Gets a text description of the media represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing a description
|
||||
/// of the media represented by the current instance.
|
||||
/// </value>
|
||||
public override string Description { get { return "GIF File"; } }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new <see cref="Codec" /> with the given width
|
||||
/// and height.
|
||||
/// </summary>
|
||||
/// <param name="width">
|
||||
/// The width of the photo.
|
||||
/// </param>
|
||||
/// <param name="height">
|
||||
/// The height of the photo.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A new <see cref="Codec" /> instance.
|
||||
/// </returns>
|
||||
public Codec (int width, int height)
|
||||
: base (width, height) { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47cdd5f88d9090727bd3e17f4f9c0893
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,782 @@
|
||||
//
|
||||
// File.cs: Provides tagging for GIF files
|
||||
//
|
||||
// Author:
|
||||
// Mike Gemuende (mike@gemuende.be)
|
||||
//
|
||||
// Copyright (C) 2010 Mike Gemuende
|
||||
//
|
||||
// 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.IO;
|
||||
|
||||
using TagLib.Image;
|
||||
using TagLib.Xmp;
|
||||
|
||||
namespace TagLib.Gif
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This class extends <see cref="TagLib.Image.ImageBlockFile" /> to provide tagging
|
||||
/// and property support for Gif files.
|
||||
/// </summary>
|
||||
[SupportedMimeType ("taglib/gif", "gif")]
|
||||
[SupportedMimeType ("image/gif")]
|
||||
public class File : ImageBlockFile
|
||||
{
|
||||
|
||||
#region GIF specific constants
|
||||
|
||||
/// <summary>
|
||||
/// Gif file signature which occurs at the begin of the file
|
||||
/// </summary>
|
||||
protected static readonly string SIGNATURE = "GIF";
|
||||
|
||||
/// <summary>
|
||||
/// String which is used to indicate version the gif file format version 87a
|
||||
/// </summary>
|
||||
protected static readonly string VERSION_87A = "87a";
|
||||
|
||||
/// <summary>
|
||||
/// String which is used to indicate version the gif file format version 89a
|
||||
/// </summary>
|
||||
protected static readonly string VERSION_89A = "89a";
|
||||
|
||||
/// <summary>
|
||||
/// Application Extension Identifier for an XMP Block
|
||||
/// </summary>
|
||||
static readonly string XMP_IDENTIFIER = "XMP Data";
|
||||
|
||||
/// <summary>
|
||||
/// Application Authentication Extension Code for an XMP Block
|
||||
/// </summary>
|
||||
static readonly string XMP_AUTH_CODE = "XMP";
|
||||
|
||||
/// <summary>
|
||||
/// The Magic Trailer for XMP Data
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The storage of XMP data in GIF does not follow the GIF specification. According to the
|
||||
/// specification, extension data is stored in so-called sub-blocks, which start with a length
|
||||
/// byte which specifies the number of data bytes contained in the sub block. So a block can at
|
||||
/// most contain 256 data bytes. After a sub-block, the next sub-block begins. The sequence ends,
|
||||
/// when a sub-block starts with 0. So readers, which are not aware of the XMP data not following
|
||||
/// this scheme, will get confused by the XMP data. To fix this, this trailer is added to the end.
|
||||
/// It has a length of 258 bytes, so that it is ensured that a reader which tries to skip the
|
||||
/// XMP data reads one of this bytes as length of a sub-block. But, each byte points with its length
|
||||
/// to the last one. Therefoe, independent of the byte, the reader reads as sub-block length, it is
|
||||
/// redirected to the last byte of the trailer and therfore to the end of the XMP data.
|
||||
/// </remarks>
|
||||
static readonly byte[] XMP_MAGIC_TRAILER = new byte[] {
|
||||
0x01, 0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8, 0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF2, 0xF1,
|
||||
0xF0, 0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8, 0xE7, 0xE6, 0xE5, 0xE4, 0xE3, 0xE2, 0xE1,
|
||||
0xE0, 0xDF, 0xDE, 0xDD, 0xDC, 0xDB, 0xDA, 0xD9, 0xD8, 0xD7, 0xD6, 0xD5, 0xD4, 0xD3, 0xD2, 0xD1,
|
||||
0xD0, 0xCF, 0xCE, 0xCD, 0xCC, 0xCB, 0xCA, 0xC9, 0xC8, 0xC7, 0xC6, 0xC5, 0xC4, 0xC3, 0xC2, 0xC1,
|
||||
0xC0, 0xBF, 0xBE, 0xBD, 0xBC, 0xBB, 0xBA, 0xB9, 0xB8, 0xB7, 0xB6, 0xB5, 0xB4, 0xB3, 0xB2, 0xB1,
|
||||
0xB0, 0xAF, 0xAE, 0xAD, 0xAC, 0xAB, 0xAA, 0xA9, 0xA8, 0xA7, 0xA6, 0xA5, 0xA4, 0xA3, 0xA2, 0xA1,
|
||||
0xA0, 0x9F, 0x9E, 0x9D, 0x9C, 0x9B, 0x9A, 0x99, 0x98, 0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91,
|
||||
0x90, 0x8F, 0x8E, 0x8D, 0x8C, 0x8B, 0x8A, 0x89, 0x88, 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81,
|
||||
0x80, 0x7F, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71,
|
||||
0x70, 0x6F, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69, 0x68, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0x61,
|
||||
0x60, 0x5F, 0x5E, 0x5D, 0x5C, 0x5B, 0x5A, 0x59, 0x58, 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51,
|
||||
0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41,
|
||||
0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31,
|
||||
0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21,
|
||||
0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11,
|
||||
0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
|
||||
0x00, 0x00
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#region private fields
|
||||
|
||||
/// <summary>
|
||||
/// The width of the image
|
||||
/// </summary>
|
||||
int width;
|
||||
|
||||
/// <summary>
|
||||
/// The height of the image
|
||||
/// </summary>
|
||||
int height;
|
||||
|
||||
/// <summary>
|
||||
/// The Properties of the image
|
||||
/// </summary>
|
||||
Properties properties;
|
||||
|
||||
/// <summary>
|
||||
/// The version of the file format
|
||||
/// </summary>
|
||||
string version;
|
||||
|
||||
/// <summary>
|
||||
/// The start of the first block in file after the header.
|
||||
/// </summary>
|
||||
long start_of_blocks = -1;
|
||||
|
||||
#endregion
|
||||
|
||||
#region public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the media properties of the file represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TagLib.Properties" /> object containing the
|
||||
/// media properties of the file represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public override Properties Properties {
|
||||
get { return properties; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local file
|
||||
/// system and specified read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path, ReadStyle propertiesStyle)
|
||||
: this (new LocalFileAbstraction (path), propertiesStyle)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local file
|
||||
/// system.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path) : this (path, ReadStyle.Average)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction and
|
||||
/// specified read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction, ReadStyle propertiesStyle)
|
||||
: base (abstraction)
|
||||
{
|
||||
Read (propertiesStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
protected File (IFileAbstraction abstraction)
|
||||
: this (abstraction, ReadStyle.Average)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Saves the changes made in the current instance to the
|
||||
/// file it represents.
|
||||
/// </summary>
|
||||
public override void Save ()
|
||||
{
|
||||
// Boilerplate
|
||||
PreSave ();
|
||||
|
||||
Mode = AccessMode.Write;
|
||||
try {
|
||||
SaveMetadata ();
|
||||
|
||||
TagTypesOnDisk = TagTypes;
|
||||
} finally {
|
||||
Mode = AccessMode.Closed;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Reads the information from file with a specified read style.
|
||||
/// </summary>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
void Read (ReadStyle propertiesStyle)
|
||||
{
|
||||
Mode = AccessMode.Read;
|
||||
try {
|
||||
ImageTag = new CombinedImageTag (TagTypes.XMP | TagTypes.GifComment);
|
||||
|
||||
ReadHeader ();
|
||||
ReadMetadata ();
|
||||
|
||||
TagTypesOnDisk = TagTypes;
|
||||
|
||||
if ((propertiesStyle & ReadStyle.Average) != 0)
|
||||
properties = ExtractProperties ();
|
||||
|
||||
} finally {
|
||||
Mode = AccessMode.Closed;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reads a single byte form file. This is needed often for Gif files.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="System.Byte"/> with the read data.
|
||||
/// </returns>
|
||||
byte ReadByte ()
|
||||
{
|
||||
ByteVector data = ReadBlock (1);
|
||||
|
||||
if (data.Count != 1)
|
||||
throw new CorruptFileException ("Unexpected end of file");
|
||||
|
||||
return data[0];
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reads the Header and the Logical Screen Descriptor of the GIF file and,
|
||||
/// if there is one, skips the global color table. It also extracts the
|
||||
/// image width and height from it.
|
||||
/// </summary>
|
||||
void ReadHeader ()
|
||||
{
|
||||
// The header consists of:
|
||||
//
|
||||
// 3 Bytes Signature
|
||||
// 3 Bytes Version
|
||||
//
|
||||
// The Logical Screen Descriptor of:
|
||||
//
|
||||
// 2 Bytes Width (little endian)
|
||||
// 2 Bytes Height (little endian)
|
||||
// 1 Byte Screen and Color Map (packed field)
|
||||
// 1 Byte Background Color
|
||||
// 1 Byte Aspect Ratio
|
||||
//
|
||||
// Whereas the bits of the packed field contains some special information.
|
||||
ByteVector data = ReadBlock (13);
|
||||
|
||||
if (data.Count != 13)
|
||||
throw new CorruptFileException ("Unexpected end of Header");
|
||||
|
||||
if (data.Mid (0, 3).ToString () != SIGNATURE)
|
||||
throw new CorruptFileException (
|
||||
$"Expected a GIF signature at start of file, but found: {data.Mid (0, 3)}");
|
||||
|
||||
// We do not care about the version here, because we can read both versions in the same way.
|
||||
// We just care when writing metadata, that, if necessary, the version is increased to 89a.
|
||||
var read_version = data.Mid (3, 3).ToString ();
|
||||
if (read_version == VERSION_87A || read_version == VERSION_89A)
|
||||
version = read_version;
|
||||
else
|
||||
throw new UnsupportedFormatException (
|
||||
$"Only GIF versions 87a and 89a are currently supported, but not: {read_version}");
|
||||
|
||||
// Read Image Size (little endian)
|
||||
width = data.Mid (6, 2).ToUShort (false);
|
||||
height = data.Mid (8, 2).ToUShort (false);
|
||||
|
||||
// Skip optional global color table
|
||||
SkipColorTable (data[10]);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reads the metadata from file. The current position must point to the
|
||||
/// start of the first block after the Header and Logical Screen
|
||||
/// Descriptor (and, if there is one, the Global Color Table)
|
||||
/// </summary>
|
||||
void ReadMetadata ()
|
||||
{
|
||||
start_of_blocks = Tell;
|
||||
|
||||
// Read Blocks until end of file is reached.
|
||||
while (true) {
|
||||
byte identifier = ReadByte ();
|
||||
|
||||
switch (identifier) {
|
||||
case 0x2c:
|
||||
SkipImage ();
|
||||
break;
|
||||
|
||||
case 0x21:
|
||||
ReadExtensionBlock ();
|
||||
break;
|
||||
|
||||
case 0x3B:
|
||||
return;
|
||||
|
||||
default:
|
||||
throw new CorruptFileException (
|
||||
$"Do not know what to do with byte 0x{identifier:X2} at the beginning of a block ({Tell - 1}).");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads an Extension Block at the current position. The current position must
|
||||
/// point to the 2nd byte of the comment block. (The other byte is usually
|
||||
/// read before to identify the comment block)
|
||||
/// </summary>
|
||||
void ReadExtensionBlock ()
|
||||
{
|
||||
// Extension Block
|
||||
//
|
||||
// 1 Byte Extension Introducer (0x21)
|
||||
// 1 Byte Extension Identifier
|
||||
// ....
|
||||
//
|
||||
// Note, the Extension Introducer was read before to
|
||||
// identify the Extension Block. Therefore, it has not
|
||||
// to be handled here.
|
||||
byte identifier = ReadByte ();
|
||||
|
||||
switch (identifier) {
|
||||
case 0xFE:
|
||||
ReadCommentBlock ();
|
||||
break;
|
||||
|
||||
case 0xFF:
|
||||
ReadApplicationExtensionBlock ();
|
||||
break;
|
||||
|
||||
// Control Extension Block, ...
|
||||
case 0xF9:
|
||||
// ... Plain Text Extension ...
|
||||
case 0x01:
|
||||
// ... and all other unknown blocks can be skipped by just
|
||||
// reading sub-blocks.
|
||||
default:
|
||||
SkipSubBlocks ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reads an Application Extension Block at the current position. The current
|
||||
/// position must point to the 3rd byte of the comment block. (The other 2 bytes
|
||||
/// are usually read before to identify the comment block)
|
||||
/// </summary>
|
||||
void ReadApplicationExtensionBlock ()
|
||||
{
|
||||
// Application Extension Block
|
||||
//
|
||||
// 1 Byte Extension Introducer (0x21)
|
||||
// 1 Byte Application Extension Label (0xFF)
|
||||
// 1 Byte Block Size (0x0B - 11)
|
||||
// 8 Bytes Application Identifier
|
||||
// 3 Bytes Application Auth. Code
|
||||
// N Bytes Application Data (sub blocks)
|
||||
// 1 Byte Block Terminator (0x00)
|
||||
//
|
||||
// Note, the first 2 bytes are still read to identify the Comment Block.
|
||||
// Therefore, we only need to read the sub blocks and extract the data.
|
||||
long position = Tell;
|
||||
ByteVector data = ReadBlock (12);
|
||||
|
||||
if (data.Count != 12)
|
||||
throw new CorruptFileException ("");
|
||||
|
||||
// Contains XMP data
|
||||
if (data.Mid (1, 8) == XMP_IDENTIFIER && data.Mid (9, 3) == XMP_AUTH_CODE) {
|
||||
// XMP Data is not organized in sub-blocks
|
||||
|
||||
// start of xmp data
|
||||
long data_start = Tell;
|
||||
|
||||
// start of trailer start
|
||||
// FIXME: Since File.Find is still buggy, the following call does not work to find the end of the
|
||||
// XMP data. Therfore, we use here a different way for now.
|
||||
//long xmp_trailer_start = Find (new ByteVector (0x00), data_start);
|
||||
|
||||
// Since searching just one byte is save, we search for the end of the xmp trailer which
|
||||
// consists of two 0x00 bytes and compute the expected start.
|
||||
long xmp_trailer_start = Find (new byte[] { 0x00 }, data_start) - XMP_MAGIC_TRAILER.Length + 2;
|
||||
|
||||
Seek (data_start, SeekOrigin.Begin);
|
||||
|
||||
if (xmp_trailer_start <= data_start)
|
||||
throw new CorruptFileException ("No End of XMP data found");
|
||||
|
||||
// length of xmp data
|
||||
int data_length = (int)(xmp_trailer_start - data_start);
|
||||
|
||||
ByteVector xmp_data = ReadBlock (data_length);
|
||||
ImageTag.AddTag (new XmpTag (xmp_data.ToString (StringType.UTF8), this));
|
||||
|
||||
// 2 bytes where read before
|
||||
AddMetadataBlock (position - 2, 14 + data_length + XMP_MAGIC_TRAILER.Length);
|
||||
|
||||
// set position behind the XMP block
|
||||
Seek (xmp_trailer_start + XMP_MAGIC_TRAILER.Length, SeekOrigin.Begin);
|
||||
|
||||
} else {
|
||||
SkipSubBlocks ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reads a Comment Block at the current position. The current position must
|
||||
/// point to the 3rd byte of the comment block. (The other 2 bytes are usually
|
||||
/// read before to identify the comment block)
|
||||
/// </summary>
|
||||
void ReadCommentBlock ()
|
||||
{
|
||||
long position = Tell;
|
||||
|
||||
// Comment Extension
|
||||
//
|
||||
// 1 Byte Extension Introducer (0x21)
|
||||
// 1 Byte Comment Label (0xFE)
|
||||
// N Bytes Comment Data (Sub Blocks)
|
||||
// 1 Byte Block Terminator (0x00)
|
||||
//
|
||||
// Note, the first 2 bytes are still read to identify the Comment Block.
|
||||
// Therefore, we only need to read the sub blocks and extract the data.
|
||||
|
||||
string comment = ReadSubBlocks ();
|
||||
|
||||
// Only add the tag, if no one is still contained.
|
||||
if ((TagTypes & TagTypes.GifComment) == 0x00) {
|
||||
ImageTag.AddTag (new GifCommentTag (comment));
|
||||
|
||||
// 2 bytes where read before
|
||||
AddMetadataBlock (position - 2, Tell - position + 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Skips the color table if there is one
|
||||
/// </summary>
|
||||
/// <param name="packed_data">
|
||||
/// A <see cref="System.Byte"/> with the packed data which is
|
||||
/// contained Logical Screen Descriptor or in the Image Descriptor.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// The data contained in the packed data is different for the Logical
|
||||
/// Screen Descriptor and for the Image Descriptor. But fortunately,
|
||||
/// the bits which are used do identifying the exitstance and the size
|
||||
/// of the color table are at the same position.
|
||||
/// </remarks>
|
||||
void SkipColorTable (byte packed_data)
|
||||
{
|
||||
// Packed Field (Information with Bit 0 is LSB)
|
||||
//
|
||||
// Bit 0-2 Size of Color Table
|
||||
// Bit 3-6 Other stuff
|
||||
// Bit 7 (Local|Global) Color Table Flag
|
||||
//
|
||||
// We are interested in Bit 7 which indicates if a global color table is
|
||||
// present or not and the Bits 0-2 which indicate the size of the color
|
||||
// table.
|
||||
if ((packed_data & 0x80) == 0x80) {
|
||||
// 2^(size + 1) for each color.
|
||||
int table_size = 3 * (1 << ((packed_data & 0x07) + 1));
|
||||
|
||||
// and simply skip the color table
|
||||
ByteVector color_table = ReadBlock (table_size);
|
||||
|
||||
if (color_table.Count != table_size)
|
||||
throw new CorruptFileException ("Unexpected end of Color Table");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Skip over the image data at the current position. The current position must
|
||||
/// point to 2nd byte of the Image Descriptor. (First byte is usually read before
|
||||
/// to identify the image descriptor.)
|
||||
/// </summary>
|
||||
void SkipImage ()
|
||||
{
|
||||
// Image Descriptor
|
||||
//
|
||||
// 1 Byte Separator (0x2C)
|
||||
// 2 Bytes Image Left Position (little endian)
|
||||
// 2 Bytes Image Right Position (little endian)
|
||||
// 2 Bytes Image Witdh (little endian)
|
||||
// 2 Bytes Image Height (little endian)
|
||||
// 1 Byte Packed Data
|
||||
//
|
||||
// Note, the Separator was read before to identify the Image Block
|
||||
// Therefore, we only need to read 9 bytes here.
|
||||
ByteVector data = ReadBlock (9);
|
||||
|
||||
if (data.Count != 9)
|
||||
throw new CorruptFileException ("Unexpected end of Image Descriptor");
|
||||
|
||||
// Skip an optional local color table
|
||||
SkipColorTable (data[8]);
|
||||
|
||||
|
||||
// Image Data
|
||||
//
|
||||
// 1 Byte LZW Minimum Code Size
|
||||
// N Bytes Image Data (Sub-Blocks)
|
||||
//
|
||||
// Before the image data, one byte for LZW encoding information is used.
|
||||
// This byte is read first, then the sub-blocks are skipped.
|
||||
ReadBlock (1);
|
||||
SkipSubBlocks ();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reads a sequence of sub-blocks from the current position and concatenates the data
|
||||
/// from the sub-blocks to a string. The current position must point to the size-byte
|
||||
/// of the first subblock to skip.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="System.String"/> with the data contained in the sub-blocks.
|
||||
/// </returns>
|
||||
string ReadSubBlocks ()
|
||||
{
|
||||
// Sub Block
|
||||
// Starts with one byte with the number of data bytes
|
||||
// following. The last sub block is terminated by length 0
|
||||
var builder = new System.Text.StringBuilder ();
|
||||
|
||||
byte length = 0;
|
||||
|
||||
do {
|
||||
|
||||
if (length >= 0)
|
||||
builder.Append (ReadBlock (length));
|
||||
|
||||
// read new length byte
|
||||
length = ReadByte ();
|
||||
|
||||
// The sub-blocks are terminated with 0
|
||||
} while (length != 0);
|
||||
|
||||
return builder.ToString ();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Skips over a sequence of sub-blocks from the current position in the file.
|
||||
/// The current position must point to the size-byte of the first subblock to skip.
|
||||
/// </summary>
|
||||
void SkipSubBlocks ()
|
||||
{
|
||||
// Sub Block
|
||||
// Starts with one byte with the number of data bytes
|
||||
// following. The last sub block is terminated by length 0
|
||||
byte length = 0;
|
||||
|
||||
do {
|
||||
|
||||
if (Tell + length >= Length)
|
||||
throw new CorruptFileException ("Unexpected end of Sub-Block");
|
||||
|
||||
// Seek to end of sub-block and update the position
|
||||
Seek (Tell + length, SeekOrigin.Begin);
|
||||
|
||||
|
||||
// read new length byte
|
||||
length = ReadByte ();
|
||||
|
||||
// The sub-blocks are terminated with 0
|
||||
} while (length != 0);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Save the metadata to file.
|
||||
/// </summary>
|
||||
void SaveMetadata ()
|
||||
{
|
||||
ByteVector comment_block = RenderGifCommentBlock ();
|
||||
ByteVector xmp_block = RenderXMPBlock ();
|
||||
|
||||
// If we write metadata and the version is not 89a, bump the format version
|
||||
// because application extension blocks and comment extension blocks are
|
||||
// specified in 89a.
|
||||
// If we do not write metadata or if metadata is deleted, we do not care
|
||||
// about the version, because it may be wrong before.
|
||||
if (comment_block != null && xmp_block != null && version != VERSION_89A) {
|
||||
Insert (VERSION_89A, 3, VERSION_89A.Length);
|
||||
}
|
||||
|
||||
// now, only metadata is stored at the beginning of the file, and we can overwrite it.
|
||||
var metadata_blocks = new ByteVector {
|
||||
comment_block,
|
||||
xmp_block
|
||||
};
|
||||
|
||||
SaveMetadata (metadata_blocks, start_of_blocks);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Renders the XMP data to a Application Extension Block which can be
|
||||
/// embedded in a Gif file.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector"/> with the Application Extension Block for the
|
||||
/// XMP data, or <see langword="null" /> if the file does not have XMP data.
|
||||
/// </returns>
|
||||
ByteVector RenderXMPBlock ()
|
||||
{
|
||||
// Check, if XmpTag is contained
|
||||
XmpTag xmp = ImageTag.Xmp;
|
||||
if (xmp == null)
|
||||
return null;
|
||||
|
||||
var xmp_data = new ByteVector {
|
||||
|
||||
// Add Extension Introducer (0x21), Application Extension Label (0xFF) and
|
||||
// the Block Size (0x0B
|
||||
new byte[] { 0x21, 0xFF, 0x0B },
|
||||
|
||||
// Application Identifier and Appl. Auth. Code
|
||||
XMP_IDENTIFIER,
|
||||
XMP_AUTH_CODE,
|
||||
|
||||
// Add XMP data and Magic Trailer
|
||||
// For XMP, we do not need to store the data in sub-blocks, therfore we
|
||||
// can just add the whole rendered data. (The trailer fixes this)
|
||||
xmp.Render (),
|
||||
XMP_MAGIC_TRAILER
|
||||
};
|
||||
|
||||
return xmp_data;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Renders the Gif Comment to a Comment Extension Block which can be
|
||||
/// embedded in a Gif file.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector"/> with the Comment Extension Block for the
|
||||
/// Gif Comment, or <see langword="null" /> if the file does not have
|
||||
/// a Gif Comment.
|
||||
/// </returns>
|
||||
ByteVector RenderGifCommentBlock ()
|
||||
{
|
||||
// Check, if GifCommentTag is contained
|
||||
if (!(GetTag (TagTypes.GifComment) is GifCommentTag comment_tag))
|
||||
return null;
|
||||
|
||||
string comment = comment_tag.Comment;
|
||||
if (comment == null)
|
||||
return null;
|
||||
|
||||
ByteVector comment_data = new ByteVector ();
|
||||
|
||||
// Add Extension Introducer (0x21) and Comment Label (0xFE)
|
||||
comment_data.Add (new byte[] { 0x21, 0xFE });
|
||||
|
||||
// Add data of comment in sub-blocks of max length 256.
|
||||
ByteVector comment_bytes = new ByteVector (comment);
|
||||
byte block_max = 255;
|
||||
for (int start = 0; start < comment_bytes.Count; start += block_max) {
|
||||
byte block_length = (byte)Math.Min (comment_bytes.Count - start, block_max);
|
||||
|
||||
comment_data.Add (block_length);
|
||||
comment_data.Add (comment_bytes.Mid (start, block_length));
|
||||
}
|
||||
comment_data.Add (new byte[] { 0x00 });
|
||||
|
||||
return comment_data;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to extract the media properties of the main
|
||||
/// photo.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="Properties" /> object with a best effort guess
|
||||
/// at the right values. When no guess at all can be made,
|
||||
/// <see langword="null" /> is returned.
|
||||
/// </returns>
|
||||
Properties ExtractProperties ()
|
||||
{
|
||||
if (width > 0 && height > 0)
|
||||
return new Properties (TimeSpan.Zero, new Codec (width, height));
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ccc0f5856d987773a8ff481376f547e0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,102 @@
|
||||
//
|
||||
// GifCommentTag.cs:
|
||||
//
|
||||
// Author:
|
||||
// Ruben Vermeersch (ruben@savanne.be)
|
||||
// Mike Gemuende (mike@gemuende.de)
|
||||
//
|
||||
// Copyright (C) 2009 Ruben Vermeersch
|
||||
// Copyright (C) 2010 Mike Gemuende
|
||||
//
|
||||
// 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 TagLib.Image;
|
||||
|
||||
namespace TagLib.Gif
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains the Gif comment.
|
||||
/// </summary>
|
||||
public class GifCommentTag : ImageTag
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="value">
|
||||
/// The value of the comment.
|
||||
/// </param>
|
||||
public GifCommentTag (string value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor. Creates a new empty comment.
|
||||
/// </summary>
|
||||
public GifCommentTag ()
|
||||
{
|
||||
Value = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// The value of the comment represented by the current instance.
|
||||
/// </summary>
|
||||
public string Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the comment for the image described
|
||||
/// by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> containing the comment of the
|
||||
/// current instace.
|
||||
/// </value>
|
||||
public override string Comment {
|
||||
get { return Value; }
|
||||
set { Value = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tag types contained in the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Always <see cref="TagTypes.GifComment" />.
|
||||
/// </value>
|
||||
public override TagTypes TagTypes {
|
||||
get { return TagTypes.GifComment; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the values stored in the current instance.
|
||||
/// </summary>
|
||||
public override void Clear ()
|
||||
{
|
||||
Value = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 90b0deeab3e1f5525bfc3333391201f9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,245 @@
|
||||
//
|
||||
// ICodec.cs: Provides ICodec, IAudioCodec, and IVideoCodec interfaces.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2007 Brian Nickel
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the types of media represented by a <see cref="ICodec"
|
||||
/// /> or <see cref="Properties" /> object.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// These values can be bitwise combined to represent multiple media
|
||||
/// types.
|
||||
/// </remarks>
|
||||
[Flags]
|
||||
public enum MediaTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// No media is present.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Audio is present.
|
||||
/// </summary>
|
||||
Audio = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Video is present.
|
||||
/// </summary>
|
||||
Video = 2,
|
||||
|
||||
/// <summary>
|
||||
/// A Photo is present.
|
||||
/// </summary>
|
||||
Photo = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Text is present.
|
||||
/// </summary>
|
||||
Text = 8
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This interface provides basic information, common to all media
|
||||
/// codecs.
|
||||
/// </summary>
|
||||
public interface ICodec
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the duration of the media represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TimeSpan" /> containing the duration of the
|
||||
/// media represented by the current instance.
|
||||
/// </value>
|
||||
TimeSpan Duration { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the types of media represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A bitwise combined <see cref="MediaTypes" /> containing
|
||||
/// the types of media represented by the current instance.
|
||||
/// </value>
|
||||
MediaTypes MediaTypes { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a text description of the media represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing a description
|
||||
/// of the media represented by the current instance.
|
||||
/// </value>
|
||||
string Description { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This interface inherits <see cref="ICodec" /> to provide
|
||||
/// information about an audio codec.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>When dealing with a <see cref="ICodec" />, if <see
|
||||
/// cref="ICodec.MediaTypes" /> contains <see cref="MediaTypes.Audio"
|
||||
/// />, it is safe to assume that the object also inherits <see
|
||||
/// cref="IAudioCodec" /> and can be recast without issue.</para>
|
||||
/// </remarks>
|
||||
public interface IAudioCodec : ICodec
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the bitrate of the audio represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing a bitrate of the
|
||||
/// audio represented by the current instance.
|
||||
/// </value>
|
||||
int AudioBitrate { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sample rate of the audio represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the sample rate of
|
||||
/// the audio represented by the current instance.
|
||||
/// </value>
|
||||
int AudioSampleRate { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of channels in the audio represented by
|
||||
/// the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the number of
|
||||
/// channels in the audio represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
int AudioChannels { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This interface provides information specific
|
||||
/// to lossless audio codecs.
|
||||
/// </summary>
|
||||
public interface ILosslessAudioCodec
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the number of bits per sample in the audio
|
||||
/// represented by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the number of bits
|
||||
/// per sample in the audio represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
int BitsPerSample { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This interface inherits <see cref="ICodec" /> to provide
|
||||
/// information about a video codec.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>When dealing with a <see cref="ICodec" />, if <see
|
||||
/// cref="ICodec.MediaTypes" /> contains <see cref="MediaTypes.Video"
|
||||
/// />, it is safe to assume that the object also inherits <see
|
||||
/// cref="IVideoCodec" /> and can be recast without issue.</para>
|
||||
/// </remarks>
|
||||
public interface IVideoCodec : ICodec
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the width of the video represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the width of the
|
||||
/// video represented by the current instance.
|
||||
/// </value>
|
||||
int VideoWidth { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the height of the video represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the height of the
|
||||
/// video represented by the current instance.
|
||||
/// </value>
|
||||
int VideoHeight { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This interface inherits <see cref="ICodec" /> to provide
|
||||
/// information about a photo.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>When dealing with a <see cref="ICodec" />, if <see
|
||||
/// cref="ICodec.MediaTypes" /> contains <see cref="MediaTypes.Photo"
|
||||
/// />, it is safe to assume that the object also inherits <see
|
||||
/// cref="IPhotoCodec" /> and can be recast without issue.</para>
|
||||
/// </remarks>
|
||||
public interface IPhotoCodec : ICodec
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the width of the photo represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the width of the
|
||||
/// photo represented by the current instance.
|
||||
/// </value>
|
||||
int PhotoWidth { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the height of the photo represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the height of the
|
||||
/// photo represented by the current instance.
|
||||
/// </value>
|
||||
int PhotoHeight { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the (format specific) quality indicator of the photo
|
||||
/// represented by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value indicating the quality. A value
|
||||
/// 0 means that there was no quality indicator for the format
|
||||
/// or the file.
|
||||
/// </value>
|
||||
int PhotoQuality { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b34c3695ae7a0148abc91f92eec33f73
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loaded 100 of 2025 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user