Initial commit

This commit is contained in:
Thastertyn committed 2024-06-07 00:47:07 +02:00
commit 262601edb8
2025 files changed
+218754

No files matched your search

+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 308bd862125e5ae9c95724055c402e8c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+415
View File
@@ -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:
+100
View File
@@ -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
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8284bad068f4283f29df4c52751a79cc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+272
View File
@@ -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 &amp; ~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
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5ea5a2b9978c53a708489187d4f05f90
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4e181c0c58fe3641d805ee0aabca0c10
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+486
View File
@@ -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
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7c3c2cdcd3206d6c2984e6419139fc01
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+248
View File
@@ -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:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 81f4ff937a733e84599dd980bba85dcf
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+275
View File
@@ -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 &amp; ~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
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6bd919f3cebce9e6b94eb2887772bf8d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+392
View File
@@ -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
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3fd643b62da0d63f89725b4266c74752
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+500
View File
@@ -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
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ec6d7edea3a67467d8e074bff4ac65d7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+359
View File
@@ -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
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e937bf4e5ed85bb70b1660583e8eb5dc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -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:
+436
View File
@@ -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
}
}
+11
View File
@@ -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:
+110
View File
@@ -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");
}
}
+11
View File
@@ -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:
+265
View File
@@ -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:
+244
View File
@@ -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
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: de6647e25247fb396826cf683998e204
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+125
View File
@@ -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
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d734ffb9edf169961b4e181c03effffd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+99
View File
@@ -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:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3f2cec2ef40ccecd7ba6d1a7e546abf8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+262
View File
@@ -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
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 006f7fb1983a3a1a89f28703d552cbc6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+320
View File
@@ -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
}
}
+11
View File
@@ -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
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fd4901c34711c7eaba954926fa92969f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+273
View File
@@ -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
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0fcfda10f765f9bf0b754fb38b66878e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+167
View File
@@ -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 &lt;System.dll>
/// #using &lt;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:
+137
View File
@@ -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;
}
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 43d149150f84518598c6d2c5500d9244
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 90815a5b58495074885ff707abaacda7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+411
View File
@@ -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
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8b09427e5619eec8580e4b303b312ac9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+292
View File
@@ -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
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 52c28e7dd422cc99f9c2e90fa020cc88
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+150
View File
@@ -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; }
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 23e93de1fe905f6eabb3e07e3c9aa3f0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8148a9d853e5e63c9887d255e17b38f8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+191
View File
@@ -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
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2b85066ddbb2e476dacfb9957cb823bc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+175
View File
@@ -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:
+665
View File
@@ -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 &amp; ~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 ();
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2398030dd33fc28e38d41d1975d6aa92
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+268
View File
@@ -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
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 948078d7fd9adb2fe995d19ef3157a39
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+234
View File
@@ -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:
+402
View File
@@ -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;
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 43e436b8e6a5ac91eb7992b11dd1e2c8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e80fdad1f70cff659bf3a310ada660df
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+60
View File
@@ -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) { }
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 47cdd5f88d9090727bd3e17f4f9c0893
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+782
View File
@@ -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
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ccc0f5856d987773a8ff481376f547e0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+102
View File
@@ -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:
+245
View File
@@ -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; }
}
}
+11
View File
@@ -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