Initial commit
This commit is contained in:
commit
262601edb8
2025 files changed
+218754
No files matched your search
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 32fed777e7f6daacfa1a4e532b30c12e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BangerTypes
|
||||
{
|
||||
public class Note
|
||||
{
|
||||
public float t; // Time
|
||||
public string a; // Arrow type
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a284c53b4540b5598dc592caa8fe84d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BangerTypes
|
||||
{
|
||||
public class Rhys
|
||||
{
|
||||
public Note[] notes;
|
||||
public string artist;
|
||||
public string title;
|
||||
public int track_time;
|
||||
public string audio; // Base64 encoded
|
||||
public string cover_art; // Base64 encoded
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 201ec27a96f795d6f94dabd5b8d453d0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BangerTypes
|
||||
{
|
||||
public class Song
|
||||
{
|
||||
public Note[] Notes { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Artist { get; set; }
|
||||
public string Album { get; set; }
|
||||
public string Duration { get; set; }
|
||||
public TimeSpan DurationSpan { get; set; }
|
||||
public AudioClip Clip { get; set; }
|
||||
public Sprite CoverArt { get; set; }
|
||||
|
||||
public string SongPath { get; set; }
|
||||
|
||||
public Color32 AverageColor { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f157c1fad538aaaa38f7d178e7b359a9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,13 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class CoroutineStarter : MonoBehaviour
|
||||
{
|
||||
private static CoroutineStarter instance = new();
|
||||
|
||||
public static void StartRoutine(IEnumerator routine)
|
||||
{
|
||||
instance.StartCoroutine(routine);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 448219931c01415039b70f8af79a05bd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2c69f559f3da0b59d97db4723910f9e5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public enum ButtonType
|
||||
{
|
||||
UP,
|
||||
DOWN,
|
||||
LEFT,
|
||||
RIGHT
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b6890e1a271ae58dc98e3e3e26f2d442
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ea9f7e8f0b3a66e84858a5b4a3c904f5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class AudioManager : MonoBehaviour
|
||||
{
|
||||
[HideInInspector]
|
||||
public AudioClip Clip { get; set; }
|
||||
public AudioSource source;
|
||||
|
||||
[Range(0f, 1f)]
|
||||
public float volume;
|
||||
|
||||
[Range(0f, 1f)]
|
||||
public float pitch;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
source = GetComponent<AudioSource>();
|
||||
source.clip = Clip;
|
||||
}
|
||||
|
||||
public void UpdateClip(AudioClip clip)
|
||||
{
|
||||
source.clip = clip;
|
||||
}
|
||||
|
||||
public void Play()
|
||||
{
|
||||
source.Play();
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
source.Stop();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 61669be1370e61be299d7421ad39b205
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
public class BassEffect
|
||||
{
|
||||
public AudioSource source;
|
||||
|
||||
public int range = 128;
|
||||
public int sensitivity = 9;
|
||||
public float bassDesensitivity = 0.4f;
|
||||
|
||||
public float[] SpectrumData { get; set; }
|
||||
|
||||
public float bassThreshhold = 0.1f;
|
||||
|
||||
public Queue<float> bassHistory = new(5);
|
||||
|
||||
List<float> bassData = new();
|
||||
|
||||
|
||||
// No sensitivity and bass reduction
|
||||
public float[] UnprocessedSpectrumData { get; set; }
|
||||
|
||||
// Raw data from GetSpectrumData
|
||||
private float[] RawSpectrumData;
|
||||
|
||||
public BassEffect(AudioSource source)
|
||||
{
|
||||
this.source = source;
|
||||
|
||||
SpectrumData = new float[range];
|
||||
RawSpectrumData = new float[4 * range];
|
||||
}
|
||||
|
||||
public float[] UpdateSpectrumData()
|
||||
{
|
||||
source.GetSpectrumData(RawSpectrumData, 0, FFTWindow.Blackman);
|
||||
|
||||
float[] res = new float[range];
|
||||
|
||||
// Smooth the spectrum data using a moving average
|
||||
for (int i = 0; i < range; i++)
|
||||
{
|
||||
float result = Mathf.Lerp(SpectrumData[i], RawSpectrumData[i], 0.1f);
|
||||
SpectrumData[i] = result;
|
||||
|
||||
if (i < (range / 14))
|
||||
{
|
||||
result *= bassDesensitivity;
|
||||
}
|
||||
|
||||
res[i] = sensitivity * result;
|
||||
}
|
||||
IsBassOn();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public float[] GetBass()
|
||||
{
|
||||
return SpectrumData.Take(3).ToArray();
|
||||
}
|
||||
|
||||
public float GetBassStrength()
|
||||
{
|
||||
float[] bass = GetBass();
|
||||
|
||||
float sum = bass.Sum() * 5f;
|
||||
|
||||
return (float) Math.Pow(sum, 2) / 10f;
|
||||
}
|
||||
|
||||
public bool IsBassOn()
|
||||
{
|
||||
float[] bass = GetBass();
|
||||
|
||||
float level = bass.Sum() / bass.Length;
|
||||
|
||||
bassData.Add(level);
|
||||
|
||||
return level > bassThreshhold;
|
||||
}
|
||||
|
||||
public void WriteData()
|
||||
{
|
||||
string res = "";
|
||||
|
||||
foreach (var bass in bassData)
|
||||
{
|
||||
res += bass + ", ";
|
||||
}
|
||||
|
||||
System.IO.File.WriteAllText("/home/thastertyn/bass-data.txt", res);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 439cd1a6fdb271b12bbba95d1273c881
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
using UITypes;
|
||||
|
||||
public class Game : MonoBehaviour
|
||||
{
|
||||
const float DELAY = 0.005f; // 200 TPS
|
||||
|
||||
public AudioManager manager;
|
||||
|
||||
private MainMenu menu;
|
||||
private BassEffect effect;
|
||||
|
||||
string totalDuration;
|
||||
bool repeatRoutine = true;
|
||||
|
||||
|
||||
void Awake()
|
||||
{
|
||||
menu = GetComponent<MainMenu>();
|
||||
|
||||
effect = new(manager.source);
|
||||
}
|
||||
|
||||
public void GameUpdate()
|
||||
{
|
||||
float[] specData = effect.UpdateSpectrumData();
|
||||
float bassStrength = effect.GetBassStrength();
|
||||
|
||||
menu.GameElem.UpdateVisualizers(specData, bassStrength);
|
||||
|
||||
UpdateTimestamp();
|
||||
}
|
||||
|
||||
IEnumerator GameLoop()
|
||||
{
|
||||
while (repeatRoutine)
|
||||
{
|
||||
GameUpdate();
|
||||
yield return new WaitForSeconds(DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadSong(SongEntry song)
|
||||
{
|
||||
totalDuration = song.Song.Duration;
|
||||
|
||||
manager.source.clip = song.Song.Clip;
|
||||
|
||||
menu.GameElem.SetColumnColor(song.Song.AverageColor);
|
||||
}
|
||||
|
||||
void UpdateTimestamp()
|
||||
{
|
||||
int totalSeconds = (int)manager.source.time;
|
||||
int h = totalSeconds / 3600;
|
||||
int m = (totalSeconds % 3600) / 60;
|
||||
int s = totalSeconds % 60;
|
||||
|
||||
string result = $"{h:D2}:{m:D2}:{s:D2} / {totalDuration}";
|
||||
menu.GameElem.UpdateSongTime(result);
|
||||
}
|
||||
|
||||
public void EscapeClicked()
|
||||
{
|
||||
repeatRoutine = false;
|
||||
manager.Stop();
|
||||
menu.Escape();
|
||||
}
|
||||
|
||||
public void Play()
|
||||
{
|
||||
manager.Play();
|
||||
repeatRoutine = true;
|
||||
StartCoroutine(GameLoop());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b1cb1154a484d1bf18dda4f1c4f16322
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
[System.Serializable]
|
||||
public class Sound : MonoBehaviour
|
||||
{
|
||||
public AudioClip clip;
|
||||
|
||||
[Range(0f, 1f)]
|
||||
public float volume;
|
||||
|
||||
[Range(0f, 1f)]
|
||||
public float pitch;
|
||||
|
||||
public string soundName;
|
||||
|
||||
[HideInInspector]
|
||||
public AudioSource source;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 33f413aa8eabb985da07d956df7f198e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7db8be7cfa459fa15990f6ed6fcb6a92
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,110 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using UnityEngine;
|
||||
using TagLib;
|
||||
using System;
|
||||
using BangerTypes;
|
||||
using NAudio.Wave;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
|
||||
namespace MenuAndSongs
|
||||
{
|
||||
public class FindSongs
|
||||
{
|
||||
public static List<string> Find(string songPath)
|
||||
{
|
||||
if (!Directory.Exists(songPath))
|
||||
Directory.CreateDirectory(songPath);
|
||||
|
||||
List<string> ls = Directory
|
||||
.GetFiles(songPath)
|
||||
.Where(file => Regex.IsMatch(file, ".*\\.mp3"))
|
||||
.ToList();
|
||||
|
||||
return ls;
|
||||
}
|
||||
|
||||
public static Song ParseRHYS(string rhysPath, Sprite defaultImage)
|
||||
{
|
||||
string jsonContent = System.IO.File.ReadAllText(rhysPath);
|
||||
Rhys rhys = JsonUtility.FromJson<Rhys>(jsonContent);
|
||||
|
||||
string title = "<b>" + (rhys.title ?? "Title not found") + "</b>";
|
||||
string artist = String.IsNullOrEmpty(rhys.artist) ? "Artist not found" : "By: <b>" + rhys.artist + "</b>";
|
||||
string album = "Album information not available";
|
||||
|
||||
TimeSpan duration = TimeSpan.FromSeconds(rhys.track_time);
|
||||
string formattedTimeSpan = string.Format("{0:D2}:{1:D2}:{2:D2}",
|
||||
(int)duration.TotalHours,
|
||||
duration.Minutes,
|
||||
duration.Seconds);
|
||||
|
||||
Sprite coverImage;
|
||||
if (!string.IsNullOrEmpty(rhys.cover_art))
|
||||
{
|
||||
byte[] imageBytes = Convert.FromBase64String(rhys.cover_art);
|
||||
Texture2D texture = new Texture2D(2, 2);
|
||||
texture.LoadImage(imageBytes);
|
||||
coverImage = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
|
||||
}
|
||||
else
|
||||
{
|
||||
coverImage = defaultImage;
|
||||
}
|
||||
|
||||
var notes = rhys.notes;
|
||||
Debug.Log("NOTES: ");
|
||||
Debug.Log(notes);
|
||||
|
||||
return new()
|
||||
{
|
||||
Title = title,
|
||||
Artist = artist,
|
||||
Album = album,
|
||||
DurationSpan = duration,
|
||||
Duration = formattedTimeSpan,
|
||||
CoverArt = coverImage,
|
||||
Clip = LoadAudioFromBase64(rhys.audio)
|
||||
};
|
||||
}
|
||||
|
||||
private static AudioClip LoadAudioFromBase64(string base64String)
|
||||
{
|
||||
// Decode Base64 String to byte array
|
||||
byte[] mp3Bytes = Convert.FromBase64String(base64String);
|
||||
|
||||
// Create a temporary file path
|
||||
string tempFilePath = Path.Combine(Application.persistentDataPath, "tempMp3File.mp3");
|
||||
System.IO.File.WriteAllBytes(tempFilePath, mp3Bytes);
|
||||
|
||||
// Load the AudioClip synchronously
|
||||
AudioClip clip = LoadAudioSync(tempFilePath);
|
||||
|
||||
// Optionally delete the temporary file if no longer needed
|
||||
System.IO.File.Delete(tempFilePath);
|
||||
|
||||
return clip;
|
||||
}
|
||||
|
||||
private static AudioClip LoadAudioSync(string filePath)
|
||||
{
|
||||
UnityWebRequest uwr = UnityWebRequestMultimedia.GetAudioClip("file://" + filePath, AudioType.MPEG);
|
||||
var operation = uwr.SendWebRequest();
|
||||
while (!operation.isDone)
|
||||
; // Busy wait - not recommended
|
||||
|
||||
if (uwr.result == UnityWebRequest.Result.Success)
|
||||
{
|
||||
return DownloadHandlerAudioClip.GetContent(uwr);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Error loading audio clip: " + uwr.error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 653a02710366ea592b0b57a41d8d165a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,12 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MenuAndSongs
|
||||
{
|
||||
[CreateAssetMenu(fileName = "SongData", menuName = "Custom/Song Data")]
|
||||
public class SongData : ScriptableObject
|
||||
{
|
||||
public static string songPath;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 87a87ffb34f411f57934067574b91792
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 82dacfd5a3919507382bfb33213d0ae9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 308bd862125e5ae9c95724055c402e8c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,415 @@
|
||||
//
|
||||
// AudioHeader.cs: Provides information about an ADTS AAC audio stream.
|
||||
//
|
||||
// Copyright (C) 2009 Patrick Dehne
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Aac
|
||||
{
|
||||
/// <summary>
|
||||
/// This structure implements <see cref="IAudioCodec" /> and provides
|
||||
/// information about an ADTS AAC audio stream.
|
||||
/// </summary>
|
||||
public class AudioHeader : IAudioCodec
|
||||
{
|
||||
#region Private Static Value Arrays
|
||||
|
||||
/// <summary>
|
||||
/// Contains a sample rate table for ADTS AAC audio.
|
||||
/// </summary>
|
||||
static readonly int[] sample_rates = new int[13] {
|
||||
96000, 88200, 64000, 48000, 44100, 32000,
|
||||
24000, 22050, 16000, 12000, 11025, 8000, 7350
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Contains a channel table for ADTS AAC audio.
|
||||
/// </summary>
|
||||
static readonly int[] channels = new int[8] {
|
||||
0, 1, 2, 3, 4, 5, 6, 8
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Private Properties
|
||||
|
||||
/// <summary>
|
||||
/// Contains the audio stream length.
|
||||
/// </summary>
|
||||
long stream_length;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the audio stream duration.
|
||||
/// </summary>
|
||||
TimeSpan duration;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of channels in the audio
|
||||
/// </summary>
|
||||
readonly int audiochannels;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the bitrate of the audio stream
|
||||
/// </summary>
|
||||
readonly int audiobitrate;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the samplerate of the audio stream
|
||||
/// </summary>
|
||||
readonly int audiosamplerate;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Fields
|
||||
|
||||
/// <summary>
|
||||
/// An empty and unset header.
|
||||
/// </summary>
|
||||
public static readonly AudioHeader Unknown = new AudioHeader ();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new empty instance of <see
|
||||
/// cref="AudioHeader" />
|
||||
/// </summary>
|
||||
AudioHeader ()
|
||||
{
|
||||
stream_length = 0;
|
||||
duration = TimeSpan.Zero;
|
||||
audiochannels = 0;
|
||||
audiobitrate = 0;
|
||||
audiosamplerate = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="AudioHeader" /> by populating it with specified
|
||||
/// values.
|
||||
/// </summary>
|
||||
/// <param name="channels">
|
||||
/// A <see cref="int" /> value indicating the number
|
||||
/// of channels in the audio stream
|
||||
/// </param>
|
||||
/// <param name="bitrate">
|
||||
/// A <see cref="int" /> value indicating the bitrate
|
||||
/// of the audio stream
|
||||
/// </param>
|
||||
/// <param name="samplerate">
|
||||
/// A <see cref="int" /> value indicating the samplerate
|
||||
/// of the audio stream
|
||||
/// </param>
|
||||
/// <param name="numberofsamples">
|
||||
/// A <see cref="int" /> value indicating the number
|
||||
/// of samples in the audio stream
|
||||
/// </param>
|
||||
/// <param name="numberofframes">
|
||||
/// A <see cref="int" /> value indicating the number
|
||||
/// of frames in the audio stream
|
||||
/// </param>
|
||||
AudioHeader (int channels, int bitrate, int samplerate, int numberofsamples, int numberofframes)
|
||||
{
|
||||
duration = TimeSpan.Zero;
|
||||
stream_length = 0;
|
||||
audiochannels = channels;
|
||||
audiobitrate = bitrate;
|
||||
audiosamplerate = samplerate;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets a text description of the media represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing a description
|
||||
/// of the media represented by the current instance.
|
||||
/// </value>
|
||||
public string Description {
|
||||
get {
|
||||
return "ADTS AAC";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the types of media represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Always <see cref="MediaTypes.Audio" />.
|
||||
/// </value>
|
||||
public MediaTypes MediaTypes {
|
||||
get { return MediaTypes.Audio; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the duration of the media represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TimeSpan" /> containing the duration of the
|
||||
/// media represented by the current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// If <see cref="SetStreamLength" /> has not been called, this
|
||||
/// value will not be correct.
|
||||
/// </remarks>
|
||||
public TimeSpan Duration {
|
||||
get {
|
||||
return duration;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bitrate of the audio represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing a bitrate of the
|
||||
/// audio represented by the current instance.
|
||||
/// </value>
|
||||
public int AudioBitrate {
|
||||
get {
|
||||
return audiobitrate;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sample rate of the audio represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the sample rate of
|
||||
/// the audio represented by the current instance.
|
||||
/// </value>
|
||||
public int AudioSampleRate {
|
||||
get {
|
||||
return audiosamplerate;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of channels in the audio represented by
|
||||
/// the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the number of
|
||||
/// channels in the audio represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public int AudioChannels {
|
||||
get { return audiochannels; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Sets the length of the audio stream represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <param name="streamLength">
|
||||
/// A <see cref="long" /> value specifying the length in
|
||||
/// bytes of the audio stream represented by the current
|
||||
/// instance.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// The this value has been set, <see cref="Duration" /> will
|
||||
/// return an incorrect value.
|
||||
/// </remarks>
|
||||
public void SetStreamLength (long streamLength)
|
||||
{
|
||||
stream_length = streamLength;
|
||||
duration = TimeSpan.FromSeconds (stream_length * 8.0 / audiobitrate);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Static Methods
|
||||
|
||||
/// <summary>
|
||||
/// Searches for an audio header in a <see cref="TagLib.File"
|
||||
/// /> starting at a specified position and searching through
|
||||
/// a specified number of bytes.
|
||||
/// </summary>
|
||||
/// <param name="header">
|
||||
/// A <see cref="AudioHeader" /> object in which the found
|
||||
/// header will be stored.
|
||||
/// </param>
|
||||
/// <param name="file">
|
||||
/// A <see cref="TagLib.File" /> object to search.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specifying the seek position
|
||||
/// in <paramref name="file" /> at which to start searching.
|
||||
/// </param>
|
||||
/// <param name="length">
|
||||
/// A <see cref="int" /> value specifying the maximum number
|
||||
/// of bytes to search before aborting.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="bool" /> value indicating whether or not a
|
||||
/// header was found.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public static bool Find (out AudioHeader header, TagLib.File file, long position, int length)
|
||||
{
|
||||
if (file == null)
|
||||
throw new ArgumentNullException (nameof (file));
|
||||
|
||||
long end = position + length;
|
||||
header = Unknown;
|
||||
|
||||
file.Seek (position);
|
||||
|
||||
ByteVector buffer = file.ReadBlock (3);
|
||||
|
||||
if (buffer.Count < 3)
|
||||
return false;
|
||||
|
||||
do {
|
||||
file.Seek (position + 3);
|
||||
buffer = buffer.Mid (buffer.Count - 3);
|
||||
buffer.Add (file.ReadBlock (
|
||||
(int)TagLib.File.BufferSize));
|
||||
|
||||
for (int i = 0; i < buffer.Count - 3 &&
|
||||
(length < 0 || position + i < end); i++)
|
||||
if (buffer[i] == 0xFF
|
||||
&& buffer[i + 1] >= 0xF0) // 0xFFF
|
||||
try {
|
||||
BitStream bits = new BitStream (buffer.Mid (i, 7).Data);
|
||||
|
||||
// 12 bits sync header
|
||||
bits.ReadInt32 (12);
|
||||
|
||||
// 1 bit mpeg 2/4
|
||||
bits.ReadInt32 (1);
|
||||
|
||||
// 2 bits layer
|
||||
bits.ReadInt32 (2);
|
||||
|
||||
// 1 bit protection absent
|
||||
bits.ReadInt32 (1);
|
||||
|
||||
// 2 bits profile object type
|
||||
bits.ReadInt32 (2);
|
||||
|
||||
// 4 bits sampling frequency index
|
||||
int samplerateindex = bits.ReadInt32 (4);
|
||||
if (samplerateindex >= sample_rates.Length)
|
||||
return false;
|
||||
long samplerate = sample_rates[samplerateindex];
|
||||
|
||||
// 1 bit private bit
|
||||
bits.ReadInt32 (1);
|
||||
|
||||
// 3 bits channel configuration
|
||||
int channelconfigindex = bits.ReadInt32 (3);
|
||||
if (channelconfigindex >= channels.Length)
|
||||
return false;
|
||||
|
||||
// 4 copyright bits
|
||||
bits.ReadInt32 (4);
|
||||
|
||||
// 13 bits frame length
|
||||
long framelength = bits.ReadInt32 (13); // double check framelength
|
||||
if (framelength < 7)
|
||||
return false;
|
||||
|
||||
// 11 bits buffer fullness
|
||||
bits.ReadInt32 (11);
|
||||
|
||||
// 2 bits number of raw data blocks in frame
|
||||
int numberofframes = bits.ReadInt32 (2) + 1;
|
||||
|
||||
long numberofsamples = numberofframes * 1024;
|
||||
long bitrate = framelength * 8 * samplerate / numberofsamples;
|
||||
|
||||
header = new AudioHeader (channels[channelconfigindex],
|
||||
(int)bitrate,
|
||||
(int)samplerate,
|
||||
(int)numberofsamples,
|
||||
numberofframes);
|
||||
|
||||
return true;
|
||||
} catch (CorruptFileException) {
|
||||
}
|
||||
|
||||
position += TagLib.File.BufferSize;
|
||||
} while (buffer.Count > 3 && (length < 0 || position < end));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches for an audio header in a <see cref="TagLib.File"
|
||||
/// /> starting at a specified position and searching to the
|
||||
/// end of the file.
|
||||
/// </summary>
|
||||
/// <param name="header">
|
||||
/// A <see cref="AudioHeader" /> object in which the found
|
||||
/// header will be stored.
|
||||
/// </param>
|
||||
/// <param name="file">
|
||||
/// A <see cref="TagLib.File" /> object to search.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specifying the seek position
|
||||
/// in <paramref name="file" /> at which to start searching.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="bool" /> value indicating whether or not a
|
||||
/// header was found.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Searching to the end of the file can be very, very slow
|
||||
/// especially for corrupt or non-MPEG files. It is
|
||||
/// recommended to use <see
|
||||
/// cref="M:AudioHeader.Find(AudioHeader,TagLib.File,long,int)" />
|
||||
/// instead.
|
||||
/// </remarks>
|
||||
public static bool Find (out AudioHeader header, TagLib.File file, long position)
|
||||
{
|
||||
return Find (out header, file, position, -1);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a70f4e38ac189d2389cf4717f5a1869a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,100 @@
|
||||
//
|
||||
// BitStream.cs: Helper to read bits from a byte array.
|
||||
//
|
||||
// Copyright (C) 2009 Patrick Dehne
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace TagLib.Aac
|
||||
{
|
||||
/// <summary>
|
||||
/// This class is used to help reading arbitary number of bits from
|
||||
/// a fixed array of bytes
|
||||
/// </summary>
|
||||
public class BitStream
|
||||
{
|
||||
readonly BitArray bits;
|
||||
int bitindex;
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Construct a new <see cref="BitStream"/>.
|
||||
/// </summary>
|
||||
/// <param name="buffer">
|
||||
/// A <see cref="T:System.Byte[]"/>, must be 7 bytes long.
|
||||
/// </param>
|
||||
public BitStream (byte[] buffer)
|
||||
{
|
||||
Debug.Assert (buffer.Length == 7, "buffer.Length == 7", "buffer size invalid");
|
||||
|
||||
if (buffer.Length != 7)
|
||||
throw new ArgumentException ("Buffer size must be 7 bytes");
|
||||
|
||||
// Reverse bits
|
||||
bits = new BitArray (buffer.Length * 8);
|
||||
for (int i = 0; i < buffer.Length; i++) {
|
||||
for (int y = 0; y < 8; y++) {
|
||||
bits[i * 8 + y] = ((buffer[i] & (1 << (7 - y))) > 0);
|
||||
}
|
||||
}
|
||||
|
||||
bitindex = 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Reads an Int32 from the bitstream
|
||||
/// </summary>
|
||||
/// <param name="numberOfBits">
|
||||
/// A <see cref="int" /> value containing the number
|
||||
/// of bits to read from the bitstream
|
||||
/// </param>
|
||||
public int ReadInt32 (int numberOfBits)
|
||||
{
|
||||
Debug.Assert (numberOfBits > 0, "numberOfBits < 1");
|
||||
Debug.Assert (numberOfBits <= 32, "numberOfBits <= 32");
|
||||
|
||||
if (numberOfBits <= 0)
|
||||
throw new ArgumentException ("Number of bits to read must be >= 1");
|
||||
|
||||
if (numberOfBits > 32)
|
||||
throw new ArgumentException ("Number of bits to read must be <= 32");
|
||||
|
||||
int value = 0;
|
||||
int start = bitindex + numberOfBits - 1;
|
||||
for (int i = 0; i < numberOfBits; i++) {
|
||||
value += bits[start] ? (1 << i) : 0;
|
||||
bitindex++;
|
||||
start--;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8284bad068f4283f29df4c52751a79cc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,272 @@
|
||||
//
|
||||
// File.cs: Provides tagging and properties support for ADTS AAC files
|
||||
//
|
||||
// Here is the ADTS Header description used for implementation:
|
||||
// http://www.hydrogenaudio.org/forums/lofiversion/index.php/t21617.html
|
||||
//
|
||||
// Copyright (C) 2009 Patrick Dehne
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Aac
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="TagLib.NonContainer.File" /> to
|
||||
/// provide tagging and properties support for ADTS AAC audio files.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A <see cref="TagLib.Id3v1.Tag" /> and <see
|
||||
/// cref="TagLib.Id3v2.Tag" /> will be added automatically to any
|
||||
/// file that doesn't contain one. This change does not effect the
|
||||
/// file until it is saved and can be reversed using the following
|
||||
/// method:
|
||||
/// <code>file.RemoveTags (file.TagTypes & ~file.TagTypesOnDisk);</code>
|
||||
/// </remarks>
|
||||
[SupportedMimeType ("taglib/aac", "aac")]
|
||||
[SupportedMimeType ("audio/aac")]
|
||||
public class File : TagLib.NonContainer.File
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the first audio header.
|
||||
/// </summary>
|
||||
AudioHeader first_header;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local
|
||||
/// file system and specified read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path, ReadStyle propertiesStyle)
|
||||
: base (path, propertiesStyle)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local
|
||||
/// file system with an average read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path) : base (path)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction and
|
||||
/// specified read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction, ReadStyle propertiesStyle)
|
||||
: base (abstraction, propertiesStyle)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction with
|
||||
/// an average read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction)
|
||||
: base (abstraction)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a tag of a specified type from the current instance,
|
||||
/// optionally creating a new tag if possible.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="TagLib.TagTypes" /> value indicating the
|
||||
/// type of tag to read.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> value specifying whether or not to
|
||||
/// try and create the tag if one is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="Tag" /> object containing the tag that was
|
||||
/// found in or added to the current instance. If no
|
||||
/// matching tag was found and none was created, <see
|
||||
/// langword="null" /> is returned.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// If a <see cref="TagLib.Id3v2.Tag" /> is added to the
|
||||
/// current instance, it will be placed at the start of the
|
||||
/// file. On the other hand, <see cref="TagLib.Id3v1.Tag" />
|
||||
/// <see cref="TagLib.Ape.Tag" /> will be added to the end of
|
||||
/// the file. All other tag types will be ignored.
|
||||
/// </remarks>
|
||||
public override Tag GetTag (TagTypes type, bool create)
|
||||
{
|
||||
Tag t = (Tag as TagLib.NonContainer.Tag).GetTag (type);
|
||||
|
||||
if (t != null || !create)
|
||||
return t;
|
||||
|
||||
switch (type) {
|
||||
case TagTypes.Id3v1:
|
||||
return EndTag.AddTag (type, Tag);
|
||||
|
||||
case TagTypes.Id3v2:
|
||||
return StartTag.AddTag (type, Tag);
|
||||
|
||||
case TagTypes.Ape:
|
||||
return EndTag.AddTag (type, Tag);
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Reads format specific information at the start of the
|
||||
/// file.
|
||||
/// </summary>
|
||||
/// <param name="start">
|
||||
/// A <see cref="long" /> value containing the seek position
|
||||
/// at which the tags end and the media data begins.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// This method only searches for an audio header in the
|
||||
/// first 16384 bytes of code to avoid searching forever in
|
||||
/// corrupt files.
|
||||
/// </remarks>
|
||||
protected override void ReadStart (long start, ReadStyle propertiesStyle)
|
||||
{
|
||||
// Only check the first 16 bytes so we're not stuck
|
||||
// reading a bad file forever.
|
||||
if ((propertiesStyle & ReadStyle.Average) != 0 &&
|
||||
!AudioHeader.Find (out first_header, this, start, 0x4000))
|
||||
throw new CorruptFileException ("ADTS audio header not found.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads format specific information at the end of the
|
||||
/// file.
|
||||
/// </summary>
|
||||
/// <param name="end">
|
||||
/// A <see cref="long" /> value containing the seek position
|
||||
/// at which the media data ends and the tags begin.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
protected override void ReadEnd (long end, ReadStyle propertiesStyle)
|
||||
{
|
||||
// Make sure we have ID3v1 and ID3v2 tags.
|
||||
GetTag (TagTypes.Id3v1, true);
|
||||
GetTag (TagTypes.Id3v2, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the audio properties from the file represented by
|
||||
/// the current instance.
|
||||
/// </summary>
|
||||
/// <param name="start">
|
||||
/// A <see cref="long" /> value containing the seek position
|
||||
/// at which the tags end and the media data begins.
|
||||
/// </param>
|
||||
/// <param name="end">
|
||||
/// A <see cref="long" /> value containing the seek position
|
||||
/// at which the media data ends and the tags begin.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="TagLib.Properties" /> object describing the
|
||||
/// media properties of the file represented by the current
|
||||
/// instance.
|
||||
/// </returns>
|
||||
protected override Properties ReadProperties (long start, long end, ReadStyle propertiesStyle)
|
||||
{
|
||||
first_header.SetStreamLength (end - start);
|
||||
return new Properties (TimeSpan.Zero, first_header);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ea5a2b9978c53a708489187d4f05f90
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4e181c0c58fe3641d805ee0aabca0c10
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,486 @@
|
||||
//
|
||||
// File.cs: Provides tagging and properties support for Apple's AIFF
|
||||
// files.
|
||||
//
|
||||
// Author:
|
||||
// Helmut Wahrmann
|
||||
//
|
||||
// Copyright (C) 2009 Helmut Wahrmann
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Aiff
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="TagLib.File" /> to provide
|
||||
/// support for reading and writing tags and properties for files
|
||||
/// using the AIFF file format.
|
||||
/// </summary>
|
||||
[SupportedMimeType ("taglib/aif", "aif")]
|
||||
[SupportedMimeType ("taglib/aiff", "aiff")]
|
||||
[SupportedMimeType ("audio/x-aiff")]
|
||||
[SupportedMimeType ("audio/aiff")]
|
||||
[SupportedMimeType ("sound/aiff")]
|
||||
[SupportedMimeType ("application/x-aiff")]
|
||||
public class File : TagLib.File
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the address of the AIFF header block.
|
||||
/// </summary>
|
||||
ByteVector header_block;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the Id3v2 tag.
|
||||
/// </summary>
|
||||
Id3v2.Tag tag;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the media properties.
|
||||
/// </summary>
|
||||
Properties properties;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Static Fields
|
||||
|
||||
/// <summary>
|
||||
/// The identifier used to recognize a AIFF files.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "FORM"
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector FileIdentifier = "FORM";
|
||||
|
||||
/// <summary>
|
||||
/// The identifier used to recognize a AIFF Common chunk.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "COMM"
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector CommIdentifier = "COMM";
|
||||
|
||||
/// <summary>
|
||||
/// The identifier used to recognize a AIFF Sound Data Chunk.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "SSND"
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector SoundIdentifier = "SSND";
|
||||
|
||||
/// <summary>
|
||||
/// The identifier used to recognize a AIFF ID3 chunk.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "ID3 "
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector ID3Identifier = "ID3 ";
|
||||
|
||||
/// <summary>
|
||||
/// The identifier used to recognize a AIFF Form type.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "AIFF"
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector AIFFFormType = "AIFF";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local file
|
||||
/// system and specified read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path, ReadStyle propertiesStyle)
|
||||
: this (new LocalFileAbstraction (path), propertiesStyle)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local file
|
||||
/// system with an average read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path)
|
||||
: this (path, ReadStyle.Average)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction and
|
||||
/// specified read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction, ReadStyle propertiesStyle) : base (abstraction)
|
||||
{
|
||||
Mode = AccessMode.Read;
|
||||
try {
|
||||
Read (true, propertiesStyle, out var aiff_size, out var tag_start, out var tag_end);
|
||||
} finally {
|
||||
Mode = AccessMode.Closed;
|
||||
}
|
||||
|
||||
TagTypesOnDisk = TagTypes;
|
||||
|
||||
GetTag (TagTypes.Id3v2, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction with an
|
||||
/// average read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction)
|
||||
: this (abstraction, ReadStyle.Average)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets a abstract representation of all tags stored in the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TagLib.Tag" /> object representing all tags
|
||||
/// stored in the current instance.
|
||||
/// </value>
|
||||
public override Tag Tag {
|
||||
get { return tag; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the media properties of the file represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TagLib.Properties" /> object containing the
|
||||
/// media properties of the file represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public override Properties Properties {
|
||||
get { return properties; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Saves the changes made in the current instance to the
|
||||
/// file it represents.
|
||||
/// </summary>
|
||||
public override void Save ()
|
||||
{
|
||||
// Boilerplate
|
||||
PreSave ();
|
||||
|
||||
Mode = AccessMode.Write;
|
||||
try {
|
||||
var data = new ByteVector ();
|
||||
|
||||
// Add the ID3 chunk and ID32 tag to the vector
|
||||
if (tag != null) {
|
||||
ByteVector tag_data = tag.Render ();
|
||||
if (tag_data.Count > 10) {
|
||||
if (tag_data.Count % 2 == 1)
|
||||
tag_data.Add (0);
|
||||
|
||||
data.Add ("ID3 ");
|
||||
data.Add (ByteVector.FromUInt ((uint)tag_data.Count, true));
|
||||
data.Add (tag_data);
|
||||
}
|
||||
}
|
||||
|
||||
Read (false, ReadStyle.None, out var aiff_size,
|
||||
out var tag_start, out var tag_end);
|
||||
|
||||
// If tagging info cannot be found, place it at
|
||||
// the end of the file.
|
||||
if (tag_start < 12 || tag_end < tag_start)
|
||||
tag_start = tag_end = Length;
|
||||
|
||||
int length = (int)(tag_end - tag_start + 8);
|
||||
|
||||
// Insert the tagging data.
|
||||
Insert (data, tag_start, length);
|
||||
|
||||
// If the data size changed update the aiff size.
|
||||
if (data.Count - length != 0 &&
|
||||
tag_start <= aiff_size) {
|
||||
// Depending, if a Tag has been added or removed,
|
||||
// the length needs to be adjusted
|
||||
if (tag == null) {
|
||||
length -= 16;
|
||||
} else {
|
||||
length -= 8;
|
||||
}
|
||||
|
||||
Insert (ByteVector.FromUInt ((uint)(aiff_size + data.Count - length), true), 4, 4);
|
||||
}
|
||||
// Update the tag types.
|
||||
TagTypesOnDisk = TagTypes;
|
||||
} finally {
|
||||
Mode = AccessMode.Closed;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a set of tag types from the current instance.
|
||||
/// </summary>
|
||||
/// <param name="types">
|
||||
/// A bitwise combined <see cref="TagLib.TagTypes" /> value
|
||||
/// containing tag types to be removed from the file.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// In order to remove all tags from a file, pass <see
|
||||
/// cref="TagTypes.AllTags" /> as <paramref name="types" />.
|
||||
/// </remarks>
|
||||
public override void RemoveTags (TagTypes types)
|
||||
{
|
||||
if (types == TagTypes.Id3v2 || types == TagTypes.AllTags) {
|
||||
tag = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a tag of a specified type from the current instance,
|
||||
/// optionally creating a new tag if possible.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="TagLib.TagTypes" /> value indicating the
|
||||
/// type of tag to read.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> value specifying whether or not to
|
||||
/// try and create the tag if one is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="Tag" /> object containing the tag that was
|
||||
/// found in or added to the current instance. If no
|
||||
/// matching tag was found and none was created, <see
|
||||
/// langword="null" /> is returned.
|
||||
/// </returns>
|
||||
public override Tag GetTag (TagTypes type, bool create)
|
||||
{
|
||||
Tag id32_tag = null;
|
||||
|
||||
switch (type) {
|
||||
case TagTypes.Id3v2:
|
||||
if (tag == null && create) {
|
||||
tag = new Id3v2.Tag {
|
||||
Version = 2
|
||||
};
|
||||
}
|
||||
|
||||
id32_tag = tag;
|
||||
break;
|
||||
}
|
||||
|
||||
return id32_tag;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Search the file for a chunk whose name is given by
|
||||
/// the chunkName parameter, starting from startPos.
|
||||
/// Note that startPos must be a valid position for a
|
||||
/// chunk, or else finding will fail.
|
||||
/// </summary>
|
||||
/// <param name="chunkName">Name of the chunk to search for</param>
|
||||
/// <param name="startPos">Position for starting the search</param>
|
||||
/// <returns>
|
||||
/// Position of the chunk in the stream, or -1
|
||||
/// if no chunk was found.
|
||||
/// </returns>
|
||||
long FindChunk (ByteVector chunkName, long startPos)
|
||||
{
|
||||
long initialPos = Tell;
|
||||
|
||||
try {
|
||||
// Start at the given position
|
||||
Seek (startPos);
|
||||
|
||||
// While not eof
|
||||
while (Tell < Length) {
|
||||
// Read 4-byte chunk name
|
||||
ByteVector chunkHeader = ReadBlock (4);
|
||||
|
||||
if (chunkHeader == chunkName) {
|
||||
// We found a matching chunk, return the position
|
||||
// of the header start
|
||||
return Tell - 4;
|
||||
} else {
|
||||
// This chunk is not the one we are looking for
|
||||
// Continue the search, seeking over the chunk
|
||||
uint chunkSize = ReadBlock (4).ToUInt ();
|
||||
// Seek forward "chunkSize" bytes
|
||||
Seek (chunkSize, System.IO.SeekOrigin.Current);
|
||||
}
|
||||
}
|
||||
|
||||
// We did not find the chunk
|
||||
return -1;
|
||||
} finally {
|
||||
Seek (initialPos);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the contents of the current instance determining
|
||||
/// the size of the riff data, the area the tagging is in,
|
||||
/// and optionally reading in the tags and media properties.
|
||||
/// </summary>
|
||||
/// <param name="read_tags">
|
||||
/// If <see langword="true" />, any tags found will be read
|
||||
/// into the current instance.
|
||||
/// </param>
|
||||
/// <param name="style">
|
||||
/// A <see cref="ReadStyle"/> value specifying how the media
|
||||
/// data is to be read into the current instance.
|
||||
/// </param>
|
||||
/// <param name="aiff_size">
|
||||
/// A <see cref="uint"/> value reference to be filled with
|
||||
/// the size of the RIFF data as read from the file.
|
||||
/// </param>
|
||||
/// <param name="tag_start">
|
||||
/// A <see cref="long" /> value reference to be filled with
|
||||
/// the absolute seek position at which the tagging data
|
||||
/// starts.
|
||||
/// </param>
|
||||
/// <param name="tag_end">
|
||||
/// A <see cref="long" /> value reference to be filled with
|
||||
/// the absolute seek position at which the tagging data
|
||||
/// ends.
|
||||
/// </param>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// The file does not begin with <see cref="FileIdentifier"
|
||||
/// />.
|
||||
/// </exception>
|
||||
void Read (bool read_tags, ReadStyle style, out uint aiff_size, out long tag_start, out long tag_end)
|
||||
{
|
||||
Seek (0);
|
||||
if (ReadBlock (4) != FileIdentifier)
|
||||
throw new CorruptFileException ("File does not begin with AIFF identifier");
|
||||
|
||||
aiff_size = ReadBlock (4).ToUInt (true);
|
||||
tag_start = -1;
|
||||
tag_end = -1;
|
||||
|
||||
// Check formType
|
||||
if (ReadBlock (4) != AIFFFormType)
|
||||
throw new CorruptFileException ("File form type is not AIFF");
|
||||
|
||||
long formBlockChunksPosition = Tell;
|
||||
|
||||
// Get the properties of the file
|
||||
if (header_block == null &&
|
||||
style != ReadStyle.None) {
|
||||
long common_chunk_pos = FindChunk (CommIdentifier, formBlockChunksPosition);
|
||||
|
||||
if (common_chunk_pos == -1) {
|
||||
throw new CorruptFileException ("No Common chunk available in AIFF file.");
|
||||
}
|
||||
|
||||
Seek (common_chunk_pos);
|
||||
header_block = ReadBlock ((int)StreamHeader.Size);
|
||||
|
||||
var header = new StreamHeader (header_block, aiff_size);
|
||||
properties = new Properties (TimeSpan.Zero, header);
|
||||
}
|
||||
|
||||
// Search for the ID3 chunk
|
||||
long id3_chunk_pos = FindChunk (ID3Identifier, formBlockChunksPosition);
|
||||
|
||||
// Search for the sound chunk
|
||||
long sound_chunk_pos = FindChunk (SoundIdentifier, formBlockChunksPosition);
|
||||
|
||||
// Ensure there is a sound chunk for the file to be valid
|
||||
if (sound_chunk_pos == -1) {
|
||||
throw new CorruptFileException ("No Sound chunk available in AIFF file.");
|
||||
}
|
||||
|
||||
// Get the length of the Sound chunk and use this as a start value to look for the ID3 chunk
|
||||
Seek (sound_chunk_pos + 4);
|
||||
|
||||
// Read the id3 chunk
|
||||
if (id3_chunk_pos > -1) {
|
||||
if (read_tags && tag == null) {
|
||||
tag = new Id3v2.Tag (this, id3_chunk_pos + 8, style);
|
||||
}
|
||||
|
||||
// Get the length of the tag out of the ID3 chunk
|
||||
Seek (id3_chunk_pos + 4);
|
||||
uint tag_size = ReadBlock (4).ToUInt (true) + 8;
|
||||
|
||||
tag_start = InvariantStartPosition = id3_chunk_pos;
|
||||
tag_end = InvariantEndPosition = tag_start + tag_size;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7c3c2cdcd3206d6c2984e6419139fc01
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,248 @@
|
||||
//
|
||||
// StreamHeader.cs: Provides support for reading Apple's AIFF stream
|
||||
// properties.
|
||||
//
|
||||
// Author:
|
||||
// Helmut Wahrmann
|
||||
//
|
||||
// Copyright (C) 2009 Helmut Wahrmann
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Aiff
|
||||
{
|
||||
/// <summary>
|
||||
/// This struct implements <see cref="IAudioCodec" /> to provide
|
||||
/// support for reading Apple's AIFF stream properties.
|
||||
/// </summary>
|
||||
public struct StreamHeader : IAudioCodec, ILosslessAudioCodec
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of channels.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (9,10).
|
||||
/// 1 is monophonic, 2 is stereo, 4 means 4 channels, etc..
|
||||
/// any number of audio channels may be represented
|
||||
/// </remarks>
|
||||
readonly ushort channels;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of sample frames in the Sound Data chunk.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (11-14).
|
||||
/// </remarks>
|
||||
readonly ulong total_frames;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of bits per sample.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (15,16).
|
||||
/// It can be any number from 1 to 32.
|
||||
/// </remarks>
|
||||
readonly ushort bits_per_sample;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the sample rate.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (17-26).
|
||||
/// the sample rate at which the sound is to be played back,
|
||||
/// in sample frames per second
|
||||
/// </remarks>
|
||||
readonly ulong sample_rate;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the length of the audio stream.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is provided by the constructor.
|
||||
/// </remarks>
|
||||
readonly long stream_length;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Static Fields
|
||||
|
||||
/// <summary>
|
||||
/// The size of an AIFF Common chunk
|
||||
/// </summary>
|
||||
public const uint Size = 26;
|
||||
|
||||
/// <summary>
|
||||
/// The identifier used to recognize a AIFF file.
|
||||
/// Altough an AIFF file start with "FORM2, we're interested
|
||||
/// in the Common chunk only, which contains the properties we need.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "COMM"
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector FileIdentifier = "COMM";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="StreamHeader" /> for a specified header block and
|
||||
/// stream length.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the stream
|
||||
/// header data.
|
||||
/// </param>
|
||||
/// <param name="streamLength">
|
||||
/// A <see cref="long" /> value containing the length of the
|
||||
/// AIFF Audio stream in bytes.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="data" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// <paramref name="data" /> does not begin with <see
|
||||
/// cref="FileIdentifier" />
|
||||
/// </exception>
|
||||
public StreamHeader (ByteVector data, long streamLength)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
|
||||
if (!data.StartsWith (FileIdentifier))
|
||||
throw new CorruptFileException ("Data does not begin with identifier.");
|
||||
|
||||
stream_length = streamLength;
|
||||
|
||||
// The first 8 bytes contain the Common chunk identifier "COMM"
|
||||
// And the size of the common chunk, which is always 18
|
||||
channels = data.Mid (8, 2).ToUShort (true);
|
||||
total_frames = data.Mid (10, 4).ToULong (true);
|
||||
bits_per_sample = data.Mid (14, 2).ToUShort (true);
|
||||
sample_rate = (ulong)data.Mid (16, 10).ToExtendedPrecision ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the duration of the media represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TimeSpan" /> containing the duration of the
|
||||
/// media represented by the current instance.
|
||||
/// </value>
|
||||
public TimeSpan Duration {
|
||||
get {
|
||||
if (sample_rate <= 0 || total_frames <= 0)
|
||||
return TimeSpan.Zero;
|
||||
|
||||
return TimeSpan.FromSeconds (
|
||||
total_frames /
|
||||
(double)sample_rate);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the types of media represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Always <see cref="MediaTypes.Audio" />.
|
||||
/// </value>
|
||||
public MediaTypes MediaTypes {
|
||||
get { return MediaTypes.Audio; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a text description of the media represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing a description
|
||||
/// of the media represented by the current instance.
|
||||
/// </value>
|
||||
public string Description {
|
||||
get { return "AIFF Audio"; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bitrate of the audio represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing a bitrate of the
|
||||
/// audio represented by the current instance.
|
||||
/// </value>
|
||||
public int AudioBitrate {
|
||||
get {
|
||||
TimeSpan d = Duration;
|
||||
if (d <= TimeSpan.Zero)
|
||||
return 0;
|
||||
|
||||
return (int)((stream_length * 8L) / d.TotalSeconds) / 1000;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sample rate of the audio represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the sample rate of
|
||||
/// the audio represented by the current instance.
|
||||
/// </value>
|
||||
public int AudioSampleRate {
|
||||
get { return (int)sample_rate; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of channels in the audio represented by
|
||||
/// the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the number of
|
||||
/// channels in the audio represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public int AudioChannels {
|
||||
get { return channels; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of bits per sample in the audio
|
||||
/// represented by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the number of bits
|
||||
/// per sample in the audio represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public int BitsPerSample {
|
||||
get { return bits_per_sample; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c36b8cbc292897db7b1633bd3967807b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 81f4ff937a733e84599dd980bba85dcf
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,275 @@
|
||||
//
|
||||
// File.cs: Provides tagging and properties support for Monkey's Audio APE
|
||||
// files.
|
||||
//
|
||||
// Author:
|
||||
// Helmut Wahrmann
|
||||
//
|
||||
// Copyright (C) 2007 Helmut Wahrmann
|
||||
// Copyright (C) 2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Ape
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="TagLib.NonContainer.File" /> to
|
||||
/// provide tagging and properties support for Monkey's Audio APE
|
||||
/// files.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A <see cref="TagLib.Ape.Tag" /> will be added automatically to
|
||||
/// any file that doesn't contain one. This change does not effect
|
||||
/// the physical file until <see cref="TagLib.File.Save" /> is called and can be
|
||||
/// reversed using the following method:
|
||||
/// <code>file.RemoveTags (file.TagTypes & ~file.TagTypesOnDisk);</code>
|
||||
/// </remarks>
|
||||
[SupportedMimeType ("taglib/ape", "ape")]
|
||||
[SupportedMimeType ("audio/x-ape")]
|
||||
[SupportedMimeType ("audio/ape")]
|
||||
[SupportedMimeType ("application/x-ape")]
|
||||
public class File : TagLib.NonContainer.File
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the block with the audio header.
|
||||
/// </summary>
|
||||
ByteVector header_block;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local file
|
||||
/// system and specified read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path, ReadStyle propertiesStyle)
|
||||
: base (path, propertiesStyle)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local file
|
||||
/// system with an average read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path)
|
||||
: base (path)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction and
|
||||
/// specified read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction, ReadStyle propertiesStyle)
|
||||
: base (abstraction, propertiesStyle)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction with an
|
||||
/// average read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction)
|
||||
: base (abstraction)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a tag of a specified type from the current instance,
|
||||
/// optionally creating a new tag if possible.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="TagLib.TagTypes" /> value indicating the
|
||||
/// type of tag to read.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> value specifying whether or not to
|
||||
/// try and create the tag if one is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="Tag" /> object containing the tag that was
|
||||
/// found in or added to the current instance. If no
|
||||
/// matching tag was found and none was created, <see
|
||||
/// langword="null" /> is returned.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// If a <see cref="TagLib.Id3v2.Tag" /> is added to the
|
||||
/// current instance, it will be placed at the start of the
|
||||
/// file. On the other hand, <see cref="TagLib.Id3v1.Tag" />
|
||||
/// <see cref="TagLib.Ape.Tag" /> will be added to the end of
|
||||
/// the file. All other tag types will be ignored.
|
||||
/// </remarks>
|
||||
public override TagLib.Tag GetTag (TagTypes type, bool create)
|
||||
{
|
||||
TagLib.Tag t = (Tag as TagLib.NonContainer.Tag)
|
||||
.GetTag (type);
|
||||
|
||||
if (t != null || !create)
|
||||
return t;
|
||||
|
||||
switch (type) {
|
||||
case TagTypes.Id3v1:
|
||||
return EndTag.AddTag (type, Tag);
|
||||
|
||||
case TagTypes.Id3v2:
|
||||
return StartTag.AddTag (type, Tag);
|
||||
|
||||
case TagTypes.Ape:
|
||||
return EndTag.AddTag (type, Tag);
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Reads format specific information at the start of the
|
||||
/// file.
|
||||
/// </summary>
|
||||
/// <param name="start">
|
||||
/// A <see cref="long" /> value containing the seek position
|
||||
/// at which the tags end and the media data begins.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
protected override void ReadStart (long start, ReadStyle propertiesStyle)
|
||||
{
|
||||
if (header_block != null &&
|
||||
(propertiesStyle & ReadStyle.Average) == 0)
|
||||
return;
|
||||
|
||||
Seek (start);
|
||||
header_block = ReadBlock ((int)StreamHeader.Size);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads format specific information at the end of the
|
||||
/// file.
|
||||
/// </summary>
|
||||
/// <param name="end">
|
||||
/// A <see cref="long" /> value containing the seek position
|
||||
/// at which the media data ends and the tags begin.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
protected override void ReadEnd (long end, ReadStyle propertiesStyle)
|
||||
{
|
||||
// Make sure we have an APE tag.
|
||||
GetTag (TagTypes.Ape, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the audio properties from the file represented by
|
||||
/// the current instance.
|
||||
/// </summary>
|
||||
/// <param name="start">
|
||||
/// A <see cref="long" /> value containing the seek position
|
||||
/// at which the tags end and the media data begins.
|
||||
/// </param>
|
||||
/// <param name="end">
|
||||
/// A <see cref="long" /> value containing the seek position
|
||||
/// at which the media data ends and the tags begin.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="TagLib.Properties" /> object describing the
|
||||
/// media properties of the file represented by the current
|
||||
/// instance.
|
||||
/// </returns>
|
||||
protected override Properties ReadProperties (long start, long end, ReadStyle propertiesStyle)
|
||||
{
|
||||
StreamHeader header = new StreamHeader (header_block,
|
||||
end - start);
|
||||
|
||||
return new Properties (TimeSpan.Zero, header);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6bd919f3cebce9e6b94eb2887772bf8d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,392 @@
|
||||
//
|
||||
// Footer.cs: Provides a representation of an APEv2 tag footer which can be read
|
||||
// from and written to disk.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Original Source:
|
||||
// apefooter.cpp from TagLib
|
||||
//
|
||||
// Copyright (C) 2005-2007 Brian Nickel
|
||||
// Copyright (C) 2004 Allan Sandfeld Jensen (Original Implementation)
|
||||
// copyright (C) 2002, 2003 Scott Wheeler (Original Implementation)
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Ape
|
||||
{
|
||||
#region Enums
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the flags applied to a <see cref="Footer" /> object.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum FooterFlags : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// The tag lacks a footer object.
|
||||
/// </summary>
|
||||
FooterAbsent = 0x40000000,
|
||||
|
||||
/// <summary>
|
||||
/// The footer is actually a header.
|
||||
/// </summary>
|
||||
IsHeader = 0x20000000,
|
||||
|
||||
/// <summary>
|
||||
/// The tag contains a header.
|
||||
/// </summary>
|
||||
HeaderPresent = 0x80000000
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This structure provides a representation of an APEv2 tag footer
|
||||
/// which can be read from and written to disk.
|
||||
/// </summary>
|
||||
public struct Footer : IEquatable<Footer>
|
||||
{
|
||||
#region Private Properties
|
||||
|
||||
/// <summary>
|
||||
/// Contains the APE tag version.
|
||||
/// </summary>
|
||||
readonly uint version;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Static Fields
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the size of an APEv2 footer.
|
||||
/// </summary>
|
||||
public const uint Size = 32;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the identifier used find an APEv2 footer in a
|
||||
/// file.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "<c>APETAGEX</c>"
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector FileIdentifier = "APETAGEX";
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Footer" /> by reading it from raw footer data.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the raw
|
||||
/// data to build the new instance from.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="data" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// <paramref name="data" /> is smaller than <see
|
||||
/// cref="Size" /> or does not begin with <see
|
||||
/// cref="FileIdentifier" />.
|
||||
/// </exception>
|
||||
public Footer (ByteVector data)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
if (data.Count < Size)
|
||||
throw new CorruptFileException ("Provided data is smaller than object size.");
|
||||
|
||||
if (!data.StartsWith (FileIdentifier))
|
||||
throw new CorruptFileException ("Provided data does not start with File Identifier");
|
||||
|
||||
version = data.Mid (8, 4).ToUInt (false);
|
||||
TagSize = data.Mid (12, 4).ToUInt (false);
|
||||
ItemCount = data.Mid (16, 4).ToUInt (false);
|
||||
Flags = (FooterFlags)data.Mid (20, 4).ToUInt (false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the version of APE tag described by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the version of the
|
||||
/// APE tag described by the current instance.
|
||||
/// </value>
|
||||
public uint Version {
|
||||
get { return version == 0 ? 2000 : version; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the flags that apply to the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A bitwise combined <see cref="FooterFlags" /> value
|
||||
/// containing the flags that apply to the current instance.
|
||||
/// </value>
|
||||
public FooterFlags Flags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the number of items in the tag represented
|
||||
/// by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the number of
|
||||
/// items in the tag represented by the current instance.
|
||||
/// </value>
|
||||
public uint ItemCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the tag represented by the current
|
||||
/// instance, including the footer but excluding the header
|
||||
/// if applicable.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the size of the
|
||||
/// tag represented by the current instance.
|
||||
/// </value>
|
||||
public uint TagSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the complete size of the tag represented by the
|
||||
/// current instance, including the header and footer.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the size of the
|
||||
/// tag represented by the current instance.
|
||||
/// </value>
|
||||
public uint CompleteTagSize {
|
||||
get {
|
||||
return TagSize + ((Flags &
|
||||
FooterFlags.HeaderPresent) != 0 ?
|
||||
Size : 0);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as an APE tag footer.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public ByteVector RenderFooter ()
|
||||
{
|
||||
return Render (false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as an APE tag header.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance or an empty
|
||||
/// <see cref="ByteVector" /> object if <see cref="Flags" />
|
||||
/// does not include <see cref="FooterFlags.HeaderPresent"
|
||||
/// />.
|
||||
/// </returns>
|
||||
public ByteVector RenderHeader ()
|
||||
{
|
||||
return (Flags & FooterFlags.HeaderPresent) != 0 ? Render (true) : new ByteVector ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as either an APE tag header
|
||||
/// or footer.
|
||||
/// </summary>
|
||||
/// <param name="isHeader">
|
||||
/// A <see cref="bool" /> value indicating whether or not the
|
||||
/// current instance is to be rendered as a header.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
ByteVector Render (bool isHeader)
|
||||
{
|
||||
var v = new ByteVector {
|
||||
|
||||
// add the file identifier -- "APETAGEX"
|
||||
FileIdentifier,
|
||||
|
||||
// add the version number -- we always render a 2.000
|
||||
// tag regardless of what the tag originally was.
|
||||
ByteVector.FromUInt (2000, false),
|
||||
|
||||
// add the tag size
|
||||
ByteVector.FromUInt (TagSize, false),
|
||||
|
||||
// add the item count
|
||||
ByteVector.FromUInt (ItemCount, false)
|
||||
};
|
||||
|
||||
// render and add the flags
|
||||
uint flags = 0;
|
||||
|
||||
if ((Flags & FooterFlags.HeaderPresent) != 0)
|
||||
flags |= (uint)FooterFlags.HeaderPresent;
|
||||
|
||||
// footer is always present
|
||||
if (isHeader)
|
||||
flags |= (uint)FooterFlags.IsHeader;
|
||||
else
|
||||
flags &= (uint)~FooterFlags.IsHeader;
|
||||
|
||||
v.Add (ByteVector.FromUInt (flags, false));
|
||||
|
||||
// add the reserved 64bit
|
||||
v.Add (ByteVector.FromULong (0));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region IEquatable
|
||||
|
||||
/// <summary>
|
||||
/// Generates a hash code for the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="int" /> value containing the hash code for
|
||||
/// the current instance.
|
||||
/// </returns>
|
||||
public override int GetHashCode ()
|
||||
{
|
||||
unchecked {
|
||||
return (int)((uint)Flags ^ TagSize ^ ItemCount ^ version);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether or not the current instance is equal to
|
||||
/// another object.
|
||||
/// </summary>
|
||||
/// <param name="other">
|
||||
/// A <see cref="object" /> to compare to the current
|
||||
/// instance.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="bool" /> value indicating whether or not the
|
||||
/// current instance is equal to <paramref name="other" />.
|
||||
/// </returns>
|
||||
/// <seealso cref="M:System.IEquatable`1.Equals" />
|
||||
public override bool Equals (object other)
|
||||
{
|
||||
if (!(other is Footer))
|
||||
return false;
|
||||
|
||||
return Equals ((Footer)other);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether or not the current instance is equal to
|
||||
/// another instance of <see cref="Footer" />.
|
||||
/// </summary>
|
||||
/// <param name="other">
|
||||
/// A <see cref="Footer" /> object to compare to the current
|
||||
/// instance.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="bool" /> value indicating whether or not the
|
||||
/// current instance is equal to <paramref name="other" />.
|
||||
/// </returns>
|
||||
/// <seealso cref="M:System.IEquatable`1.Equals" />
|
||||
public bool Equals (Footer other)
|
||||
{
|
||||
return Flags == other.Flags &&
|
||||
TagSize == other.TagSize &&
|
||||
ItemCount == other.ItemCount &&
|
||||
version == other.version;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not two instances of <see cref="Footer"
|
||||
/// /> are equal to eachother.
|
||||
/// </summary>
|
||||
/// <param name="first">
|
||||
/// The first <see cref="Footer" /> object to compare.
|
||||
/// </param>
|
||||
/// <param name="second">
|
||||
/// The second <see cref="Footer" /> object to compare.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if <paramref name="first" /> is
|
||||
/// equal to <paramref name="second" />. Otherwise, <see
|
||||
/// langword="false" />.
|
||||
/// </returns>
|
||||
public static bool operator == (Footer first, Footer second)
|
||||
{
|
||||
return first.Equals (second);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not two instances of <see cref="Footer"
|
||||
/// /> are unequal to eachother.
|
||||
/// </summary>
|
||||
/// <param name="first">
|
||||
/// The first <see cref="Footer" /> object to compare.
|
||||
/// </param>
|
||||
/// <param name="second">
|
||||
/// The second <see cref="Footer" /> object to compare.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if <paramref name="first" /> is
|
||||
/// unequal to <paramref name="second" />. Otherwise, <see
|
||||
/// langword="false" />.
|
||||
/// </returns>
|
||||
public static bool operator != (Footer first, Footer second)
|
||||
{
|
||||
return !first.Equals (second);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3fd643b62da0d63f89725b4266c74752
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,500 @@
|
||||
//
|
||||
// Item.cs: Provides a representation of an APEv2 tag item which can be read
|
||||
// from and written to disk.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Original Source:
|
||||
// apeitem.cpp from TagLib
|
||||
//
|
||||
// Copyright (C) 2005-2007 Brian Nickel
|
||||
// Copyright (C) 2004 by Allan Sandfeld Jensen (Original Implementation)
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Ape
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the type of data stored in a <see cref="Item" />
|
||||
/// object.
|
||||
/// </summary>
|
||||
public enum ItemType
|
||||
{
|
||||
/// <summary>
|
||||
/// The item contains Unicode text.
|
||||
/// </summary>
|
||||
Text = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The item contains binary data.
|
||||
/// </summary>
|
||||
Binary = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The item contains a locator (file path/URL) for external
|
||||
/// information.
|
||||
/// </summary>
|
||||
Locator = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This class provides a representation of an APEv2 tag item which
|
||||
/// can be read from and written to disk.
|
||||
/// </summary>
|
||||
public class Item : ICloneable
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the item value.
|
||||
/// </summary>
|
||||
ReadOnlyByteVector data;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the item text.
|
||||
/// </summary>
|
||||
string[] text;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Item" /> by reading in a raw APEv2 item.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the item to
|
||||
/// read.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// A <see cref="int" /> value specifying the offset in
|
||||
/// <paramref name="data" /> at which the item data begins.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="data" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="offset" /> is less than zero.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// A complete item could not be read.
|
||||
/// </exception>
|
||||
public Item (ByteVector data, int offset)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
Parse (data, offset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Item" /> with a specified key and value.
|
||||
/// </summary>
|
||||
/// <param name="key">
|
||||
/// A <see cref="string" /> object containing the key to use
|
||||
/// for the current instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="string" /> object containing the value to
|
||||
/// store in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="key" /> or <paramref name="value" /> is
|
||||
/// <see langword="null" />.
|
||||
/// </exception>
|
||||
public Item (string key, string value)
|
||||
{
|
||||
if (key == null)
|
||||
throw new ArgumentNullException (nameof (key));
|
||||
|
||||
if (value == null)
|
||||
throw new ArgumentNullException (nameof (value));
|
||||
|
||||
Key = key;
|
||||
text = new [] { value };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Item" /> with a specified key and collection of
|
||||
/// values.
|
||||
/// </summary>
|
||||
/// <param name="key">
|
||||
/// A <see cref="string" /> object containing the key to use
|
||||
/// for the current instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="T:string[]" /> containing the values to store
|
||||
/// in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="key" /> or <paramref name="value" /> is
|
||||
/// <see langword="null" />.
|
||||
/// </exception>
|
||||
public Item (string key, params string[] value)
|
||||
{
|
||||
if (key == null)
|
||||
throw new ArgumentNullException (nameof (key));
|
||||
|
||||
if (value == null)
|
||||
throw new ArgumentNullException (nameof (value));
|
||||
|
||||
Key = key;
|
||||
text = (string[])value.Clone ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Item" /> with a specified key and collection of
|
||||
/// values.
|
||||
/// </summary>
|
||||
/// <param name="key">
|
||||
/// A <see cref="string" /> object containing the key to use
|
||||
/// for the current instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="StringCollection" /> object containing the
|
||||
/// values to store in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="key" /> or <paramref name="value" /> is
|
||||
/// <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <seealso cref="Item(string,string[])" />
|
||||
[Obsolete ("Use Item(string,string[])")]
|
||||
public Item (string key, StringCollection value)
|
||||
{
|
||||
if (key == null)
|
||||
throw new ArgumentNullException (nameof (key));
|
||||
|
||||
if (value == null)
|
||||
throw new ArgumentNullException (nameof (value));
|
||||
|
||||
Key = key;
|
||||
text = value.ToArray ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Item" /> with a specified key and raw data.
|
||||
/// </summary>
|
||||
/// <param name="key">
|
||||
/// A <see cref="string" /> object containing the key to use
|
||||
/// for the current instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="StringCollection" /> object containing the
|
||||
/// values to store in the new instance.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// This constructor automatically marks the new instance as
|
||||
/// <see cref="ItemType.Binary" />.
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="key" /> or <paramref name="value" /> is
|
||||
/// <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <seealso cref="Item(string,string[])" />
|
||||
public Item (string key, ByteVector value)
|
||||
{
|
||||
Key = key;
|
||||
Type = ItemType.Binary;
|
||||
|
||||
data = value as ReadOnlyByteVector;
|
||||
if (data == null)
|
||||
data = new ReadOnlyByteVector (value);
|
||||
}
|
||||
|
||||
Item (Item item)
|
||||
{
|
||||
Type = item.Type;
|
||||
Key = item.Key;
|
||||
|
||||
if (item.data != null)
|
||||
data = new ReadOnlyByteVector (item.data);
|
||||
|
||||
if (item.text != null)
|
||||
text = (string[])item.text.Clone ();
|
||||
|
||||
ReadOnly = item.ReadOnly;
|
||||
Size = item.Size;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the key used to identify the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing the key used to
|
||||
/// identify the current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// This value is used for specifying the contents of the
|
||||
/// item in a common and consistant fashion. For example,
|
||||
/// <c>"TITLE"</c> specifies that the item contains the title
|
||||
/// of the track.
|
||||
/// </remarks>
|
||||
public string Key { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the binary value stored in the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ByteVector" /> object containing the binary
|
||||
/// value stored in the current instance, or <see
|
||||
/// langword="null" /> if the item contains text.
|
||||
/// </value>
|
||||
public ByteVector Value {
|
||||
get { return (Type == ItemType.Binary) ? data : null; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the current instance as it last appeared
|
||||
/// on disk.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the size of the
|
||||
/// current instance as it last appeared on disk.
|
||||
/// </value>
|
||||
public int Size { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the type of value contained in the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ItemType" /> value indicating the type of
|
||||
/// value contained in the current instance.
|
||||
/// </value>
|
||||
public ItemType Type { get; set; } = ItemType.Text;
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets whether or not the current instance is
|
||||
/// flagged as read-only on disk.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="bool" /> value indicating whether or not the
|
||||
/// current instance is flagged as read-only on disk.
|
||||
/// </value>
|
||||
public bool ReadOnly { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not the current instance is empty.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="bool" /> value indicating whether or not the
|
||||
/// current instance contains no value.
|
||||
/// </value>
|
||||
public bool IsEmpty {
|
||||
get {
|
||||
if (Type != ItemType.Binary)
|
||||
return text == null || text.Length == 0;
|
||||
else
|
||||
return data == null || data.IsEmpty;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets the contents of the current instance as a <see
|
||||
/// cref="string" />.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// <para>A <see cref="string" /> object containing the text
|
||||
/// stored in the current instance, or <see langword="null"
|
||||
/// /> if the item is empty of contains binary data.</para>
|
||||
/// <para>If the current instance contains multiple string
|
||||
/// values, they will be returned as a comma separated
|
||||
/// value.</para>
|
||||
/// </returns>
|
||||
public override string ToString ()
|
||||
{
|
||||
if (Type == ItemType.Binary || text == null)
|
||||
return null;
|
||||
|
||||
return string.Join (", ", text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the contents of the current instance as a <see
|
||||
/// cref="string" /> array.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="T:string[]" /> containing the text stored in
|
||||
/// the current instance, or an empty array if the item
|
||||
/// contains binary data.
|
||||
/// </returns>
|
||||
public string[] ToStringArray ()
|
||||
{
|
||||
if (Type == ItemType.Binary || text == null)
|
||||
return new string[0];
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as an APEv2 item.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public ByteVector Render ()
|
||||
{
|
||||
uint flags = (uint)((ReadOnly) ? 1 : 0) |
|
||||
((uint)Type << 1);
|
||||
|
||||
if (IsEmpty)
|
||||
return new ByteVector ();
|
||||
|
||||
ByteVector result = null;
|
||||
|
||||
if (Type == ItemType.Binary) {
|
||||
if (text == null && data != null)
|
||||
result = data;
|
||||
}
|
||||
|
||||
if (result == null && text != null) {
|
||||
result = new ByteVector ();
|
||||
|
||||
for (int i = 0; i < text.Length; i++) {
|
||||
if (i != 0)
|
||||
result.Add (0);
|
||||
|
||||
result.Add (ByteVector.FromString (text[i], StringType.UTF8));
|
||||
}
|
||||
}
|
||||
|
||||
// If no data is stored, don't write the item.
|
||||
if (result == null || result.Count == 0)
|
||||
return new ByteVector ();
|
||||
|
||||
var output = new ByteVector {
|
||||
ByteVector.FromUInt ((uint)result.Count,
|
||||
false),
|
||||
ByteVector.FromUInt (flags, false),
|
||||
ByteVector.FromString (Key, StringType.UTF8),
|
||||
0,
|
||||
result
|
||||
};
|
||||
|
||||
Size = output.Count;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Populates the current instance by reading in a raw APEv2
|
||||
/// item.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the item to
|
||||
/// read.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// A <see cref="int" /> value specifying the offset in
|
||||
/// <paramref name="data" /> at which the item data begins.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="data" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="offset" /> is less than zero.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// A complete item could not be read.
|
||||
/// </exception>
|
||||
protected void Parse (ByteVector data, int offset)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
if (offset < 0)
|
||||
throw new ArgumentOutOfRangeException (nameof (offset));
|
||||
|
||||
|
||||
// 11 bytes is the minimum size for an APE item
|
||||
if (data.Count < offset + 11)
|
||||
throw new CorruptFileException ("Not enough data for APE Item");
|
||||
|
||||
uint value_length = data.Mid (offset, 4).ToUInt (false);
|
||||
uint flags = data.Mid (offset + 4, 4).ToUInt (false);
|
||||
|
||||
ReadOnly = (flags & 1) == 1;
|
||||
Type = (ItemType)((flags >> 1) & 3);
|
||||
|
||||
int pos = data.Find (ByteVector.TextDelimiter (StringType.UTF8), offset + 8);
|
||||
|
||||
Key = data.ToString (StringType.UTF8, offset + 8, pos - offset - 8);
|
||||
|
||||
if (value_length > data.Count - pos - 1)
|
||||
throw new CorruptFileException ("Invalid data length.");
|
||||
|
||||
Size = pos + 1 + (int)value_length - offset;
|
||||
|
||||
if (Type == ItemType.Binary)
|
||||
this.data = new ReadOnlyByteVector (data.Mid (pos + 1, (int)value_length));
|
||||
else
|
||||
text = data.Mid (pos + 1, (int)value_length).ToStrings (StringType.UTF8, 0);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region ICloneable
|
||||
|
||||
/// <summary>
|
||||
/// Creates a deep copy of the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A new <see cref="Item"/> object identical to the current
|
||||
/// instance.
|
||||
/// </returns>
|
||||
public Item Clone ()
|
||||
{
|
||||
return new Item (this);
|
||||
}
|
||||
|
||||
object ICloneable.Clone ()
|
||||
{
|
||||
return Clone ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ec6d7edea3a67467d8e074bff4ac65d7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,359 @@
|
||||
//
|
||||
// StreamHeader.cs: Provides support for reading Monkey's Audio APE stream
|
||||
// properties.
|
||||
//
|
||||
// Author:
|
||||
// Helmut Wahrmann
|
||||
//
|
||||
// Copyright (C) 2007 Helmut Wahrmann
|
||||
// Copyright (C) 2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace TagLib.Ape
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the compression level used when encoding a Monkey's
|
||||
/// Audio APE file.
|
||||
/// </summary>
|
||||
public enum CompressionLevel
|
||||
{
|
||||
/// <summary>
|
||||
/// The audio is not compressed.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The audio is mildly compressed.
|
||||
/// </summary>
|
||||
Fast = 1000,
|
||||
|
||||
/// <summary>
|
||||
/// The audio is compressed at a normal level.
|
||||
/// </summary>
|
||||
Normal = 2000,
|
||||
|
||||
/// <summary>
|
||||
/// The audio is highly compressed.
|
||||
/// </summary>
|
||||
High = 3000,
|
||||
|
||||
/// <summary>
|
||||
/// The audio is extremely highly compressed.
|
||||
/// </summary>
|
||||
ExtraHigh = 4000,
|
||||
|
||||
/// <summary>
|
||||
/// The audio is compressed to an insane level.
|
||||
/// </summary>
|
||||
Insane
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This struct implements <see cref="IAudioCodec" /> to provide
|
||||
/// support for reading Monkey's Audio APE stream properties.
|
||||
/// </summary>
|
||||
public struct StreamHeader : IAudioCodec, ILosslessAudioCodec
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the APE version.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (4,5) of the file and is
|
||||
/// 1000 times the actual version number, so 3810 indicates
|
||||
/// version 3.81.
|
||||
/// </remarks>
|
||||
readonly ushort version;
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// Contains the format flags.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (53,54).
|
||||
/// </remarks>
|
||||
private ushort format_flags;
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of audio blocks in one frame.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (55-58).
|
||||
/// </remarks>
|
||||
readonly uint blocks_per_frame;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of audio blocks in the final frame.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (59-62).
|
||||
/// </remarks>
|
||||
readonly uint final_frame_blocks;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the total number of frames.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (63-66).
|
||||
/// </remarks>
|
||||
readonly uint total_frames;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of bits per sample.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (67,68) and is typically
|
||||
/// 16.
|
||||
/// </remarks>
|
||||
readonly ushort bits_per_sample;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of channels.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (69,70) and is typically
|
||||
/// 1 or 2.
|
||||
/// </remarks>
|
||||
readonly ushort channels;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the sample rate.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (71-74) and is typically
|
||||
/// 44100.
|
||||
/// </remarks>
|
||||
readonly uint sample_rate;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the length of the audio stream.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is provided by the constructor.
|
||||
/// </remarks>
|
||||
readonly long stream_length;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Static Fields
|
||||
|
||||
/// <summary>
|
||||
/// The size of a Monkey Audio header.
|
||||
/// </summary>
|
||||
public const uint Size = 76;
|
||||
|
||||
/// <summary>
|
||||
/// The identifier used to recognize a WavPack file.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "MAC "
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector FileIdentifier = "MAC ";
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="StreamHeader" /> for a specified header block and
|
||||
/// stream length.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the stream
|
||||
/// header data.
|
||||
/// </param>
|
||||
/// <param name="streamLength">
|
||||
/// A <see cref="long" /> value containing the length of the
|
||||
/// Monkey Audio stream in bytes.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="data" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// <paramref name="data" /> does not begin with <see
|
||||
/// cref="FileIdentifier" /> or is less than <see cref="Size"
|
||||
/// /> bytes long.
|
||||
/// </exception>
|
||||
public StreamHeader (ByteVector data, long streamLength)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
if (!data.StartsWith (FileIdentifier))
|
||||
throw new CorruptFileException (
|
||||
"Data does not begin with identifier.");
|
||||
|
||||
if (data.Count < Size)
|
||||
throw new CorruptFileException (
|
||||
"Insufficient data in stream header");
|
||||
|
||||
stream_length = streamLength;
|
||||
version = data.Mid (4, 2).ToUShort (false);
|
||||
Compression = (CompressionLevel)data.Mid (52, 2)
|
||||
.ToUShort (false);
|
||||
// format_flags = data.Mid(54, 2).ToUShort(false);
|
||||
blocks_per_frame = data.Mid (56, 4).ToUInt (false);
|
||||
final_frame_blocks = data.Mid (60, 4).ToUInt (false);
|
||||
total_frames = data.Mid (64, 4).ToUInt (false);
|
||||
bits_per_sample = data.Mid (68, 2).ToUShort (false);
|
||||
channels = data.Mid (70, 2).ToUShort (false);
|
||||
sample_rate = data.Mid (72, 4).ToUInt (false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the duration of the media represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TimeSpan" /> containing the duration of the
|
||||
/// media represented by the current instance.
|
||||
/// </value>
|
||||
public TimeSpan Duration {
|
||||
get {
|
||||
if (sample_rate <= 0 || total_frames <= 0)
|
||||
return TimeSpan.Zero;
|
||||
|
||||
return TimeSpan.FromSeconds (
|
||||
((total_frames - 1) *
|
||||
blocks_per_frame + final_frame_blocks) /
|
||||
(double)sample_rate);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the types of media represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Always <see cref="MediaTypes.Audio" />.
|
||||
/// </value>
|
||||
public MediaTypes MediaTypes {
|
||||
get { return MediaTypes.Audio; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a text description of the media represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing a description
|
||||
/// of the media represented by the current instance.
|
||||
/// </value>
|
||||
public string Description {
|
||||
get {
|
||||
return string.Format (
|
||||
CultureInfo.InvariantCulture, "Monkey's Audio APE Version {0:0.000}", Version);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bitrate of the audio represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing a bitrate of the
|
||||
/// audio represented by the current instance.
|
||||
/// </value>
|
||||
public int AudioBitrate {
|
||||
get {
|
||||
TimeSpan d = Duration;
|
||||
if (d <= TimeSpan.Zero)
|
||||
return 0;
|
||||
|
||||
return (int)((stream_length * 8L) / d.TotalSeconds) / 1000;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sample rate of the audio represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the sample rate of
|
||||
/// the audio represented by the current instance.
|
||||
/// </value>
|
||||
public int AudioSampleRate {
|
||||
get { return (int)sample_rate; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of channels in the audio represented by
|
||||
/// the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the number of
|
||||
/// channels in the audio represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public int AudioChannels {
|
||||
get { return channels; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the APE version of the audio represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="double" /> value containing the APE version
|
||||
/// of the audio represented by the current instance.
|
||||
/// </value>
|
||||
public double Version {
|
||||
get { return version / (double)1000; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of bits per sample in the audio
|
||||
/// represented by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the number of bits
|
||||
/// per sample in the audio represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public int BitsPerSample {
|
||||
get { return bits_per_sample; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the level of compression used when encoding the
|
||||
/// audio represented by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="CompressionLevel" /> value indicating the
|
||||
/// level of compression used when encoding the audio
|
||||
/// represented by the current instance.
|
||||
/// </value>
|
||||
public CompressionLevel Compression { get; private set; }
|
||||
|
||||
#endregion
|
||||
}␍}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d8234dea7db8f83ed86cb702f3474bbe
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e937bf4e5ed85bb70b1660583e8eb5dc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5551302f5547e0525a891b390866fb18
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,263 @@
|
||||
//
|
||||
// ContentDescriptionObject.cs: Provides a representation of an ASF Content
|
||||
// Description object which can be read from and written to disk.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Object" /> to provide a
|
||||
/// representation of an ASF Content Description object which can be
|
||||
/// read from and written to disk.
|
||||
/// </summary>
|
||||
public class ContentDescriptionObject : Object
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the media title.
|
||||
/// </summary>
|
||||
string title = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the author/performer.
|
||||
/// </summary>
|
||||
string author = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the copyright information.
|
||||
/// </summary>
|
||||
string copyright = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the description of the media.
|
||||
/// </summary>
|
||||
string description = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the rating of the media.
|
||||
/// </summary>
|
||||
string rating = string.Empty;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ContentDescriptionObject" /> by reading the
|
||||
/// contents from a specified position in a specified file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object containing the file from
|
||||
/// which the contents of the new instance are to be read.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specify at what position to
|
||||
/// read the object.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="position" /> is less than zero or greater
|
||||
/// than the size of the file.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// The object read from disk does not have the correct GUID
|
||||
/// or smaller than the minimum size.
|
||||
/// </exception>
|
||||
public ContentDescriptionObject (File file, long position)
|
||||
: base (file, position)
|
||||
{
|
||||
if (Guid != Asf.Guid.AsfContentDescriptionObject)
|
||||
throw new CorruptFileException ("Object GUID incorrect.");
|
||||
|
||||
if (OriginalSize < 34)
|
||||
throw new CorruptFileException ("Object size too small.");
|
||||
|
||||
ushort title_length = file.ReadWord ();
|
||||
ushort author_length = file.ReadWord ();
|
||||
ushort copyright_length = file.ReadWord ();
|
||||
ushort description_length = file.ReadWord ();
|
||||
ushort rating_length = file.ReadWord ();
|
||||
|
||||
title = file.ReadUnicode (title_length);
|
||||
author = file.ReadUnicode (author_length);
|
||||
copyright = file.ReadUnicode (copyright_length);
|
||||
description = file.ReadUnicode (description_length);
|
||||
rating = file.ReadUnicode (rating_length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ContentDescriptionObject" /> with no contents.
|
||||
/// </summary>
|
||||
public ContentDescriptionObject ()
|
||||
: base (Asf.Guid.AsfContentDescriptionObject)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Region
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the title of the media described by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing the title of
|
||||
/// the media or <see langword="null" /> if it is not set.
|
||||
/// </value>
|
||||
public string Title {
|
||||
get { return title.Length == 0 ? null : title; }
|
||||
set {
|
||||
title = string.IsNullOrEmpty (value) ? string.Empty : value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the author or performer of the media
|
||||
/// described by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing the author of
|
||||
/// the media or <see langword="null" /> if it is not set.
|
||||
/// </value>
|
||||
public string Author {
|
||||
get { return author.Length == 0 ? null : author; }
|
||||
set {
|
||||
author = string.IsNullOrEmpty (value) ? string.Empty : value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the copyright information for the media
|
||||
/// described by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing the copyright
|
||||
/// information for the media or <see langword="null" /> if
|
||||
/// it is not set.
|
||||
/// </value>
|
||||
public string Copyright {
|
||||
get { return copyright.Length == 0 ? null : copyright; }
|
||||
set {
|
||||
copyright = string.IsNullOrEmpty (value) ? string.Empty : value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the description of the media described by
|
||||
/// the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing a description
|
||||
/// of the media or <see langword="null" /> if it is not set.
|
||||
/// </value>
|
||||
public string Description {
|
||||
get {
|
||||
return description.Length == 0 ? null : description;
|
||||
}
|
||||
set {
|
||||
description = string.IsNullOrEmpty (value) ? string.Empty : value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the rating of the media described by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing a rating of the
|
||||
/// media or <see langword="null" /> if it is not set.
|
||||
/// </value>
|
||||
public string Rating {
|
||||
get { return rating.Length == 0 ? null : rating; }
|
||||
set {
|
||||
rating = string.IsNullOrEmpty (value) ? string.Empty : value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not the current instance is empty.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <see langword="true" /> if all the values are cleared.
|
||||
/// Otherwise <see langword="false" />.
|
||||
/// </value>
|
||||
public bool IsEmpty {
|
||||
get {
|
||||
return title.Length == 0 &&
|
||||
author.Length == 0 &&
|
||||
copyright.Length == 0 &&
|
||||
description.Length == 0 &&
|
||||
rating.Length == 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Region
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ASF object.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public override ByteVector Render ()
|
||||
{
|
||||
ByteVector title_bytes = RenderUnicode (title);
|
||||
ByteVector author_bytes = RenderUnicode (author);
|
||||
ByteVector copyright_bytes = RenderUnicode (copyright);
|
||||
ByteVector description_bytes =
|
||||
RenderUnicode (description);
|
||||
ByteVector rating_bytes = RenderUnicode (rating);
|
||||
|
||||
ByteVector output = RenderWord ((ushort)
|
||||
title_bytes.Count);
|
||||
output.Add (RenderWord ((ushort)author_bytes.Count));
|
||||
output.Add (RenderWord ((ushort)copyright_bytes.Count));
|
||||
output.Add (RenderWord ((ushort)
|
||||
description_bytes.Count));
|
||||
output.Add (RenderWord ((ushort)rating_bytes.Count));
|
||||
output.Add (title_bytes);
|
||||
output.Add (author_bytes);
|
||||
output.Add (copyright_bytes);
|
||||
output.Add (description_bytes);
|
||||
output.Add (rating_bytes);
|
||||
|
||||
return Render (output);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f526cfb69af160d3c9edf6227f73e985
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,474 @@
|
||||
//
|
||||
// ContentDescriptor.cs: Provides a representation of an ASF Content Descriptor
|
||||
// to be used in combination with ExtendedContentDescriptionObject.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the type of data stored in a <see
|
||||
/// cref="ContentDescriptor" /> or <see cref="DescriptionRecord" />
|
||||
/// object.
|
||||
/// </summary>
|
||||
public enum DataType
|
||||
{
|
||||
/// <summary>
|
||||
/// The descriptor contains Unicode (UTF-16LE) text.
|
||||
/// </summary>
|
||||
Unicode = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The descriptor contains binary data.
|
||||
/// </summary>
|
||||
Bytes = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The descriptor contains a boolean value.
|
||||
/// </summary>
|
||||
Bool = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The descriptor contains a 4-byte DWORD value.
|
||||
/// </summary>
|
||||
DWord = 3,
|
||||
|
||||
/// <summary>
|
||||
/// The descriptor contains a 8-byte QWORD value.
|
||||
/// </summary>
|
||||
QWord = 4,
|
||||
|
||||
/// <summary>
|
||||
/// The descriptor contains a 2-byte WORD value.
|
||||
/// </summary>
|
||||
Word = 5,
|
||||
|
||||
/// <summary>
|
||||
/// The descriptor contains a 16-byte GUID value.
|
||||
/// </summary>
|
||||
Guid = 6
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This class provides a representation of an ASF Content
|
||||
/// Descriptor to be used in combination with <see
|
||||
/// cref="ExtendedContentDescriptionObject" />.
|
||||
/// </summary>
|
||||
public class ContentDescriptor
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the string value.
|
||||
/// </summary>
|
||||
string strValue;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the byte value.
|
||||
/// </summary>
|
||||
ByteVector byteValue;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the long value.
|
||||
/// </summary>
|
||||
ulong longValue;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ContentDescriptor" /> with a specified name and
|
||||
/// and value.
|
||||
/// </summary>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// new instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="string" /> object containing the value for
|
||||
/// the new instance.
|
||||
/// </param>
|
||||
public ContentDescriptor (string name, string value)
|
||||
{
|
||||
Name = name;
|
||||
strValue = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ContentDescriptor" /> with a specified name and
|
||||
/// and value.
|
||||
/// </summary>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// new instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="ByteVector" /> object containing the value
|
||||
/// for the new instance.
|
||||
/// </param>
|
||||
public ContentDescriptor (string name, ByteVector value)
|
||||
{
|
||||
Name = name;
|
||||
Type = DataType.Bytes;
|
||||
byteValue = new ByteVector (value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ContentDescriptor" /> with a specified name and
|
||||
/// and value.
|
||||
/// </summary>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// new instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="uint" /> value containing the value
|
||||
/// for the new instance.
|
||||
/// </param>
|
||||
public ContentDescriptor (string name, uint value)
|
||||
{
|
||||
Name = name;
|
||||
Type = DataType.DWord;
|
||||
longValue = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ContentDescriptor" /> with a specified name and
|
||||
/// and value.
|
||||
/// </summary>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// new instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="ulong" /> value containing the value
|
||||
/// for the new instance.
|
||||
/// </param>
|
||||
public ContentDescriptor (string name, ulong value)
|
||||
{
|
||||
Name = name;
|
||||
Type = DataType.QWord;
|
||||
longValue = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ContentDescriptor" /> with a specified name and
|
||||
/// and value.
|
||||
/// </summary>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// new instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="ushort" /> value containing the value
|
||||
/// for the new instance.
|
||||
/// </param>
|
||||
public ContentDescriptor (string name, ushort value)
|
||||
{
|
||||
Name = name;
|
||||
Type = DataType.Word;
|
||||
longValue = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ContentDescriptor" /> with a specified name and
|
||||
/// and value.
|
||||
/// </summary>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// new instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="bool" /> value containing the value
|
||||
/// for the new instance.
|
||||
/// </param>
|
||||
public ContentDescriptor (string name, bool value)
|
||||
{
|
||||
Name = name;
|
||||
Type = DataType.Bool;
|
||||
longValue = value ? 1uL : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ContentDescriptor" /> by reading its contents from
|
||||
/// a file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object to read the raw ASF
|
||||
/// Description Record from.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// A valid descriptor could not be read.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// <paramref name="file" /> must be at a seek position at
|
||||
/// which the descriptor can be read.
|
||||
/// </remarks>
|
||||
protected internal ContentDescriptor (File file)
|
||||
{
|
||||
if (file == null)
|
||||
throw new ArgumentNullException (nameof (file));
|
||||
|
||||
if (!Parse (file))
|
||||
throw new CorruptFileException ("Failed to parse content descriptor.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// current instance.
|
||||
/// </value>
|
||||
public string Name { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of data contained in the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="DataType" /> value indicating type of data
|
||||
/// contained in the current instance.
|
||||
/// </value>
|
||||
public DataType Type { get; private set; } = DataType.Unicode;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string representation of the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="string" /> object containing the value of
|
||||
/// the current instance.
|
||||
/// </returns>
|
||||
public override string ToString ()
|
||||
{
|
||||
if (Type == DataType.Unicode)
|
||||
return strValue;
|
||||
|
||||
if (Type == DataType.Bytes)
|
||||
return byteValue.ToString (StringType.UTF16LE);
|
||||
|
||||
return longValue.ToString ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the binary contents of the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// contents of the current instance, or <see langword="null"
|
||||
/// /> if <see cref="Type" /> is unequal to <see
|
||||
/// cref="DataType.Bytes" />.
|
||||
/// </returns>
|
||||
public ByteVector ToByteVector ()
|
||||
{
|
||||
return byteValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the boolean value contained in the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="bool" /> value containing the value of the
|
||||
/// current instance.
|
||||
/// </returns>
|
||||
public bool ToBool ()
|
||||
{
|
||||
return longValue != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the DWORD value contained in the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="uint" /> value containing the value of the
|
||||
/// current instance.
|
||||
/// </returns>
|
||||
public uint ToDWord ()
|
||||
{
|
||||
if (Type == DataType.Unicode && strValue != null && uint.TryParse (strValue, out var value))
|
||||
return value;
|
||||
|
||||
return (uint)longValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the QWORD value contained in the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ulong" /> value containing the value of the
|
||||
/// current instance.
|
||||
/// </returns>
|
||||
public ulong ToQWord ()
|
||||
{
|
||||
if (Type == DataType.Unicode && strValue != null && ulong.TryParse (strValue, out var value))
|
||||
return value;
|
||||
|
||||
return longValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the WORD value contained in the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ushort" /> value containing the value of the
|
||||
/// current instance.
|
||||
/// </returns>
|
||||
public ushort ToWord ()
|
||||
{
|
||||
if (Type == DataType.Unicode && strValue != null && ushort.TryParse (strValue, out var value))
|
||||
return value;
|
||||
|
||||
return (ushort)longValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ASF Description
|
||||
/// Record.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public ByteVector Render ()
|
||||
{
|
||||
ByteVector value;
|
||||
|
||||
switch (Type) {
|
||||
case DataType.Unicode:
|
||||
value = Object.RenderUnicode (strValue);
|
||||
break;
|
||||
case DataType.Bytes:
|
||||
value = byteValue;
|
||||
break;
|
||||
case DataType.Bool:
|
||||
case DataType.DWord:
|
||||
value = Object.RenderDWord ((uint)longValue);
|
||||
break;
|
||||
case DataType.QWord:
|
||||
value = Object.RenderQWord (longValue);
|
||||
break;
|
||||
case DataType.Word:
|
||||
value = Object.RenderWord ((ushort)longValue);
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
ByteVector name = Object.RenderUnicode (Name);
|
||||
|
||||
var output = new ByteVector {
|
||||
Object.RenderWord ((ushort)name.Count),
|
||||
name,
|
||||
Object.RenderWord ((ushort)Type),
|
||||
Object.RenderWord ((ushort)value.Count),
|
||||
value
|
||||
};
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Populates the current instance by reading in the contents
|
||||
/// from a file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object to read the raw ASF
|
||||
/// Content Descriptor from.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if the data was read correctly.
|
||||
/// Otherwise <see langword="false" />.
|
||||
/// </returns>
|
||||
protected bool Parse (File file)
|
||||
{
|
||||
int name_count = file.ReadWord ();
|
||||
Name = file.ReadUnicode (name_count);
|
||||
|
||||
Type = (DataType)file.ReadWord ();
|
||||
|
||||
int value_count = file.ReadWord ();
|
||||
switch (Type) {
|
||||
case DataType.Word:
|
||||
longValue = file.ReadWord ();
|
||||
break;
|
||||
|
||||
case DataType.Bool:
|
||||
longValue = file.ReadDWord ();
|
||||
break;
|
||||
|
||||
case DataType.DWord:
|
||||
longValue = file.ReadDWord ();
|
||||
break;
|
||||
|
||||
case DataType.QWord:
|
||||
longValue = file.ReadQWord ();
|
||||
break;
|
||||
|
||||
case DataType.Unicode:
|
||||
strValue = file.ReadUnicode (value_count);
|
||||
break;
|
||||
|
||||
case DataType.Bytes:
|
||||
byteValue = file.ReadBlock (value_count);
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 12848f0d0cefe0dd3864fc18248f7482
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,568 @@
|
||||
//
|
||||
// DescriptionRecord.cs: Provides a representation of an ASF Description Record
|
||||
// to be used in combination with MetadataLibaryObject.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// This class provides a representation of an ASF Description Record
|
||||
/// to be used in combination with <see cref="MetadataLibraryObject"
|
||||
/// />.
|
||||
/// </summary>
|
||||
public class DescriptionRecord
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the string value.
|
||||
/// </summary>
|
||||
string strValue;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the byte value.
|
||||
/// </summary>
|
||||
ByteVector byteValue;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the long value.
|
||||
/// </summary>
|
||||
ulong longValue;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the GUID value.
|
||||
/// </summary>
|
||||
System.Guid guidValue = System.Guid.Empty;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="DescriptionRecord" /> with a specified language,
|
||||
/// stream, name, and value.
|
||||
/// </summary>
|
||||
/// <param name="languageListIndex">
|
||||
/// A <see cref="ushort" /> value containing the language
|
||||
/// list index of the new instance.
|
||||
/// </param>
|
||||
/// <param name="streamNumber">
|
||||
/// A <see cref="ushort" /> value containing the stream
|
||||
/// number of the new instance.
|
||||
/// </param>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// new instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="string" /> object containing the value for
|
||||
/// the new instance.
|
||||
/// </param>
|
||||
public DescriptionRecord (ushort languageListIndex, ushort streamNumber, string name, string value)
|
||||
{
|
||||
LanguageListIndex = languageListIndex;
|
||||
StreamNumber = streamNumber;
|
||||
Name = name;
|
||||
strValue = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="DescriptionRecord" /> with a specified language,
|
||||
/// stream, name, and value.
|
||||
/// </summary>
|
||||
/// <param name="languageListIndex">
|
||||
/// A <see cref="ushort" /> value containing the language
|
||||
/// list index of the new instance.
|
||||
/// </param>
|
||||
/// <param name="streamNumber">
|
||||
/// A <see cref="ushort" /> value containing the stream
|
||||
/// number of the new instance.
|
||||
/// </param>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// new instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="ByteVector" /> object containing the value
|
||||
/// for the new instance.
|
||||
/// </param>
|
||||
public DescriptionRecord (ushort languageListIndex, ushort streamNumber, string name, ByteVector value)
|
||||
{
|
||||
LanguageListIndex = languageListIndex;
|
||||
StreamNumber = streamNumber;
|
||||
Name = name;
|
||||
Type = DataType.Bytes;
|
||||
byteValue = new ByteVector (value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="DescriptionRecord" /> with a specified language,
|
||||
/// stream, name, and value.
|
||||
/// </summary>
|
||||
/// <param name="languageListIndex">
|
||||
/// A <see cref="ushort" /> value containing the language
|
||||
/// list index of the new instance.
|
||||
/// </param>
|
||||
/// <param name="streamNumber">
|
||||
/// A <see cref="ushort" /> value containing the stream
|
||||
/// number of the new instance.
|
||||
/// </param>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// new instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="uint" /> value containing the value
|
||||
/// for the new instance.
|
||||
/// </param>
|
||||
public DescriptionRecord (ushort languageListIndex, ushort streamNumber, string name, uint value)
|
||||
{
|
||||
LanguageListIndex = languageListIndex;
|
||||
StreamNumber = streamNumber;
|
||||
Name = name;
|
||||
Type = DataType.DWord;
|
||||
longValue = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="DescriptionRecord" /> with a specified language,
|
||||
/// stream, name, and value.
|
||||
/// </summary>
|
||||
/// <param name="languageListIndex">
|
||||
/// A <see cref="ushort" /> value containing the language
|
||||
/// list index of the new instance.
|
||||
/// </param>
|
||||
/// <param name="streamNumber">
|
||||
/// A <see cref="ushort" /> value containing the stream
|
||||
/// number of the new instance.
|
||||
/// </param>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// new instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="ulong" /> value containing the value
|
||||
/// for the new instance.
|
||||
/// </param>
|
||||
public DescriptionRecord (ushort languageListIndex, ushort streamNumber, string name, ulong value)
|
||||
{
|
||||
LanguageListIndex = languageListIndex;
|
||||
StreamNumber = streamNumber;
|
||||
Name = name;
|
||||
Type = DataType.QWord;
|
||||
longValue = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="DescriptionRecord" /> with a specified language,
|
||||
/// stream, name, and value.
|
||||
/// </summary>
|
||||
/// <param name="languageListIndex">
|
||||
/// A <see cref="ushort" /> value containing the language
|
||||
/// list index of the new instance.
|
||||
/// </param>
|
||||
/// <param name="streamNumber">
|
||||
/// A <see cref="ushort" /> value containing the stream
|
||||
/// number of the new instance.
|
||||
/// </param>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// new instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="ushort" /> value containing the value
|
||||
/// for the new instance.
|
||||
/// </param>
|
||||
public DescriptionRecord (ushort languageListIndex, ushort streamNumber, string name, ushort value)
|
||||
{
|
||||
LanguageListIndex = languageListIndex;
|
||||
StreamNumber = streamNumber;
|
||||
Name = name;
|
||||
Type = DataType.Word;
|
||||
longValue = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="DescriptionRecord" /> with a specified language,
|
||||
/// stream, name, and value.
|
||||
/// </summary>
|
||||
/// <param name="languageListIndex">
|
||||
/// A <see cref="ushort" /> value containing the language
|
||||
/// list index of the new instance.
|
||||
/// </param>
|
||||
/// <param name="streamNumber">
|
||||
/// A <see cref="ushort" /> value containing the stream
|
||||
/// number of the new instance.
|
||||
/// </param>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// new instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="bool" /> value containing the value
|
||||
/// for the new instance.
|
||||
/// </param>
|
||||
public DescriptionRecord (ushort languageListIndex, ushort streamNumber, string name, bool value)
|
||||
{
|
||||
LanguageListIndex = languageListIndex;
|
||||
StreamNumber = streamNumber;
|
||||
Name = name;
|
||||
Type = DataType.Bool;
|
||||
longValue = value ? 1uL : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="DescriptionRecord" /> with a specified language,
|
||||
/// stream, name, and value.
|
||||
/// </summary>
|
||||
/// <param name="languageListIndex">
|
||||
/// A <see cref="ushort" /> value containing the language
|
||||
/// list index of the new instance.
|
||||
/// </param>
|
||||
/// <param name="streamNumber">
|
||||
/// A <see cref="ushort" /> value containing the stream
|
||||
/// number of the new instance.
|
||||
/// </param>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// new instance.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// A <see cref="System.Guid" /> value containing the value
|
||||
/// for the new instance.
|
||||
/// </param>
|
||||
public DescriptionRecord (ushort languageListIndex, ushort streamNumber, string name, System.Guid value)
|
||||
{
|
||||
LanguageListIndex = languageListIndex;
|
||||
StreamNumber = streamNumber;
|
||||
Name = name;
|
||||
Type = DataType.Guid;
|
||||
guidValue = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="DescriptionRecord" /> by reading its contents from
|
||||
/// a file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object to read the raw ASF
|
||||
/// Description Record from.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// A valid record could not be read.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// <paramref name="file" /> must be at a seek position at
|
||||
/// which the record can be read.
|
||||
/// </remarks>
|
||||
protected internal DescriptionRecord (File file)
|
||||
{
|
||||
if (file == null)
|
||||
throw new ArgumentNullException (nameof (file));
|
||||
|
||||
if (!Parse (file))
|
||||
throw new CorruptFileException ("Failed to parse description record.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the index of the language associated with the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ushort" /> value containing the index of the
|
||||
/// language associated with the current instance.
|
||||
/// </value>
|
||||
public ushort LanguageListIndex { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the index of the stream associated with the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ushort" /> value containing the index of the
|
||||
/// stream associated with the current instance.
|
||||
/// </value>
|
||||
public ushort StreamNumber { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// current instance.
|
||||
/// </value>
|
||||
public string Name { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of data contained in the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="DataType" /> value indicating type of data
|
||||
/// contained in the current instance.
|
||||
/// </value>
|
||||
public DataType Type { get; private set; } = DataType.Unicode;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string representation of the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="string" /> object containing the value of
|
||||
/// the current instance.
|
||||
/// </returns>
|
||||
public override string ToString ()
|
||||
{
|
||||
if (Type == DataType.Unicode)
|
||||
return strValue;
|
||||
|
||||
if (Type == DataType.Bytes)
|
||||
return byteValue.ToString (StringType.UTF16LE);
|
||||
|
||||
return longValue.ToString ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the binary contents of the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// contents of the current instance, or <see langword="null"
|
||||
/// /> if <see cref="Type" /> is unequal to <see
|
||||
/// cref="DataType.Bytes" />.
|
||||
/// </returns>
|
||||
public ByteVector ToByteVector ()
|
||||
{
|
||||
return byteValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the boolean value contained in the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="bool" /> value containing the value of the
|
||||
/// current instance.
|
||||
/// </returns>
|
||||
public bool ToBool ()
|
||||
{
|
||||
return longValue != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the DWORD value contained in the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="uint" /> value containing the value of the
|
||||
/// current instance.
|
||||
/// </returns>
|
||||
public uint ToDWord ()
|
||||
{
|
||||
if (Type == DataType.Unicode && strValue != null && uint.TryParse (strValue, out var value))
|
||||
return value;
|
||||
|
||||
return (uint)longValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the QWORD value contained in the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ulong" /> value containing the value of the
|
||||
/// current instance.
|
||||
/// </returns>
|
||||
public ulong ToQWord ()
|
||||
{
|
||||
if (Type == DataType.Unicode && strValue != null && ulong.TryParse (strValue, out var value))
|
||||
return value;
|
||||
|
||||
return longValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the WORD value contained in the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ushort" /> value containing the value of the
|
||||
/// current instance.
|
||||
/// </returns>
|
||||
public ushort ToWord ()
|
||||
{
|
||||
if (Type == DataType.Unicode && strValue != null && ushort.TryParse (strValue, out var value))
|
||||
return value;
|
||||
|
||||
return (ushort)longValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the GUID value contained in the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="System.Guid" /> value containing the value
|
||||
/// of the current instance.
|
||||
/// </returns>
|
||||
public System.Guid ToGuid ()
|
||||
{
|
||||
return guidValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ASF Description
|
||||
/// Record.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public ByteVector Render ()
|
||||
{
|
||||
ByteVector value;
|
||||
|
||||
switch (Type) {
|
||||
case DataType.Unicode:
|
||||
value = Object.RenderUnicode (strValue);
|
||||
break;
|
||||
case DataType.Bytes:
|
||||
value = byteValue;
|
||||
break;
|
||||
case DataType.Bool:
|
||||
case DataType.DWord:
|
||||
value = Object.RenderDWord ((uint)longValue);
|
||||
break;
|
||||
case DataType.QWord:
|
||||
value = Object.RenderQWord (longValue);
|
||||
break;
|
||||
case DataType.Word:
|
||||
value = Object.RenderWord ((ushort)longValue);
|
||||
break;
|
||||
case DataType.Guid:
|
||||
value = guidValue.ToByteArray ();
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
ByteVector name = Object.RenderUnicode (Name);
|
||||
|
||||
var output = new ByteVector {
|
||||
Object.RenderWord (LanguageListIndex),
|
||||
Object.RenderWord (StreamNumber),
|
||||
Object.RenderWord ((ushort)name.Count),
|
||||
Object.RenderWord ((ushort)Type),
|
||||
Object.RenderDWord ((uint)value.Count),
|
||||
name,
|
||||
value
|
||||
};
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Populates the current instance by reading in the contents
|
||||
/// from a file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object to read the raw ASF
|
||||
/// Description Record from.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if the data was read correctly.
|
||||
/// Otherwise <see langword="false" />.
|
||||
/// </returns>
|
||||
protected bool Parse (File file)
|
||||
{
|
||||
// Field name Field type Size (bits)
|
||||
// Language List Index WORD 16
|
||||
// Stream Number WORD 16
|
||||
// Name Length WORD 16
|
||||
// Data Type WORD 16
|
||||
// Data Length DWORD 32
|
||||
// Name WCHAR varies
|
||||
// Data See below varies
|
||||
|
||||
LanguageListIndex = file.ReadWord ();
|
||||
StreamNumber = file.ReadWord ();
|
||||
ushort name_length = file.ReadWord ();
|
||||
Type = (DataType)file.ReadWord ();
|
||||
int data_length = (int)file.ReadDWord ();
|
||||
Name = file.ReadUnicode (name_length);
|
||||
|
||||
switch (Type) {
|
||||
case DataType.Word:
|
||||
longValue = file.ReadWord ();
|
||||
break;
|
||||
case DataType.Bool:
|
||||
case DataType.DWord:
|
||||
longValue = file.ReadDWord ();
|
||||
break;
|
||||
case DataType.QWord:
|
||||
longValue = file.ReadQWord ();
|
||||
break;
|
||||
case DataType.Unicode:
|
||||
strValue = file.ReadUnicode (data_length);
|
||||
break;
|
||||
case DataType.Bytes:
|
||||
byteValue = file.ReadBlock (data_length);
|
||||
break;
|
||||
case DataType.Guid:
|
||||
guidValue = file.ReadGuid ();
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b240cea38450eb09286babb6fd6d82c7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,270 @@
|
||||
//
|
||||
// ExtendedContentDescriptionObject.cs: Provides a representation of an ASF
|
||||
// Extended Content Description object which can be read from and written to
|
||||
// disk.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Object" /> to provide a
|
||||
/// representation of an ASF Extended Content Description object
|
||||
/// which can be read from and written to disk.
|
||||
/// </summary>
|
||||
public class ExtendedContentDescriptionObject : Object, IEnumerable<ContentDescriptor>
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the content descriptors.
|
||||
/// </summary>
|
||||
readonly List<ContentDescriptor> descriptors = new List<ContentDescriptor> ();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ExtendedContentDescriptionObject" /> by reading the
|
||||
/// contents from a specified position in a specified file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object containing the file from
|
||||
/// which the contents of the new instance are to be read.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specify at what position to
|
||||
/// read the object.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="position" /> is less than zero or greater
|
||||
/// than the size of the file.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// The object read from disk does not have the correct GUID
|
||||
/// or smaller than the minimum size.
|
||||
/// </exception>
|
||||
public ExtendedContentDescriptionObject (File file, long position)
|
||||
: base (file, position)
|
||||
{
|
||||
if (!Guid.Equals (Asf.Guid.AsfExtendedContentDescriptionObject))
|
||||
throw new CorruptFileException ("Object GUID incorrect.");
|
||||
|
||||
if (OriginalSize < 26)
|
||||
throw new CorruptFileException ("Object size too small.");
|
||||
|
||||
ushort count = file.ReadWord ();
|
||||
|
||||
for (ushort i = 0; i < count; i++)
|
||||
AddDescriptor (new ContentDescriptor (file));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ExtendedContentDescriptionObject" /> with no
|
||||
/// contents.
|
||||
/// </summary>
|
||||
public ExtendedContentDescriptionObject ()
|
||||
: base (Asf.Guid.AsfExtendedContentDescriptionObject)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not the current instance is empty.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <see langword="true" /> if the current instance doesn't
|
||||
/// contain any <see cref="ContentDescriptor" /> objects.
|
||||
/// Otherwise <see langword="false" />.
|
||||
/// </value>
|
||||
public bool IsEmpty {
|
||||
get { return descriptors.Count == 0; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ASF object.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public override ByteVector Render ()
|
||||
{
|
||||
ByteVector output = new ByteVector ();
|
||||
ushort count = 0;
|
||||
|
||||
foreach (ContentDescriptor desc in descriptors) {
|
||||
count++;
|
||||
output.Add (desc.Render ());
|
||||
}
|
||||
|
||||
return Render (RenderWord (count) + output);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all descriptors with a given name from the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// descriptors to be removed.
|
||||
/// </param>
|
||||
public void RemoveDescriptors (string name)
|
||||
{
|
||||
for (int i = descriptors.Count - 1; i >= 0; i--)
|
||||
if (name == descriptors[i].Name)
|
||||
descriptors.RemoveAt (i);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all descriptors with any of a collection of names
|
||||
/// from the current instance.
|
||||
/// </summary>
|
||||
/// <param name="names">
|
||||
/// A <see cref="T:string[]" /> containing the names of the
|
||||
/// descriptors to be retrieved.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="names" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <returns>
|
||||
/// A <see cref="T:System.Collections.Generic.IEnumerable`1" /> object enumerating
|
||||
/// through the <see cref="ContentDescriptor" /> objects
|
||||
/// retrieved from the current instance.
|
||||
/// </returns>
|
||||
public IEnumerable<ContentDescriptor> GetDescriptors (params string[] names)
|
||||
{
|
||||
if (names == null)
|
||||
throw new ArgumentNullException (nameof (names));
|
||||
|
||||
foreach (string name in names)
|
||||
foreach (ContentDescriptor desc in descriptors)
|
||||
if (desc.Name == name)
|
||||
yield return desc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a descriptor to the current instance.
|
||||
/// </summary>
|
||||
/// <param name="descriptor">
|
||||
/// A <see cref="ContentDescriptor" /> object to add to the
|
||||
/// current instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="descriptor" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public void AddDescriptor (ContentDescriptor descriptor)
|
||||
{
|
||||
if (descriptor == null)
|
||||
throw new ArgumentNullException (nameof (descriptor));
|
||||
|
||||
descriptors.Add (descriptor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the a collection of desciptors for a given name,
|
||||
/// removing the existing matching records.
|
||||
/// </summary>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// descriptors to be added.
|
||||
/// </param>
|
||||
/// <param name="descriptors">
|
||||
/// A <see cref="T:ContentDescriptor[]" /> containing
|
||||
/// descriptors to add to the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="name" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// All added entries in <paramref name="descriptors" />
|
||||
/// should match <paramref name="name" /> but it is not
|
||||
/// verified by the method. The descriptors will be added
|
||||
/// with their own names and not the one provided in this
|
||||
/// method, which are used for removing existing values and
|
||||
/// determining where to position the new objects.
|
||||
/// </remarks>
|
||||
public void SetDescriptors (string name, params ContentDescriptor[] descriptors)
|
||||
{
|
||||
if (name == null)
|
||||
throw new ArgumentNullException (nameof (name));
|
||||
|
||||
int position = this.descriptors.Count;
|
||||
for (int i = this.descriptors.Count - 1; i >= 0; i--) {
|
||||
if (name == this.descriptors[i].Name) {
|
||||
this.descriptors.RemoveAt (i);
|
||||
position = i;
|
||||
}
|
||||
}
|
||||
this.descriptors.InsertRange (position, descriptors);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region IEnumerable
|
||||
|
||||
/// <summary>
|
||||
/// Gets an enumerator for enumerating through the content
|
||||
/// descriptors.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="T:System.Collections.IEnumerator`1" /> for
|
||||
/// enumerating through the content descriptors.
|
||||
/// </returns>
|
||||
public IEnumerator<ContentDescriptor> GetEnumerator ()
|
||||
{
|
||||
return descriptors.GetEnumerator ();
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator
|
||||
System.Collections.IEnumerable.GetEnumerator ()
|
||||
{
|
||||
return descriptors.GetEnumerator ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d284fb627fd9b464a993ff8f4769b52c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,436 @@
|
||||
//
|
||||
// File.cs: Provides tagging and properties support for Microsoft's ASF files.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="TagLib.File" /> to provide tagging
|
||||
/// and properties support for Microsoft's ASF files.
|
||||
/// </summary>
|
||||
[SupportedMimeType ("taglib/wma", "wma")]
|
||||
[SupportedMimeType ("taglib/wmv", "wmv")]
|
||||
[SupportedMimeType ("taglib/asf", "asf")]
|
||||
[SupportedMimeType ("audio/x-ms-wma")]
|
||||
[SupportedMimeType ("audio/x-ms-asf")]
|
||||
[SupportedMimeType ("video/x-ms-asf")]
|
||||
public class File : TagLib.File
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the file's tag.
|
||||
/// </summary>
|
||||
Tag asf_tag;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the file's properties.
|
||||
/// </summary>
|
||||
Properties properties;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local file
|
||||
/// system and specified read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path, ReadStyle propertiesStyle)
|
||||
: base (path)
|
||||
{
|
||||
Read (propertiesStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local file
|
||||
/// system with an average read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path)
|
||||
: this (path, ReadStyle.Average)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction and
|
||||
/// specified read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction, ReadStyle propertiesStyle)
|
||||
: base (abstraction)
|
||||
{
|
||||
Read (propertiesStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction with an
|
||||
/// average read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction)
|
||||
: this (abstraction, ReadStyle.Average)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets a abstract representation of all tags stored in the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TagLib.Tag" /> object representing all tags
|
||||
/// stored in the current instance.
|
||||
/// </value>
|
||||
public override TagLib.Tag Tag {
|
||||
get { return asf_tag; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the media properties of the file represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TagLib.Properties" /> object containing the
|
||||
/// media properties of the file represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public override Properties Properties {
|
||||
get { return properties; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Saves the changes made in the current instance to the
|
||||
/// file it represents.
|
||||
/// </summary>
|
||||
public override void Save ()
|
||||
{
|
||||
// Boilerplate
|
||||
PreSave ();
|
||||
|
||||
Mode = AccessMode.Write;
|
||||
try {
|
||||
var header = new HeaderObject (this, 0);
|
||||
|
||||
if (asf_tag == null) {
|
||||
header.RemoveContentDescriptors ();
|
||||
TagTypesOnDisk &= ~TagTypes.Asf;
|
||||
} else {
|
||||
TagTypesOnDisk |= TagTypes.Asf;
|
||||
header.AddUniqueObject (
|
||||
asf_tag.ContentDescriptionObject);
|
||||
header.AddUniqueObject (
|
||||
asf_tag.ExtendedContentDescriptionObject);
|
||||
header.Extension.AddUniqueObject (
|
||||
asf_tag.MetadataLibraryObject);
|
||||
}
|
||||
|
||||
var output = header.Render ();
|
||||
long diff = output.Count - (long)header.OriginalSize;
|
||||
Insert (output, 0, (long)header.OriginalSize);
|
||||
|
||||
InvariantStartPosition += diff;
|
||||
InvariantEndPosition += diff;
|
||||
} finally {
|
||||
Mode = AccessMode.Closed;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a tag of a specified type from the current instance,
|
||||
/// optionally creating a new tag if possible.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="TagLib.TagTypes" /> value indicating the
|
||||
/// type of tag to read.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> value specifying whether or not to
|
||||
/// try and create the tag if one is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="Tag" /> object containing the tag that was
|
||||
/// found in or added to the current instance. If no
|
||||
/// matching tag was found and none was created, <see
|
||||
/// langword="null" /> is returned.
|
||||
/// </returns>
|
||||
public override TagLib.Tag GetTag (TagTypes type, bool create)
|
||||
{
|
||||
if (type == TagTypes.Asf)
|
||||
return asf_tag;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a set of tag types from the current instance.
|
||||
/// </summary>
|
||||
/// <param name="types">
|
||||
/// A bitwise combined <see cref="TagLib.TagTypes" /> value
|
||||
/// containing tag types to be removed from the file.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// In order to remove all tags from a file, pass <see
|
||||
/// cref="TagTypes.AllTags" /> as <paramref name="types" />.
|
||||
/// </remarks>
|
||||
public override void RemoveTags (TagTypes types)
|
||||
{
|
||||
if ((types & TagTypes.Asf) == TagTypes.Asf)
|
||||
asf_tag.Clear ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 2-byte WORD from the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ushort" /> value containing the WORD read
|
||||
/// from the current instance.
|
||||
/// </returns>
|
||||
public ushort ReadWord ()
|
||||
{
|
||||
return ReadBlock (2).ToUShort (false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 4-byte DWORD from the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="uint" /> value containing the DWORD read
|
||||
/// from the current instance.
|
||||
/// </returns>
|
||||
public uint ReadDWord ()
|
||||
{
|
||||
return ReadBlock (4).ToUInt (false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 8-byte QWORD from the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ulong" /> value containing the QWORD read
|
||||
/// from the current instance.
|
||||
/// </returns>
|
||||
public ulong ReadQWord ()
|
||||
{
|
||||
return ReadBlock (8).ToULong (false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 16-byte GUID from the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="System.Guid" /> value containing the GUID
|
||||
/// read from the current instance.
|
||||
/// </returns>
|
||||
public System.Guid ReadGuid ()
|
||||
{
|
||||
return new System.Guid (ReadBlock (16).Data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a Unicode (UTF-16LE) string of specified length
|
||||
/// from the current instance.
|
||||
/// </summary>
|
||||
/// <param name="length">
|
||||
/// A <see cref="int" /> value specifying the number of bytes
|
||||
/// to read. This should always be an even number.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="string" /> object containing the Unicode
|
||||
/// string read from the current instance.
|
||||
/// </returns>
|
||||
public string ReadUnicode (int length)
|
||||
{
|
||||
ByteVector data = ReadBlock (length);
|
||||
string output = data.ToString (StringType.UTF16LE);
|
||||
int i = output.IndexOf ('\0');
|
||||
return (i >= 0) ? output.Substring (0, i) : output;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a collection of objects from the current instance.
|
||||
/// </summary>
|
||||
/// <param name="count">
|
||||
/// A <see cref="uint" /> value specifying the number of
|
||||
/// objects to read.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specifying the seek position
|
||||
/// at which to start reading.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A new <see cref="T:System.Collections.Generic.IEnumerable`1" /> object enumerating
|
||||
/// through the <see cref="Object" /> objects read from the
|
||||
/// current instance.
|
||||
/// </returns>
|
||||
public IEnumerable<Object> ReadObjects (uint count,
|
||||
long position)
|
||||
{
|
||||
for (int i = 0; i < (int)count; i++) {
|
||||
Object obj = ReadObject (position);
|
||||
position += (long)obj.OriginalSize;
|
||||
yield return obj;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a <see cref="Object" /> from the current instance.
|
||||
/// </summary>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specifying the seek position
|
||||
/// at which to start reading.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A new <see cref="Object" /> object of appropriate type as
|
||||
/// read from the current instance.
|
||||
/// </returns>
|
||||
public Object ReadObject (long position)
|
||||
{
|
||||
Seek (position);
|
||||
System.Guid id = ReadGuid ();
|
||||
|
||||
if (id.Equals (Guid.AsfFilePropertiesObject))
|
||||
return new FilePropertiesObject (this,
|
||||
position);
|
||||
|
||||
if (id.Equals (Guid.AsfStreamPropertiesObject))
|
||||
return new StreamPropertiesObject (this,
|
||||
position);
|
||||
|
||||
if (id.Equals (Guid.AsfContentDescriptionObject))
|
||||
return new ContentDescriptionObject (this,
|
||||
position);
|
||||
|
||||
if (id.Equals (
|
||||
Guid.AsfExtendedContentDescriptionObject))
|
||||
return new ExtendedContentDescriptionObject (
|
||||
this, position);
|
||||
|
||||
if (id.Equals (Guid.AsfPaddingObject))
|
||||
return new PaddingObject (this, position);
|
||||
|
||||
if (id.Equals (Guid.AsfHeaderExtensionObject))
|
||||
return new HeaderExtensionObject (this,
|
||||
position);
|
||||
|
||||
if (id.Equals (Guid.AsfMetadataLibraryObject))
|
||||
return new MetadataLibraryObject (this,
|
||||
position);
|
||||
|
||||
return new UnknownObject (this, position);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Reads the contents of the current instance.
|
||||
/// </summary>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
void Read (ReadStyle propertiesStyle)
|
||||
{
|
||||
Mode = AccessMode.Read;
|
||||
try {
|
||||
HeaderObject header = new HeaderObject (this, 0);
|
||||
|
||||
if (header.HasContentDescriptors)
|
||||
TagTypesOnDisk |= TagTypes.Asf;
|
||||
|
||||
asf_tag = new Tag (header);
|
||||
|
||||
InvariantStartPosition = (long)header.OriginalSize;
|
||||
InvariantEndPosition = Length;
|
||||
|
||||
if ((propertiesStyle & ReadStyle.Average) != 0)
|
||||
properties = header.Properties;
|
||||
} finally {
|
||||
Mode = AccessMode.Closed;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 230597e1f22d7c4048805f50836d30b1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,275 @@
|
||||
//
|
||||
// FilePropertiesObject.cs: Provides a representation of an ASF File Properties
|
||||
// object which can be read from and written to disk.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Object" /> to provide a
|
||||
/// representation of an ASF File Properties object which can be read
|
||||
/// from and written to disk.
|
||||
/// </summary>
|
||||
public class FilePropertiesObject : Object
|
||||
{
|
||||
#region Constant Values
|
||||
|
||||
static readonly DateTime FileTimeOffset = new DateTime (1601, 1, 1);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the GUID for the file.
|
||||
/// </summary>
|
||||
System.Guid file_id;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the creation date.
|
||||
/// </summary>
|
||||
readonly ulong creation_date;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the play duration.
|
||||
/// </summary>
|
||||
readonly ulong play_duration;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the send duration.
|
||||
/// </summary>
|
||||
readonly ulong send_duration;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="FilePropertiesObject" /> by reading the contents
|
||||
/// from a specified position in a specified file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object containing the file from
|
||||
/// which the contents of the new instance are to be read.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specify at what position to
|
||||
/// read the object.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="position" /> is less than zero or greater
|
||||
/// than the size of the file.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// The object read from disk does not have the correct GUID
|
||||
/// or smaller than the minimum size.
|
||||
/// </exception>
|
||||
public FilePropertiesObject (File file, long position)
|
||||
: base (file, position)
|
||||
{
|
||||
if (!Guid.Equals (Asf.Guid.AsfFilePropertiesObject))
|
||||
throw new CorruptFileException ("Object GUID incorrect.");
|
||||
|
||||
if (OriginalSize < 104)
|
||||
throw new CorruptFileException ("Object size too small.");
|
||||
|
||||
file_id = file.ReadGuid ();
|
||||
FileSize = file.ReadQWord ();
|
||||
creation_date = file.ReadQWord ();
|
||||
DataPacketsCount = file.ReadQWord ();
|
||||
play_duration = file.ReadQWord ();
|
||||
send_duration = file.ReadQWord ();
|
||||
Preroll = file.ReadQWord ();
|
||||
Flags = file.ReadDWord ();
|
||||
MinimumDataPacketSize = file.ReadDWord ();
|
||||
MaximumDataPacketSize = file.ReadDWord ();
|
||||
MaximumBitrate = file.ReadDWord ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the GUID for the file described by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="System.Guid" /> value containing the GUID
|
||||
/// for the file described by the current instance.
|
||||
/// </value>
|
||||
public System.Guid FileId {
|
||||
get { return file_id; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the file described by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ulong" /> value containing the size of the
|
||||
/// file described by the current instance.
|
||||
/// </value>
|
||||
public ulong FileSize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the creation date of the file described by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="DateTime" /> value containing the creation
|
||||
/// date of the file described by the current instance.
|
||||
/// </value>
|
||||
public DateTime CreationDate {
|
||||
get { return new DateTime ((long)creation_date + FileTimeOffset.Ticks); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of data packets in the file described by
|
||||
/// the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ulong" /> value containing the number of
|
||||
/// data packets in the file described by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public ulong DataPacketsCount { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the play duration of the file described by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TimeSpan" /> value containing the play
|
||||
/// duration of the file described by the current instance.
|
||||
/// </value>
|
||||
public TimeSpan PlayDuration {
|
||||
get { return new TimeSpan ((long)play_duration); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the send duration of the file described by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TimeSpan" /> value containing the send
|
||||
/// duration of the file described by the current instance.
|
||||
/// </value>
|
||||
public TimeSpan SendDuration {
|
||||
get { return new TimeSpan ((long)send_duration); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the pre-roll of the file described by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ulong" /> value containing the pre-roll of
|
||||
/// the file described by the current instance.
|
||||
/// </value>
|
||||
public ulong Preroll { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the flags of the file described by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the flags of the
|
||||
/// file described by the current instance.
|
||||
/// </value>
|
||||
public uint Flags { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the minimum data packet size of the file described
|
||||
/// by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the minimum data
|
||||
/// packet size of the file described by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public uint MinimumDataPacketSize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum data packet size of the file described
|
||||
/// by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the maximum data
|
||||
/// packet size of the file described by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public uint MaximumDataPacketSize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum bitrate of the file described by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="uint" /> value containing the maximum
|
||||
/// bitrate of the file described by the current instance.
|
||||
/// </value>
|
||||
public uint MaximumBitrate { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ASF object.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public override ByteVector Render ()
|
||||
{
|
||||
ByteVector output = file_id.ToByteArray ();
|
||||
output.Add (RenderQWord (FileSize));
|
||||
output.Add (RenderQWord (creation_date));
|
||||
output.Add (RenderQWord (DataPacketsCount));
|
||||
output.Add (RenderQWord (play_duration));
|
||||
output.Add (RenderQWord (send_duration));
|
||||
output.Add (RenderQWord (Preroll));
|
||||
output.Add (RenderDWord (Flags));
|
||||
output.Add (RenderDWord (MinimumDataPacketSize));
|
||||
output.Add (RenderDWord (MaximumDataPacketSize));
|
||||
output.Add (RenderDWord (MaximumBitrate));
|
||||
|
||||
return Render (output);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aadef2fcac80345fe8d8d585ba22aed5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,110 @@
|
||||
//
|
||||
// Guid.cs: Provides common GUID values used by ASF Objects.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// This static class contains common <see cref="System.Guid" />
|
||||
/// values used by ASF Objects.
|
||||
/// </summary>
|
||||
public static class Guid
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that an object is a <see
|
||||
/// cref="ContentDescriptionObject" />.
|
||||
/// </summary>
|
||||
public static readonly System.Guid AsfContentDescriptionObject =
|
||||
new System.Guid ("75B22633-668E-11CF-A6D9-00AA0062CE6C");
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that an object is a <see
|
||||
/// cref="ExtendedContentDescriptionObject" />.
|
||||
/// </summary>
|
||||
public static readonly System.Guid AsfExtendedContentDescriptionObject =
|
||||
new System.Guid ("D2D0A440-E307-11D2-97F0-00A0C95EA850");
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that an object is a <see
|
||||
/// cref="FilePropertiesObject" />.
|
||||
/// </summary>
|
||||
public static readonly System.Guid AsfFilePropertiesObject =
|
||||
new System.Guid ("8CABDCA1-A947-11CF-8EE4-00C00C205365");
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that an object is a <see
|
||||
/// cref="HeaderExtensionObject" />.
|
||||
/// </summary>
|
||||
public static readonly System.Guid AsfHeaderExtensionObject =
|
||||
new System.Guid ("5FBF03B5-A92E-11CF-8EE3-00C00C205365");
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that an object is a <see
|
||||
/// cref="HeaderObject" />.
|
||||
/// </summary>
|
||||
public static readonly System.Guid AsfHeaderObject =
|
||||
new System.Guid ("75B22630-668E-11CF-A6D9-00AA0062CE6C");
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that an object is a <see
|
||||
/// cref="MetadataLibraryObject" />.
|
||||
/// </summary>
|
||||
public static readonly System.Guid AsfMetadataLibraryObject =
|
||||
new System.Guid ("44231C94-9498-49D1-A141-1D134E457054");
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that an object is a <see
|
||||
/// cref="PaddingObject" />.
|
||||
/// </summary>
|
||||
public static readonly System.Guid AsfPaddingObject =
|
||||
new System.Guid ("1806D474-CADF-4509-A4BA-9AABCB96AAE8");
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that an object is a <see
|
||||
/// cref="StreamPropertiesObject" />.
|
||||
/// </summary>
|
||||
public static readonly System.Guid AsfStreamPropertiesObject =
|
||||
new System.Guid ("B7DC0791-A9B7-11CF-8EE6-00C00C205365");
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that a <see cref="StreamPropertiesObject" />
|
||||
/// contains information about an audio stream.
|
||||
/// </summary>
|
||||
public static readonly System.Guid AsfAudioMedia =
|
||||
new System.Guid ("F8699E40-5B4D-11CF-A8FD-00805F5C442B");
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that a <see cref="StreamPropertiesObject" />
|
||||
/// contains information about an video stream.
|
||||
/// </summary>
|
||||
public static readonly System.Guid AsfVideoMedia =
|
||||
new System.Guid ("BC19EFC0-5B4D-11CF-A8FD-00805F5C442B");
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a placeholder portion of a file is correctly
|
||||
/// encoded.
|
||||
/// </summary>
|
||||
public static readonly System.Guid AsfReserved1 =
|
||||
new System.Guid ("ABD3D211-A9BA-11cf-8EE6-00C00C205365");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 106d81de03690f00d9a5574b209c688b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,174 @@
|
||||
//
|
||||
// HeaderExtensionObject.cs: Provides a representation of an ASF Header
|
||||
// Extension object which can be read from and written to disk.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Object" /> to provide a
|
||||
/// representation of an ASF Header Extension object which can be
|
||||
/// read from and written to disk.
|
||||
/// </summary>
|
||||
public class HeaderExtensionObject : Object
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the child objects.
|
||||
/// </summary>
|
||||
readonly List<Object> children = new List<Object> ();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="HeaderExtensionObject" /> by reading the contents
|
||||
/// from a specified position in a specified file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object containing the file from
|
||||
/// which the contents of the new instance are to be read.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specify at what position to
|
||||
/// read the object.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="position" /> is less than zero or greater
|
||||
/// than the size of the file.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// The object read from disk does not have the correct GUID
|
||||
/// or contents.
|
||||
/// </exception>
|
||||
public HeaderExtensionObject (File file, long position)
|
||||
: base (file, position)
|
||||
{
|
||||
if (!Guid.Equals (Asf.Guid.AsfHeaderExtensionObject))
|
||||
throw new CorruptFileException ("Object GUID incorrect.");
|
||||
|
||||
if (file.ReadGuid () != Asf.Guid.AsfReserved1)
|
||||
throw new CorruptFileException ("Reserved1 GUID expected.");
|
||||
|
||||
if (file.ReadWord () != 6)
|
||||
throw new CorruptFileException ("Invalid reserved WORD. Expected '6'.");
|
||||
|
||||
uint size_remaining = file.ReadDWord ();
|
||||
position += 0x170 / 8;
|
||||
|
||||
while (size_remaining > 0) {
|
||||
Object obj = file.ReadObject (position);
|
||||
position += (long)obj.OriginalSize;
|
||||
size_remaining -= (uint)obj.OriginalSize;
|
||||
children.Add (obj);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the child objects contained in the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="T:System.Collections.Generic.IEnumerable`1" /> object enumerating
|
||||
/// through the children of the current instance.
|
||||
/// </value>
|
||||
public IEnumerable<Object> Children {
|
||||
get { return children; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ASF object.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public override ByteVector Render ()
|
||||
{
|
||||
ByteVector output = new ByteVector ();
|
||||
|
||||
foreach (var child in children)
|
||||
output.Add (child.Render ());
|
||||
|
||||
output.Insert (0, RenderDWord ((uint)output.Count));
|
||||
output.Insert (0, RenderWord (6));
|
||||
output.Insert (0, Asf.Guid.AsfReserved1.ToByteArray ());
|
||||
|
||||
return Render (output);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a child object to the current instance.
|
||||
/// </summary>
|
||||
/// <param name="obj">
|
||||
/// A <see cref="Object" /> object to add to the current
|
||||
/// instance.
|
||||
/// </param>
|
||||
public void AddObject (Object obj)
|
||||
{
|
||||
children.Add (obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a child unique child object to the current instance,
|
||||
/// replacing and existing child if present.
|
||||
/// </summary>
|
||||
/// <param name="obj">
|
||||
/// A <see cref="Object" /> object to add to the current
|
||||
/// instance.
|
||||
/// </param>
|
||||
public void AddUniqueObject (Object obj)
|
||||
{
|
||||
for (int i = 0; i < children.Count; i++)
|
||||
if (children[i].Guid == obj.Guid) {
|
||||
children[i] = obj;
|
||||
return;
|
||||
}
|
||||
|
||||
children.Add (obj);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc8a5039b8de0c71c9af979086ce9378
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,265 @@
|
||||
//
|
||||
// HeaderObject.cs: Provides a representation of an ASF Header object which can
|
||||
// be read from and written to disk.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Object" /> to provide a
|
||||
/// representation of an ASF Header object which can be read from and
|
||||
/// written to disk.
|
||||
/// </summary>
|
||||
public class HeaderObject : Object
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the reserved header data.
|
||||
/// </summary>
|
||||
readonly ByteVector reserved;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the child objects.
|
||||
/// </summary>
|
||||
readonly List<Object> children;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="HeaderObject" /> by reading the contents from a
|
||||
/// specified position in a specified file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object containing the file from
|
||||
/// which the contents of the new instance are to be read.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specify at what position to
|
||||
/// read the object.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="position" /> is less than zero or greater
|
||||
/// than the size of the file.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// The object read from disk does not have the correct GUID
|
||||
/// or smaller than the minimum size.
|
||||
/// </exception>
|
||||
public HeaderObject (File file, long position)
|
||||
: base (file, position)
|
||||
{
|
||||
if (!Guid.Equals (Asf.Guid.AsfHeaderObject))
|
||||
throw new CorruptFileException ("Object GUID incorrect.");
|
||||
|
||||
if (OriginalSize < 26)
|
||||
throw new CorruptFileException ("Object size too small.");
|
||||
|
||||
children = new List<Object> ();
|
||||
|
||||
uint child_count = file.ReadDWord ();
|
||||
|
||||
reserved = file.ReadBlock (2);
|
||||
|
||||
children.AddRange (file.ReadObjects (child_count,
|
||||
file.Tell));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the header extension object contained in the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="HeaderExtensionObject" /> object containing
|
||||
/// the header extension object.
|
||||
/// </value>
|
||||
public HeaderExtensionObject Extension {
|
||||
get {
|
||||
foreach (Object child in children)
|
||||
if (child is HeaderExtensionObject)
|
||||
return child as HeaderExtensionObject;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the child objects contained in the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="T:System.Collections.Generic.IEnumerable`1" /> object enumerating
|
||||
/// through the children of the current instance.
|
||||
/// </value>
|
||||
public IEnumerable<Object> Children {
|
||||
get { return children; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the media properties contained within the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="Properties" /> object containing the media
|
||||
/// properties of the current instance.
|
||||
/// </value>
|
||||
public Properties Properties {
|
||||
get {
|
||||
TimeSpan duration = TimeSpan.Zero;
|
||||
var codecs = new List<ICodec> ();
|
||||
|
||||
foreach (var obj in Children) {
|
||||
if (obj is FilePropertiesObject fpobj) {
|
||||
duration = fpobj.PlayDuration - TimeSpan.FromMilliseconds (fpobj.Preroll);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (obj is StreamPropertiesObject spobj) {
|
||||
codecs.Add (spobj.Codec);
|
||||
}
|
||||
}
|
||||
|
||||
return new Properties (duration, codecs);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not the current instance contains either
|
||||
/// type of content descriptiors.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <see langword="true" /> if the current instance contains
|
||||
/// a <see cref="ContentDescriptionObject" /> or a <see
|
||||
/// cref="ExtendedContentDescriptionObject" />. Otherwise
|
||||
/// <see langword="false" />.
|
||||
/// </value>
|
||||
public bool HasContentDescriptors {
|
||||
get {
|
||||
foreach (Object child in children)
|
||||
if (child.Guid == Asf.Guid.AsfContentDescriptionObject ||
|
||||
child.Guid == Asf.Guid.AsfExtendedContentDescriptionObject)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ASF object.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public override ByteVector Render ()
|
||||
{
|
||||
var output = new ByteVector ();
|
||||
uint child_count = 0;
|
||||
|
||||
foreach (var child in children)
|
||||
if (child.Guid != Asf.Guid.AsfPaddingObject) {
|
||||
output.Add (child.Render ());
|
||||
child_count++;
|
||||
}
|
||||
|
||||
long size_diff = (long)output.Count + 30 -
|
||||
(long)OriginalSize;
|
||||
|
||||
if (size_diff != 0) {
|
||||
var obj = new PaddingObject ((uint)(size_diff > 0 ? 4096 : -size_diff));
|
||||
|
||||
output.Add (obj.Render ());
|
||||
child_count++;
|
||||
}
|
||||
|
||||
output.Insert (0, reserved);
|
||||
output.Insert (0, RenderDWord (child_count));
|
||||
return Render (output);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a child object to the current instance.
|
||||
/// </summary>
|
||||
/// <param name="obj">
|
||||
/// A <see cref="Object" /> object to add to the current
|
||||
/// instance.
|
||||
/// </param>
|
||||
public void AddObject (Object obj)
|
||||
{
|
||||
children.Add (obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a child unique child object to the current instance,
|
||||
/// replacing and existing child if present.
|
||||
/// </summary>
|
||||
/// <param name="obj">
|
||||
/// A <see cref="Object" /> object to add to the current
|
||||
/// instance.
|
||||
/// </param>
|
||||
public void AddUniqueObject (Object obj)
|
||||
{
|
||||
for (int i = 0; i < children.Count; i++)
|
||||
if (children[i].Guid == obj.Guid) {
|
||||
children[i] = obj;
|
||||
return;
|
||||
}
|
||||
|
||||
children.Add (obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the content description objects from the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
public void RemoveContentDescriptors ()
|
||||
{
|
||||
for (int i = children.Count - 1; i >= 0; i--)
|
||||
if (children[i].Guid == Asf.Guid.AsfContentDescriptionObject ||
|
||||
children[i].Guid == Asf.Guid.AsfExtendedContentDescriptionObject)
|
||||
children.RemoveAt (i);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 28f74c9348168792da3d31feb083107a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,288 @@
|
||||
//
|
||||
// MetadataLibraryObject.cs: Provides a representation of an ASF Metadata
|
||||
// Library object which can be read from and written to disk.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Object" /> to provide a
|
||||
/// representation of an ASF Metadata Library object which can be
|
||||
/// read from and written to disk.
|
||||
/// </summary>
|
||||
public class MetadataLibraryObject : Object, IEnumerable<DescriptionRecord>
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the description records.
|
||||
/// </summary>
|
||||
readonly List<DescriptionRecord> records = new List<DescriptionRecord> ();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="MetadataLibraryObject" /> by reading the contents
|
||||
/// from a specified position in a specified file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object containing the file from
|
||||
/// which the contents of the new instance are to be read.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specify at what position to
|
||||
/// read the object.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="position" /> is less than zero or greater
|
||||
/// than the size of the file.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// The object read from disk does not have the correct GUID
|
||||
/// or smaller than the minimum size.
|
||||
/// </exception>
|
||||
public MetadataLibraryObject (File file, long position)
|
||||
: base (file, position)
|
||||
{
|
||||
if (!Guid.Equals (Asf.Guid.AsfMetadataLibraryObject))
|
||||
throw new CorruptFileException ("Object GUID incorrect.");
|
||||
|
||||
if (OriginalSize < 26)
|
||||
throw new CorruptFileException ("Object size too small.");
|
||||
|
||||
ushort count = file.ReadWord ();
|
||||
|
||||
for (ushort i = 0; i < count; i++) {
|
||||
var rec = new DescriptionRecord (file);
|
||||
AddRecord (rec);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="MetadataLibraryObject" /> with no contents.
|
||||
/// </summary>
|
||||
public MetadataLibraryObject ()
|
||||
: base (Asf.Guid.AsfMetadataLibraryObject)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not the current instance is empty.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <see langword="true" /> if the current instance doesn't
|
||||
/// contain any <see cref="DescriptionRecord" /> objects.
|
||||
/// Otherwise <see langword="false" />.
|
||||
/// </value>
|
||||
public bool IsEmpty {
|
||||
get { return records.Count == 0; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ASF object.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public override ByteVector Render ()
|
||||
{
|
||||
ByteVector output = new ByteVector ();
|
||||
ushort count = 0;
|
||||
|
||||
foreach (DescriptionRecord rec in records) {
|
||||
count++;
|
||||
output.Add (rec.Render ());
|
||||
}
|
||||
|
||||
return Render (RenderWord (count) + output);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all records with a given language, stream, and
|
||||
/// name from the current instance.
|
||||
/// </summary>
|
||||
/// <param name="languageListIndex">
|
||||
/// A <see cref="ushort" /> value containing the language
|
||||
/// list index of the records to be removed.
|
||||
/// </param>
|
||||
/// <param name="streamNumber">
|
||||
/// A <see cref="ushort" /> value containing the stream
|
||||
/// number of the records to be removed.
|
||||
/// </param>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// records to be removed.
|
||||
/// </param>
|
||||
public void RemoveRecords (ushort languageListIndex, ushort streamNumber, string name)
|
||||
{
|
||||
for (int i = records.Count - 1; i >= 0; i--) {
|
||||
DescriptionRecord rec = records[i];
|
||||
if (rec.LanguageListIndex == languageListIndex &&
|
||||
rec.StreamNumber == streamNumber &&
|
||||
rec.Name == name)
|
||||
records.RemoveAt (i);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all records with a given language, stream, and any
|
||||
/// of a collection of names from the current instance.
|
||||
/// </summary>
|
||||
/// <param name="languageListIndex">
|
||||
/// A <see cref="ushort" /> value containing the language
|
||||
/// list index of the records to be retrieved.
|
||||
/// </param>
|
||||
/// <param name="streamNumber">
|
||||
/// A <see cref="ushort" /> value containing the stream
|
||||
/// number of the records to be retrieved.
|
||||
/// </param>
|
||||
/// <param name="names">
|
||||
/// A <see cref="T:string[]" /> containing the names of the
|
||||
/// records to be retrieved.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="T:System.Collections.Generic.IEnumerable`1" /> object enumerating
|
||||
/// through the <see cref="DescriptionRecord" /> objects
|
||||
/// retrieved from the current instance.
|
||||
/// </returns>
|
||||
public IEnumerable<DescriptionRecord> GetRecords (ushort languageListIndex, ushort streamNumber, params string[] names)
|
||||
{
|
||||
foreach (DescriptionRecord rec in records) {
|
||||
if (rec.LanguageListIndex != languageListIndex ||
|
||||
rec.StreamNumber != streamNumber)
|
||||
continue;
|
||||
|
||||
foreach (string name in names)
|
||||
if (rec.Name == name)
|
||||
yield return rec;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a record to the current instance.
|
||||
/// </summary>
|
||||
/// <param name="record">
|
||||
/// A <see cref="DescriptionRecord" /> object to add to the
|
||||
/// current instance.
|
||||
/// </param>
|
||||
public void AddRecord (DescriptionRecord record)
|
||||
{
|
||||
records.Add (record);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the a collection of records for a given language,
|
||||
/// stream, and name, removing the existing matching records.
|
||||
/// </summary>
|
||||
/// <param name="languageListIndex">
|
||||
/// A <see cref="ushort" /> value containing the language
|
||||
/// list index of the records to be added.
|
||||
/// </param>
|
||||
/// <param name="streamNumber">
|
||||
/// A <see cref="ushort" /> value containing the stream
|
||||
/// number of the records to be added.
|
||||
/// </param>
|
||||
/// <param name="name">
|
||||
/// A <see cref="string" /> object containing the name of the
|
||||
/// records to be added.
|
||||
/// </param>
|
||||
/// <param name="records">
|
||||
/// A <see cref="T:DescriptionRecord[]" /> containing records
|
||||
/// to add to the new instance.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// All added entries in <paramref name="records" /> should
|
||||
/// match <paramref name="languageListIndex" />, <paramref
|
||||
/// name="streamNumber" /> and <paramref name="name" /> but
|
||||
/// it is not verified by the method. The records will be
|
||||
/// added with their own values and not those provided in
|
||||
/// this method, which are used for removing existing values
|
||||
/// and determining where to position the new object.
|
||||
/// </remarks>
|
||||
public void SetRecords (ushort languageListIndex, ushort streamNumber, string name, params DescriptionRecord[] records)
|
||||
{
|
||||
int position = this.records.Count;
|
||||
for (int i = this.records.Count - 1; i >= 0; i--) {
|
||||
DescriptionRecord rec = this.records[i];
|
||||
if (rec.LanguageListIndex == languageListIndex &&
|
||||
rec.StreamNumber == streamNumber &&
|
||||
rec.Name == name) {
|
||||
this.records.RemoveAt (i);
|
||||
position = i;
|
||||
}
|
||||
}
|
||||
this.records.InsertRange (position, records);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region IEnumerable
|
||||
|
||||
/// <summary>
|
||||
/// Gets an enumerator for enumerating through the
|
||||
/// description records.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="T:System.Collections.IEnumerator`1" /> for
|
||||
/// enumerating through the description records.
|
||||
/// </returns>
|
||||
public IEnumerator<DescriptionRecord> GetEnumerator ()
|
||||
{
|
||||
return records.GetEnumerator ();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator ()
|
||||
{
|
||||
return records.GetEnumerator ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 60b732db7695db75682664625a7c9288
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,244 @@
|
||||
//
|
||||
// Object.cs: Provides a basic representation of an ASF object which can be read
|
||||
// from and written to disk.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// This abstract class provides a basic representation of an ASF
|
||||
/// object which can be read from and written to disk.
|
||||
/// </summary>
|
||||
public abstract class Object
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the GUID of the object.
|
||||
/// </summary>
|
||||
readonly System.Guid id;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Object" /> by reading the contents from a
|
||||
/// specified position in a specified file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object containing the file from
|
||||
/// which the contents of the new instance are to be read.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specify at what position to
|
||||
/// read the object.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="position" /> is less than zero or greater
|
||||
/// than the size of the file.
|
||||
/// </exception>
|
||||
protected Object (File file, long position)
|
||||
{
|
||||
if (file == null)
|
||||
throw new ArgumentNullException (nameof (file));
|
||||
|
||||
if (position < 0 ||
|
||||
position > file.Length - 24)
|
||||
throw new ArgumentOutOfRangeException (nameof (position));
|
||||
|
||||
file.Seek (position);
|
||||
id = file.ReadGuid ();
|
||||
OriginalSize = file.ReadQWord ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Object" /> with a specified GUID.
|
||||
/// </summary>
|
||||
/// <param name="guid">
|
||||
/// A <see cref="System.Guid" /> value containing the GUID to
|
||||
/// use for the new instance.
|
||||
/// </param>
|
||||
protected Object (System.Guid guid)
|
||||
{
|
||||
id = guid;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the GUID for the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="System.Guid" /> object containing the GUID
|
||||
/// of the current instance.
|
||||
/// </value>
|
||||
public System.Guid Guid {
|
||||
get { return id; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the original size of the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ulong" /> value containing the size of the
|
||||
/// current instance as it originally appeared on disk.
|
||||
/// </value>
|
||||
public ulong OriginalSize { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ASF object.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
/// <seealso cref="Render(ByteVector)" />
|
||||
public abstract ByteVector Render ();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Static Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders a Unicode (wide) string.
|
||||
/// </summary>
|
||||
/// <param name="value">
|
||||
/// A <see cref="string" /> object containing the text to
|
||||
/// render.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered value.
|
||||
/// </returns>
|
||||
public static ByteVector RenderUnicode (string value)
|
||||
{
|
||||
ByteVector v = ByteVector.FromString (value, StringType.UTF16LE);
|
||||
v.Add (RenderWord (0));
|
||||
return v;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders a 4-byte DWORD.
|
||||
/// </summary>
|
||||
/// <param name="value">
|
||||
/// A <see cref="uint" /> value containing the DWORD to
|
||||
/// render.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered value.
|
||||
/// </returns>
|
||||
public static ByteVector RenderDWord (uint value)
|
||||
{
|
||||
return ByteVector.FromUInt (value, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders a 8-byte QWORD.
|
||||
/// </summary>
|
||||
/// <param name="value">
|
||||
/// A <see cref="ulong" /> value containing the QWORD to
|
||||
/// render.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered value.
|
||||
/// </returns>
|
||||
public static ByteVector RenderQWord (ulong value)
|
||||
{
|
||||
return ByteVector.FromULong (value, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders a 2-byte WORD.
|
||||
/// </summary>
|
||||
/// <param name="value">
|
||||
/// A <see cref="ushort" /> value containing the WORD to
|
||||
/// render.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered value.
|
||||
/// </returns>
|
||||
public static ByteVector RenderWord (ushort value)
|
||||
{
|
||||
return ByteVector.FromUShort (value, false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ASF object
|
||||
/// containing specified data.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the data to
|
||||
/// contained in the rendered version of the current
|
||||
/// instance.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Child classes implementing <see cref="Render()" /> should
|
||||
/// render their contents and then send the data through this
|
||||
/// method to produce the final output.
|
||||
/// </remarks>
|
||||
protected ByteVector Render (ByteVector data)
|
||||
{
|
||||
ulong length = (ulong)((data != null ? data.Count : 0) + 24);
|
||||
ByteVector v = id.ToByteArray ();
|
||||
v.Add (RenderQWord (length));
|
||||
v.Add (data);
|
||||
return v;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de6647e25247fb396826cf683998e204
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,125 @@
|
||||
//
|
||||
// PaddingObject.cs: Provides a representation of an ASF Padding object which
|
||||
// can be read from and written to disk.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Object" /> to provide a
|
||||
/// representation of an ASF Padding object which can be read from
|
||||
/// and written to disk.
|
||||
/// </summary>
|
||||
public class PaddingObject : Object
|
||||
{
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="PaddingObject" /> by reading the contents from a
|
||||
/// specified position in a specified file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object containing the file from
|
||||
/// which the contents of the new instance are to be read.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specify at what position to
|
||||
/// read the object.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="position" /> is less than zero or greater
|
||||
/// than the size of the file.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// The object read from disk does not have the correct GUID
|
||||
/// or smaller than the minimum size.
|
||||
/// </exception>
|
||||
public PaddingObject (File file, long position)
|
||||
: base (file, position)
|
||||
{
|
||||
if (!Guid.Equals (Asf.Guid.AsfPaddingObject))
|
||||
throw new CorruptFileException ("Object GUID incorrect.");
|
||||
|
||||
if (OriginalSize < 24)
|
||||
throw new CorruptFileException ("Object size too small.");
|
||||
|
||||
Size = OriginalSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="PaddingObject" /> of a specified size.
|
||||
/// </summary>
|
||||
/// <param name="size">
|
||||
/// A <see cref="uint" /> value specifying the number of
|
||||
/// bytes the new instance is to take up on disk.
|
||||
/// </param>
|
||||
public PaddingObject (uint size)
|
||||
: base (Asf.Guid.AsfPaddingObject)
|
||||
{
|
||||
Size = size;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Prublic Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the number of bytes the current instance
|
||||
/// will take up on disk.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ulong" /> value containing the size of the
|
||||
/// current instance on disk.
|
||||
/// </value>
|
||||
public ulong Size { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ASF object.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public override ByteVector Render ()
|
||||
{
|
||||
return Render (new ByteVector ((int)(Size - 24)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 57cc0edc0b79695a69d3f10c7d65944f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,226 @@
|
||||
//
|
||||
// StreamPropertiesObject.cs: Provides a representation of an ASF Stream
|
||||
// Properties object which can be read from and written to disk.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Object" /> to provide a
|
||||
/// representation of an ASF Stream Properties object which can be
|
||||
/// read from and written to disk.
|
||||
/// </summary>
|
||||
public class StreamPropertiesObject : Object
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the time offset of the stream.
|
||||
/// </summary>
|
||||
readonly ulong time_offset;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the reserved data.
|
||||
/// </summary>
|
||||
readonly uint reserved;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="PaddingObject" /> by reading the contents from a
|
||||
/// specified position in a specified file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object containing the file from
|
||||
/// which the contents of the new instance are to be read.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specify at what position to
|
||||
/// read the object.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="position" /> is less than zero or greater
|
||||
/// than the size of the file.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// The object read from disk does not have the correct GUID
|
||||
/// or smaller than the minimum size.
|
||||
/// </exception>
|
||||
public StreamPropertiesObject (File file, long position)
|
||||
: base (file, position)
|
||||
{
|
||||
if (!Guid.Equals (Asf.Guid.AsfStreamPropertiesObject))
|
||||
throw new CorruptFileException ("Object GUID incorrect.");
|
||||
|
||||
if (OriginalSize < 78)
|
||||
throw new CorruptFileException ("Object size too small.");
|
||||
|
||||
StreamType = file.ReadGuid ();
|
||||
ErrorCorrectionType = file.ReadGuid ();
|
||||
time_offset = file.ReadQWord ();
|
||||
|
||||
int type_specific_data_length = (int)file.ReadDWord ();
|
||||
int error_correction_data_length = (int)file.ReadDWord ();
|
||||
|
||||
Flags = file.ReadWord ();
|
||||
reserved = file.ReadDWord ();
|
||||
TypeSpecificData = file.ReadBlock (type_specific_data_length);
|
||||
ErrorCorrectionData = file.ReadBlock (error_correction_data_length);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the codec information contained in the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ICodec" /> object containing the codec
|
||||
/// information read from <see cref="TypeSpecificData" /> or
|
||||
/// <see langword="null" /> if the data could not be decoded.
|
||||
/// </value>
|
||||
public ICodec Codec {
|
||||
get {
|
||||
if (StreamType == Asf.Guid.AsfAudioMedia)
|
||||
return new Riff.WaveFormatEx (TypeSpecificData, 0);
|
||||
|
||||
if (StreamType == Asf.Guid.AsfVideoMedia)
|
||||
return new Riff.BitmapInfoHeader (TypeSpecificData, 11);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the stream type GUID of the current instance.
|
||||
/// </summary>
|
||||
/// <summary>
|
||||
/// A <see cref="System.Guid" /> object containing the stream
|
||||
/// type GUID of the current instance.
|
||||
/// </summary>
|
||||
public System.Guid StreamType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the error correction type GUID of the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <summary>
|
||||
/// A <see cref="System.Guid" /> object containing the error
|
||||
/// correction type GUID of the current instance.
|
||||
/// </summary>
|
||||
public System.Guid ErrorCorrectionType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the time offset at which the stream described by the
|
||||
/// current instance begins.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TimeSpan" /> value containing the time
|
||||
/// offset at which the stream described by the current
|
||||
/// instance begins.
|
||||
/// </value>
|
||||
public TimeSpan TimeOffset {
|
||||
get { return new TimeSpan ((long)time_offset); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the flags that apply to the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ushort" /> value containing the flags that
|
||||
/// apply to the current instance.
|
||||
/// </value>
|
||||
public ushort Flags { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type specific data contained in the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ByteVector" /> object containing the type
|
||||
/// specific data contained in the current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// The contents of this value are dependant on the type
|
||||
/// contained in <see cref="StreamType" />.
|
||||
/// </remarks>
|
||||
public ByteVector TypeSpecificData { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the error correction data contained in the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ByteVector" /> object containing the error
|
||||
/// correction data contained in the current instance.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// The contents of this value are dependant on the type
|
||||
/// contained in <see cref="ErrorCorrectionType" />.
|
||||
/// </remarks>
|
||||
public ByteVector ErrorCorrectionData { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ASF object.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public override ByteVector Render ()
|
||||
{
|
||||
ByteVector output = StreamType.ToByteArray ();
|
||||
output.Add (ErrorCorrectionType.ToByteArray ());
|
||||
output.Add (RenderQWord (time_offset));
|
||||
output.Add (RenderDWord ((uint)TypeSpecificData.Count));
|
||||
output.Add (RenderDWord ((uint)ErrorCorrectionData.Count));
|
||||
output.Add (RenderWord (Flags));
|
||||
output.Add (RenderDWord (reserved));
|
||||
output.Add (TypeSpecificData);
|
||||
output.Add (ErrorCorrectionData);
|
||||
|
||||
return Render (output);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f4fa10f38049b3e2499e7f713daf6b9a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d734ffb9edf169961b4e181c03effffd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,99 @@
|
||||
//
|
||||
// UnknownObject.cs: Provides a simple and generic representation of an object
|
||||
// not identified by TagLib# so that its contents may be preserved.
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Asf
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Object" /> to provide a
|
||||
/// representation of an unknown object which can be read from and
|
||||
/// written to disk.
|
||||
/// </summary>
|
||||
public class UnknownObject : Object
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="UnknownObject" /> by reading the contents from a
|
||||
/// specified position in a specified file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="Asf.File" /> object containing the file from
|
||||
/// which the contents of the new instance are to be read.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specify at what position to
|
||||
/// read the object.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="position" /> is less than zero or greater
|
||||
/// than the size of the file.
|
||||
/// </exception>
|
||||
public UnknownObject (File file, long position)
|
||||
: base (file, position)
|
||||
{
|
||||
Data = file.ReadBlock ((int)(OriginalSize - 24));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the data contained in the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ByteVector" /> object containing the data
|
||||
/// contained in the current instance.
|
||||
/// </value>
|
||||
public ByteVector Data { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Renders the current instance as a raw ASF object.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVector" /> object containing the
|
||||
/// rendered version of the current instance.
|
||||
/// </returns>
|
||||
public override ByteVector Render ()
|
||||
{
|
||||
return Render (Data);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 91aaa7eb7ea3bc7638ef1a9a9bb9f898
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f2cec2ef40ccecd7ba6d1a7e546abf8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,262 @@
|
||||
//
|
||||
// File.cs:
|
||||
//
|
||||
// Author:
|
||||
// Guy Taylor (s0700260@sms.ed.ac.uk) (thebigguy.co.uk@gmail.com)
|
||||
//
|
||||
// Original Source:
|
||||
// Ogg/File.cs from TagLib-sharp
|
||||
//
|
||||
// Copyright (C) 2009 Guy Taylor (Original Implementation)
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
using System;
|
||||
|
||||
namespace TagLib.Audible
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="TagLib.File" /> to provide tagging
|
||||
/// and properties support for Audible inc's aa file format.
|
||||
/// </summary>
|
||||
[SupportedMimeType ("audio/x-audible")]
|
||||
[SupportedMimeType ("taglib/aa", "aa")]
|
||||
[SupportedMimeType ("taglib/aax", "aax")]
|
||||
public class File : TagLib.File
|
||||
{
|
||||
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the tags for the file.
|
||||
/// </summary>
|
||||
readonly TagLib.Tag tag;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Static Fields
|
||||
|
||||
/// <summary>
|
||||
/// The offset to the tag block.
|
||||
/// </summary>
|
||||
public const short TagBlockOffset = 0xBD;
|
||||
|
||||
/// <summary>
|
||||
/// The offset to the end of tag pointer.
|
||||
/// </summary>
|
||||
public const short OffsetToEndTagPointer = 0x38;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local file
|
||||
/// system and specified read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path, ReadStyle propertiesStyle)
|
||||
: this (new LocalFileAbstraction (path), propertiesStyle)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local file
|
||||
/// system with an average read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path)
|
||||
: this (path, ReadStyle.Average)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction and
|
||||
/// specified read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// The file is not the write length.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction, ReadStyle propertiesStyle)
|
||||
: base (abstraction)
|
||||
{
|
||||
|
||||
Mode = AccessMode.Read;
|
||||
|
||||
try {
|
||||
// get the pointer to the end of the tag block
|
||||
// and calculate the tag block length
|
||||
Seek (OffsetToEndTagPointer);
|
||||
int tagLen = ((int)ReadBlock (4).ToUInt (true)) - TagBlockOffset;
|
||||
|
||||
// read the whole tag and send to Tag class
|
||||
Seek (TagBlockOffset);
|
||||
ByteVector bv = ReadBlock (tagLen);
|
||||
|
||||
tag = new Tag (bv);
|
||||
|
||||
} finally {
|
||||
Mode = AccessMode.Closed;
|
||||
}
|
||||
|
||||
// ??
|
||||
TagTypesOnDisk = TagTypes;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction with an
|
||||
/// average read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction)
|
||||
: this (abstraction, ReadStyle.Average)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Saves the changes made in the current instance to the
|
||||
/// file it represents.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Currently this does not work as there is not enough
|
||||
/// information about the file format
|
||||
/// </remarks>
|
||||
public override void Save ()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a set of tag types from the current instance.
|
||||
/// </summary>
|
||||
/// <param name="types">
|
||||
/// A bitwise combined <see cref="TagLib.TagTypes" /> value
|
||||
/// containing tag types to be removed from the file.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// In order to remove all tags from a file, pass <see
|
||||
/// cref="TagTypes.AllTags" /> as <paramref name="types" />.
|
||||
/// </remarks>
|
||||
/// <remarks>
|
||||
/// Currently this does not work as there is not enough
|
||||
/// information about the file format
|
||||
/// </remarks>
|
||||
public override void RemoveTags (TagTypes types)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a tag of a specified type from the current instance,
|
||||
/// optionally creating a new tag if possible.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="TagLib.TagTypes" /> value indicating the
|
||||
/// type of tag to read.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> value specifying whether or not to
|
||||
/// try and create the tag if one is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="Tag" /> object containing the tag that was
|
||||
/// found in or added to the current instance. If no
|
||||
/// matching tag was found and none was created, <see
|
||||
/// langword="null" /> is returned.
|
||||
/// </returns>
|
||||
public override TagLib.Tag GetTag (TagTypes type, bool create)
|
||||
{
|
||||
if (type == TagTypes.AudibleMetadata)
|
||||
return tag;
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets a abstract representation of all tags stored in the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TagLib.Tag" /> object representing all tags
|
||||
/// stored in the current instance.
|
||||
/// </value>
|
||||
public override TagLib.Tag Tag {
|
||||
get { return tag; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the media properties of the file represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TagLib.Properties" /> object containing the
|
||||
/// media properties of the file represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public override Properties Properties { get; } = new Properties ();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 006f7fb1983a3a1a89f28703d552cbc6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,320 @@
|
||||
//
|
||||
// Tag.cs:
|
||||
//
|
||||
// Author:
|
||||
// Guy Taylor (s0700260@sms.ed.ac.uk) (thebigguy.co.uk@gmail.com)
|
||||
//
|
||||
// Original Source:
|
||||
// Id3v1/Tag.cs from TagLib-sharp
|
||||
//
|
||||
// Copyright (C) 2009 Guy Taylor (Original Implementation)
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TagLib.Audible
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Tag" /> to provide support for
|
||||
/// reading tags stored in the Audible Metadata format.
|
||||
/// </summary>
|
||||
public class Tag : TagLib.Tag
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
List<KeyValuePair<string, string>> tags;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Tag" /> with no contents.
|
||||
/// </summary>
|
||||
public Tag ()
|
||||
{
|
||||
Clear ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Tag" /> by reading the contents from a specified
|
||||
/// position in a specified file.
|
||||
/// </summary>
|
||||
/// <param name="file">
|
||||
/// A <see cref="File" /> object containing the file from
|
||||
/// which the contents of the new instance is to be read.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// A <see cref="long" /> value specify at what position to
|
||||
/// read the tag.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="file" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="position" /> is less than zero or greater
|
||||
/// than the size of the file.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// The file does not contain FileIdentifier
|
||||
/// at the given position.
|
||||
/// </exception>
|
||||
public Tag (File file, long position)
|
||||
{
|
||||
// TODO: can we read from file
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="Tag" /> by reading the contents from a specified
|
||||
/// <see cref="ByteVector" /> object.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object to read the tag from.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="data" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// <paramref name="data" /> is less than 128 bytes or does
|
||||
/// not start with FileIdentifier.
|
||||
/// </exception>
|
||||
public Tag (ByteVector data)
|
||||
{
|
||||
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
Clear ();
|
||||
Parse (data);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Populates the current instance by parsing the contents of
|
||||
/// a raw AudibleMetadata tag.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the whole tag
|
||||
/// object
|
||||
/// </param>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// <paramref name="data" /> is less than 128 bytes or does
|
||||
/// not start with FileIdentifier.
|
||||
/// </exception>
|
||||
void Parse (ByteVector data)
|
||||
{
|
||||
string currentKey, currentValue;
|
||||
int keyLen, valueLen;
|
||||
|
||||
try {
|
||||
do {
|
||||
keyLen = (int)data.ToUInt (true);
|
||||
data.RemoveRange (0, 4);
|
||||
valueLen = (int)data.ToUInt (true);
|
||||
data.RemoveRange (0, 4);
|
||||
currentKey = data.ToString (StringType.UTF8, 0, keyLen);
|
||||
data.RemoveRange (0, keyLen);
|
||||
currentValue = data.ToString (StringType.UTF8, 0, valueLen);
|
||||
data.RemoveRange (0, valueLen);
|
||||
|
||||
tags.Add (new KeyValuePair<string, string> (currentKey, currentValue));
|
||||
|
||||
//StringHandle (currentKey, currentValue);
|
||||
|
||||
// if it is not the last item remove the end byte (null terminated)
|
||||
if (data.Count != 0)
|
||||
data.RemoveRange (0, 1);
|
||||
}
|
||||
while (data.Count >= 4);
|
||||
} catch (Exception) {
|
||||
//
|
||||
}
|
||||
|
||||
if (data.Count != 0)
|
||||
throw new CorruptFileException ();
|
||||
}
|
||||
|
||||
void setTag (string tagName, string value)
|
||||
{
|
||||
for (int i = 0; i < tags.Count; i++) {
|
||||
if (tags[i].Key == tagName)
|
||||
tags[i] = new KeyValuePair<string, string> (tags[i].Key, value);
|
||||
}
|
||||
}
|
||||
|
||||
string getTag (string tagName)
|
||||
{
|
||||
foreach (KeyValuePair<string, string> tag in tags) {
|
||||
if (tag.Key == tagName)
|
||||
return tag.Value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// Given a key and value pair it will update the
|
||||
/// present metadata.
|
||||
/// </summary>
|
||||
/// <param name="key">
|
||||
/// A <see cref="String" /> containing the key.
|
||||
/// </param>
|
||||
/// <param name="strValue">
|
||||
/// A <see cref="String" /> containing the value.
|
||||
/// </param>
|
||||
private void StringHandle (String key, String strValue)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case "title":
|
||||
title = strValue;
|
||||
break;
|
||||
case "author":
|
||||
artist = strValue;
|
||||
break;
|
||||
case "provider":
|
||||
album = strValue;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
#region TagLib.Tag
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tag types contained in the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Always <see cref="TagTypes.AudibleMetadata" />.
|
||||
/// </value>
|
||||
public override TagTypes TagTypes {
|
||||
get { return TagTypes.AudibleMetadata; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get or Set the Author Tag
|
||||
/// </summary>
|
||||
|
||||
public string Author {
|
||||
get {
|
||||
return getTag ("author");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get or Set the Copyright Tag
|
||||
/// </summary>
|
||||
|
||||
public override string Copyright {
|
||||
get {
|
||||
return getTag ("copyright");
|
||||
}
|
||||
set {
|
||||
setTag ("copyright", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get or Set the Description Tag
|
||||
/// </summary>
|
||||
|
||||
public override string Description {
|
||||
get { return getTag ("description"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get or Set the Narrator Tag
|
||||
/// </summary>
|
||||
public string Narrator {
|
||||
get {
|
||||
return getTag ("narrator");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the title for the media described by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing the title for
|
||||
/// the media described by the current instance or <see
|
||||
/// langword="null" /> if no value is present.
|
||||
/// </value>
|
||||
public override string Title {
|
||||
get {
|
||||
return getTag ("title");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the album for the media described by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing the album for
|
||||
/// the media described by the current instance or <see
|
||||
/// langword="null" /> if no value is present.
|
||||
/// </value>
|
||||
public override string Album {
|
||||
get {
|
||||
return getTag ("provider");
|
||||
//return string.IsNullOrEmpty (album) ?
|
||||
// null : album;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the album artist for the media described by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="T:string[]" /> object containing a single
|
||||
/// artist described by the current instance or <see
|
||||
/// langword="null" /> if no value is present.
|
||||
/// </value>
|
||||
public override string[] AlbumArtists {
|
||||
get {
|
||||
var artist = getTag ("provider");
|
||||
|
||||
return string.IsNullOrEmpty (artist) ?
|
||||
null : new [] { artist };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the values stored in the current instance.
|
||||
/// </summary>
|
||||
public override void Clear ()
|
||||
{
|
||||
tags = new List<KeyValuePair<string, string>> ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c399f58c554dc5479a139a58c8a72b80
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fd4901c34711c7eaba954926fa92969f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,273 @@
|
||||
//
|
||||
// ByteVectorList.cs:
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
// Aaron Bockover (abockover@novell.com)
|
||||
//
|
||||
// Original Source:
|
||||
// tbytevectorlist.cpp from TagLib
|
||||
//
|
||||
// Copyright (C) 2005-2007 Brian Nickel
|
||||
// Copyright (C) 2006 Novell, Inc.
|
||||
// Copyright (C) 2002,2003 Scott Wheeler (Original Implementation)
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace TagLib
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="T:TagLib.ListBase`1"/> to represent
|
||||
/// a collection of <see cref="ByteVector" /> objects.
|
||||
/// </summary>
|
||||
[ComVisible (false)]
|
||||
public class ByteVectorCollection : ListBase<ByteVector>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ByteVectorCollection" /> with no contents.
|
||||
/// </summary>
|
||||
public ByteVectorCollection ()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ByteVectorCollection" /> with specified contents.
|
||||
/// </summary>
|
||||
/// <param name="list">
|
||||
/// A <see cref="T:System.Collections.Generic.IEnumerable`1"
|
||||
/// /> containing <see cref="ByteVector" /> objects to add to
|
||||
/// the current instance.
|
||||
/// </param>
|
||||
public ByteVectorCollection (IEnumerable<ByteVector> list)
|
||||
{
|
||||
if (list != null)
|
||||
Add (list);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="ByteVectorCollection" /> with specified contents.
|
||||
/// </summary>
|
||||
/// <param name="list">
|
||||
/// A <see cref="T:ByteVector[]" /> containing objects to add to
|
||||
/// the current instance.
|
||||
/// </param>
|
||||
public ByteVectorCollection (params ByteVector[] list)
|
||||
{
|
||||
if (list != null)
|
||||
Add (list);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a sorted insert of a <see cref="ByteVector" />
|
||||
/// object into the current instance, optionally only adding
|
||||
/// if the item is unique.
|
||||
/// </summary>
|
||||
/// <param name="item">
|
||||
/// A <see cref="ByteVector" /> object to add to the current
|
||||
/// instance.
|
||||
/// </param>
|
||||
/// <param name="unique">
|
||||
/// If <see langword="true" />, the object will only be added
|
||||
/// if an identical value is not already contained in the
|
||||
/// current instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="item" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public override void SortedInsert (ByteVector item, bool unique)
|
||||
{
|
||||
if (item == null)
|
||||
throw new ArgumentNullException (nameof (item));
|
||||
|
||||
// FIXME: This is not used, but if it is a faster
|
||||
// method could be used.
|
||||
int i = 0;
|
||||
for (; i < Count; i++) {
|
||||
if (item == this[i] && unique)
|
||||
return;
|
||||
|
||||
if (item >= this[i])
|
||||
break;
|
||||
}
|
||||
|
||||
Insert (i + 1, item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the current instance to a <see cref="ByteVector"
|
||||
/// /> by joining the contents together with a specified
|
||||
/// separator.
|
||||
/// </summary>
|
||||
/// <param name="separator">
|
||||
/// A <see cref="ByteVector"/> object to separate the
|
||||
/// combined contents of the current instance.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A new <see cref="ByteVector"/> object containing the
|
||||
/// joined contents of the current instance.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="separator" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public ByteVector ToByteVector (ByteVector separator)
|
||||
{
|
||||
if (separator == null)
|
||||
throw new ArgumentNullException (nameof (separator));
|
||||
|
||||
var vector = new ByteVector ();
|
||||
|
||||
for (int i = 0; i < Count; i++) {
|
||||
if (i != 0 && separator.Count > 0)
|
||||
vector.Add (separator);
|
||||
|
||||
vector.Add (this[i]);
|
||||
}
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits a <see cref="ByteVector" /> object using a
|
||||
/// pattern.
|
||||
/// </summary>
|
||||
/// <param name="vector">
|
||||
/// A <see cref="ByteVector"/> object to split.
|
||||
/// </param>
|
||||
/// <param name="pattern">
|
||||
/// A <see cref="ByteVector"/> object to use to split
|
||||
/// <paramref name="vector" /> with.
|
||||
/// </param>
|
||||
/// <param name="byteAlign">
|
||||
/// A <see cref="int" /> specifying the byte align to use
|
||||
/// when splitting. In order to split when a pattern is
|
||||
/// encountered, the index at which it is found must be
|
||||
/// divisible by <paramref name="byteAlign" />.
|
||||
/// </param>
|
||||
/// <param name="max">
|
||||
/// A <see cref="int" /> value specifying the maximum number
|
||||
/// of objects to return, or zero to not to limit the number.
|
||||
/// If that that number is reached, the last value will
|
||||
/// contain the remainder of the file even if it contains
|
||||
/// more instances of <paramref name="pattern" />.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVectorCollection" /> object containing
|
||||
/// the split contents of the current instance.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="vector" /> or <paramref name="pattern" />
|
||||
/// is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="byteAlign" /> is less than 1.
|
||||
/// </exception>
|
||||
public static ByteVectorCollection Split (ByteVector vector, ByteVector pattern, int byteAlign, int max)
|
||||
{
|
||||
if (vector == null)
|
||||
throw new ArgumentNullException (nameof (vector));
|
||||
|
||||
if (pattern == null)
|
||||
throw new ArgumentNullException (nameof (pattern));
|
||||
|
||||
if (byteAlign < 1)
|
||||
throw new ArgumentOutOfRangeException (nameof (byteAlign), "byteAlign must be at least 1.");
|
||||
|
||||
var list = new ByteVectorCollection ();
|
||||
int previous_offset = 0;
|
||||
|
||||
for (int offset = vector.Find (pattern, 0, byteAlign);
|
||||
offset != -1 && (max < 1 ||
|
||||
max > list.Count + 1);
|
||||
offset = vector.Find (pattern,
|
||||
offset + pattern.Count, byteAlign)) {
|
||||
list.Add (vector.Mid (previous_offset,
|
||||
offset - previous_offset));
|
||||
previous_offset = offset + pattern.Count;
|
||||
}
|
||||
|
||||
if (previous_offset < vector.Count)
|
||||
list.Add (vector.Mid (previous_offset,
|
||||
vector.Count - previous_offset));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits a <see cref="ByteVector" /> object using a
|
||||
/// pattern.
|
||||
/// </summary>
|
||||
/// <param name="vector">
|
||||
/// A <see cref="ByteVector"/> object to split.
|
||||
/// </param>
|
||||
/// <param name="pattern">
|
||||
/// A <see cref="ByteVector"/> object to use to split
|
||||
/// <paramref name="vector" /> with.
|
||||
/// </param>
|
||||
/// <param name="byteAlign">
|
||||
/// A <see cref="int" /> specifying the byte align to use
|
||||
/// when splitting. In order to split when a pattern is
|
||||
/// encountered, the index at which it is found must be
|
||||
/// divisible by <paramref name="byteAlign" />.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVectorCollection" /> object containing
|
||||
/// the split contents of the current instance.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="vector" /> or <paramref name="pattern" />
|
||||
/// is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// <paramref name="byteAlign" /> is less than 1.
|
||||
/// </exception>
|
||||
public static ByteVectorCollection Split (ByteVector vector, ByteVector pattern, int byteAlign)
|
||||
{
|
||||
return Split (vector, pattern, byteAlign, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits a <see cref="ByteVector" /> object using a
|
||||
/// pattern.
|
||||
/// </summary>
|
||||
/// <param name="vector">
|
||||
/// A <see cref="ByteVector"/> object to split.
|
||||
/// </param>
|
||||
/// <param name="pattern">
|
||||
/// A <see cref="ByteVector"/> object to use to split
|
||||
/// <paramref name="vector" /> with.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="ByteVectorCollection" /> object containing
|
||||
/// the split contents of the current instance.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="vector" /> or <paramref name="pattern" />
|
||||
/// is <see langword="null" />.
|
||||
/// </exception>
|
||||
public static ByteVectorCollection Split (ByteVector vector, ByteVector pattern)
|
||||
{
|
||||
return Split (vector, pattern, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 13ce76148d2aedf098df14fcf5195df7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0fcfda10f765f9bf0b754fb38b66878e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,167 @@
|
||||
//
|
||||
// CorruptFileException.cs:
|
||||
//
|
||||
// Author:
|
||||
// Aaron Bockover (abockover@novell.com)
|
||||
//
|
||||
// Original Source:
|
||||
// Entagged#
|
||||
//
|
||||
// Copyright (C) 2006 Novell, Inc.
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace TagLib
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="Exception" /> and is used to
|
||||
/// indicate that a file or tag is corrupt.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This exception will be thrown if invalid data interferes with the
|
||||
/// reading of the file or tag. One common example is in the (legal)
|
||||
/// downloading of media files with BitTorrent, in which case large
|
||||
/// portions of the file will contain zeroed bytes.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <para>Catching an exception when creating a <see
|
||||
/// cref="File" />.</para>
|
||||
/// <code lang="C#">
|
||||
/// using System;
|
||||
/// using TagLib;
|
||||
///
|
||||
/// public class ExceptionTest
|
||||
/// {
|
||||
/// public static void Main ()
|
||||
/// {
|
||||
/// try {
|
||||
/// File file = File.Create ("partial.mp3"); // Partial download.
|
||||
/// } catch (CorruptFileException e) {
|
||||
/// Console.WriteLine ("That file is corrupt: {0}", e.ToString ());
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// <code lang="C++">
|
||||
/// #using <System.dll>
|
||||
/// #using <taglib-sharp.dll>
|
||||
///
|
||||
/// using System;
|
||||
/// using TagLib;
|
||||
///
|
||||
/// void main ()
|
||||
/// {
|
||||
/// try {
|
||||
/// File file = File::Create ("partial.mp3"); // Partial download.
|
||||
/// } catch (CorruptFileException^ e) {
|
||||
/// Console::WriteLine ("That file is corrupt: {0}", e);
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// <code lang="VB">
|
||||
/// Imports System
|
||||
/// Imports TagLib
|
||||
///
|
||||
/// Public Class ExceptionTest
|
||||
/// Public Shared Sub Main ()
|
||||
/// Try
|
||||
/// file As File = File.Create ("partial.mp3") ' Partial download.
|
||||
/// Catch e As CorruptFileException
|
||||
/// Console.WriteLine ("That file is corrupt: {0}", e.ToString ());
|
||||
/// End Try
|
||||
/// End Sub
|
||||
/// End Class
|
||||
/// </code>
|
||||
/// <code lang="Boo">
|
||||
/// import System
|
||||
/// import TagLib
|
||||
///
|
||||
/// try:
|
||||
/// file As File = File.Create ("partial.mp3") # Partial download.
|
||||
/// catch e as CorruptFileException:
|
||||
/// Console.WriteLine ("That file is corrupt: {0}", e.ToString ());
|
||||
/// </code>
|
||||
/// </example>
|
||||
[Serializable]
|
||||
public class CorruptFileException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="CorruptFileException" /> with a specified
|
||||
/// message.
|
||||
/// </summary>
|
||||
/// <param name="message">
|
||||
/// A <see cref="string" /> containing a message explaining
|
||||
/// the reason for the exception.
|
||||
/// </param>
|
||||
public CorruptFileException (string message) : base (message)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="CorruptFileException" /> with the default
|
||||
/// values.
|
||||
/// </summary>
|
||||
public CorruptFileException ()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="CorruptFileException" /> with a specified
|
||||
/// message containing a specified exception.
|
||||
/// </summary>
|
||||
/// <param name="message">
|
||||
/// A <see cref="string" /> containing a message explaining
|
||||
/// the reason for the exception.
|
||||
/// </param>
|
||||
/// <param name="innerException">
|
||||
/// A <see cref="Exception" /> object to be contained in the
|
||||
/// new exception. For example, previously caught exception.
|
||||
/// </param>
|
||||
public CorruptFileException (string message, Exception innerException)
|
||||
: base (message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="CorruptFileException" /> from a specified
|
||||
/// serialization info and streaming context.
|
||||
/// </summary>
|
||||
/// <param name="info">
|
||||
/// A <see cref="SerializationInfo" /> object containing the
|
||||
/// serialized data to be used for the new instance.
|
||||
/// </param>
|
||||
/// <param name="context">
|
||||
/// A <see cref="StreamingContext" /> object containing the
|
||||
/// streaming context information for the new instance.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// This constructor is implemented because <see
|
||||
/// cref="CorruptFileException" /> implements the <see
|
||||
/// cref="ISerializable" /> interface.
|
||||
/// </remarks>
|
||||
protected CorruptFileException (SerializationInfo info, StreamingContext context)
|
||||
: base (info, context)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b3d4c56812fd17788a353ae122bb5c53
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,137 @@
|
||||
//
|
||||
// Debugger.cs:
|
||||
//
|
||||
// Author:
|
||||
// Brian Nickel (brian.nickel@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2006-2007 Brian Nickel
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TagLib
|
||||
{
|
||||
static class Debugger
|
||||
{
|
||||
public delegate void DebugMessageSentHandler (string message);
|
||||
|
||||
public static event DebugMessageSentHandler DebugMessageSent;
|
||||
|
||||
public static void Debug (string message)
|
||||
{
|
||||
DebugMessageSent?.Invoke (message);
|
||||
}
|
||||
|
||||
public static void DumpHex (ByteVector data)
|
||||
{
|
||||
DumpHex (data.Data);
|
||||
}
|
||||
|
||||
public static void DumpHex (byte[] data)
|
||||
{
|
||||
int cols = 16;
|
||||
int rows = data.Length / cols + (data.Length % cols != 0 ? 1 : 0);
|
||||
|
||||
for (int row = 0; row < rows; row++) {
|
||||
for (int col = 0; col < cols; col++) {
|
||||
if (row == rows - 1 && data.Length % cols != 0 && col >= data.Length % cols)
|
||||
Console.Write (" ");
|
||||
else
|
||||
Console.Write (" {0:x2}", data[row * cols + col]);
|
||||
}
|
||||
|
||||
Console.Write (" | ");
|
||||
|
||||
for (int col = 0; col < cols; col++) {
|
||||
if (row == rows - 1 && data.Length % cols != 0 && col >= data.Length % cols)
|
||||
Console.Write (" ");
|
||||
else
|
||||
WriteByte2 (data[row * cols + col]);
|
||||
}
|
||||
|
||||
Console.WriteLine ();
|
||||
}
|
||||
Console.WriteLine ();
|
||||
}
|
||||
|
||||
static void WriteByte2 (byte data)
|
||||
{
|
||||
foreach (char c in allowed)
|
||||
if (c == data) {
|
||||
Console.Write (c);
|
||||
return;
|
||||
}
|
||||
|
||||
Console.Write (".");
|
||||
}
|
||||
|
||||
static readonly string allowed = "0123456789abcdefghijklmnopqr" +
|
||||
"stuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`~!@#$%^&*()_+-={}" +
|
||||
"[];:'\",.<>?/\\|";
|
||||
|
||||
|
||||
static readonly Dictionary<object, Dictionary<object, DebugTimeData>>
|
||||
debug_times = new Dictionary<object, Dictionary<object, DebugTimeData>> ();
|
||||
|
||||
public static void AddDebugTime (object o1, object o2, DateTime start)
|
||||
{
|
||||
var data = new DebugTimeData (DateTime.Now - start, 1);
|
||||
if (debug_times.ContainsKey (o1) && debug_times[o1].ContainsKey (o2)) {
|
||||
data.time += debug_times[o1][o2].time;
|
||||
data.occurances += debug_times[o1][o2].occurances;
|
||||
}
|
||||
|
||||
if (!debug_times.ContainsKey (o1))
|
||||
debug_times.Add (o1, new Dictionary<object, DebugTimeData> ());
|
||||
|
||||
if (!debug_times[o1].ContainsKey (o2))
|
||||
debug_times[o1].Add (o2, data);
|
||||
else
|
||||
debug_times[o1][o2] = data;
|
||||
}
|
||||
|
||||
public static void DumpDebugTime (object o1)
|
||||
{
|
||||
Console.WriteLine (o1.ToString ());
|
||||
if (!debug_times.ContainsKey (o1))
|
||||
return;
|
||||
|
||||
foreach (var pair in debug_times[o1]) {
|
||||
Console.WriteLine (" {0}", pair.Key);
|
||||
Console.WriteLine (" Objects: {0}", pair.Value.time);
|
||||
Console.WriteLine (" Total: {0}", pair.Value.occurances);
|
||||
Console.WriteLine (" Average: {0}", new TimeSpan (pair.Value.time.Ticks / pair.Value.occurances));
|
||||
Console.WriteLine ();
|
||||
}
|
||||
|
||||
debug_times.Remove (o1);
|
||||
}
|
||||
|
||||
struct DebugTimeData
|
||||
{
|
||||
public TimeSpan time;
|
||||
public long occurances;
|
||||
|
||||
public DebugTimeData (TimeSpan time, int occurances)
|
||||
{
|
||||
this.time = time;
|
||||
this.occurances = occurances;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 43d149150f84518598c6d2c5500d9244
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 90815a5b58495074885ff707abaacda7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,411 @@
|
||||
//
|
||||
// File.cs: Provides tagging and properties support for the DSD (Direct Stream Digital) DSF
|
||||
// file Format.
|
||||
//
|
||||
// Author:
|
||||
// Helmut Wahrmann
|
||||
//
|
||||
// Copyright (C) 2014 Helmut Wahrmann
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
using TagLib.Id3v2;
|
||||
|
||||
namespace TagLib.Dsf
|
||||
{
|
||||
/// <summary>
|
||||
/// This class extends <see cref="TagLib.File" /> to provide
|
||||
/// support for reading and writing tags and properties for files
|
||||
/// using the AIFF file format.
|
||||
/// </summary>
|
||||
[SupportedMimeType ("taglib/dsf", "dsf")]
|
||||
[SupportedMimeType ("audio/x-dsf")]
|
||||
[SupportedMimeType ("audio/dsf")]
|
||||
[SupportedMimeType ("sound/dsf")]
|
||||
[SupportedMimeType ("application/x-dsf")]
|
||||
public class File : TagLib.File
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the address of the DSF header block.
|
||||
/// </summary>
|
||||
ByteVector header_block;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the Id3v2 tag.
|
||||
/// </summary>
|
||||
Id3v2.Tag tag;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the media properties.
|
||||
/// </summary>
|
||||
Properties properties;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the size of the DSF File
|
||||
/// </summary>
|
||||
readonly uint dsf_size;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the start position of the Tag
|
||||
/// </summary>
|
||||
long tag_start;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the end position of the Tag
|
||||
/// </summary>
|
||||
long tag_end;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Static Fields
|
||||
|
||||
/// <summary>
|
||||
/// The identifier used to recognize a DSF file.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "DSD "
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector FileIdentifier = "DSD ";
|
||||
|
||||
/// <summary>
|
||||
/// The identifier used to recognize a Format chunk.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "fmt "
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector FormatIdentifier = "fmt ";
|
||||
|
||||
/// <summary>
|
||||
/// The identifier used to recognize a DSF ID3 chunk.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "ID3 "
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector ID3Identifier = "ID3";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local file
|
||||
/// system and specified read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path, ReadStyle propertiesStyle)
|
||||
: this (new LocalFileAbstraction (path), propertiesStyle)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified path in the local file
|
||||
/// system with an average read style.
|
||||
/// </summary>
|
||||
/// <param name="path">
|
||||
/// A <see cref="string" /> object containing the path of the
|
||||
/// file to use in the new instance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="path" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public File (string path) : this (path, ReadStyle.Average)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction and
|
||||
/// specified read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <param name="propertiesStyle">
|
||||
/// A <see cref="ReadStyle" /> value specifying at what level
|
||||
/// of accuracy to read the media properties, or <see
|
||||
/// cref="ReadStyle.None" /> to ignore the properties.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction, ReadStyle propertiesStyle)
|
||||
: base (abstraction)
|
||||
{
|
||||
Mode = AccessMode.Read;
|
||||
try {
|
||||
Read (true, propertiesStyle, out dsf_size, out tag_start, out tag_end);
|
||||
} finally {
|
||||
Mode = AccessMode.Closed;
|
||||
}
|
||||
|
||||
TagTypesOnDisk = TagTypes;
|
||||
GetTag (TagTypes.Id3v2, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="File" /> for a specified file abstraction with an
|
||||
/// average read style.
|
||||
/// </summary>
|
||||
/// <param name="abstraction">
|
||||
/// A <see cref="TagLib.File.IFileAbstraction" /> object to use when
|
||||
/// reading from and writing to the file.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="abstraction" /> is <see langword="null"
|
||||
/// />.
|
||||
/// </exception>
|
||||
public File (IFileAbstraction abstraction)
|
||||
: this (abstraction, ReadStyle.Average)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets a abstract representation of all tags stored in the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TagLib.Tag" /> object representing all tags
|
||||
/// stored in the current instance.
|
||||
/// </value>
|
||||
public override Tag Tag {
|
||||
get { return tag; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the media properties of the file represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TagLib.Properties" /> object containing the
|
||||
/// media properties of the file represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public override Properties Properties {
|
||||
get { return properties; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Saves the changes made in the current instance to the
|
||||
/// file it represents.
|
||||
/// </summary>
|
||||
public override void Save ()
|
||||
{
|
||||
// Boilerplate
|
||||
PreSave ();
|
||||
|
||||
Mode = AccessMode.Write;
|
||||
try {
|
||||
long original_tag_length = tag_end - tag_start;
|
||||
ByteVector data = new ByteVector ();
|
||||
|
||||
if (tag == null) {
|
||||
// The tag has been removed
|
||||
RemoveBlock (tag_start, original_tag_length);
|
||||
Insert (ByteVector.FromULong (0, false), 20, 8);
|
||||
} else {
|
||||
data = tag.Render ();
|
||||
|
||||
// If tagging info cannot be found, place it at
|
||||
// the end of the file.
|
||||
if (tag_start == 0 || tag_end < tag_start) {
|
||||
tag_start = tag_end = Length;
|
||||
// Update the New Tag start
|
||||
Insert (ByteVector.FromULong ((ulong)(tag_start), false), 20, 8);
|
||||
}
|
||||
|
||||
// Insert the tagging data.
|
||||
Insert (data, tag_start, data.Count);
|
||||
}
|
||||
|
||||
long length = dsf_size + data.Count - original_tag_length;
|
||||
|
||||
// If the data size changed update the dsf size.
|
||||
if (data.Count - original_tag_length != 0 && tag_start <= dsf_size) {
|
||||
Insert (ByteVector.FromULong ((ulong)(length), false), 12, 8);
|
||||
}
|
||||
// Update the tag types.
|
||||
TagTypesOnDisk = TagTypes;
|
||||
} finally {
|
||||
Mode = AccessMode.Closed;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a set of tag types from the current instance.
|
||||
/// </summary>
|
||||
/// <param name="types">
|
||||
/// A bitwise combined <see cref="TagLib.TagTypes" /> value
|
||||
/// containing tag types to be removed from the file.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// In order to remove all tags from a file, pass <see
|
||||
/// cref="TagTypes.AllTags" /> as <paramref name="types" />.
|
||||
/// </remarks>
|
||||
public override void RemoveTags (TagTypes types)
|
||||
{
|
||||
if (types == TagTypes.Id3v2 ||
|
||||
types == TagTypes.AllTags) {
|
||||
tag = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a tag of a specified type from the current instance,
|
||||
/// optionally creating a new tag if possible.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// A <see cref="TagLib.TagTypes" /> value indicating the
|
||||
/// type of tag to read.
|
||||
/// </param>
|
||||
/// <param name="create">
|
||||
/// A <see cref="bool" /> value specifying whether or not to
|
||||
/// try and create the tag if one is not found.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="Tag" /> object containing the tag that was
|
||||
/// found in or added to the current instance. If no
|
||||
/// matching tag was found and none was created, <see
|
||||
/// langword="null" /> is returned.
|
||||
/// </returns>
|
||||
public override Tag GetTag (TagTypes type, bool create)
|
||||
{
|
||||
Tag id32_tag = null;
|
||||
|
||||
switch (type) {
|
||||
case TagTypes.Id3v2:
|
||||
if (tag == null && create) {
|
||||
tag = new Id3v2.Tag {
|
||||
Version = 2
|
||||
};
|
||||
}
|
||||
|
||||
id32_tag = tag;
|
||||
break;
|
||||
}
|
||||
|
||||
return id32_tag;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Reads the contents of the current instance determining
|
||||
/// the size of the dsf data, the area the tagging is in,
|
||||
/// and optionally reading in the tags and media properties.
|
||||
/// </summary>
|
||||
/// <param name="read_tags">
|
||||
/// If <see langword="true" />, any tags found will be read
|
||||
/// into the current instance.
|
||||
/// </param>
|
||||
/// <param name="style">
|
||||
/// A <see cref="ReadStyle"/> value specifying how the media
|
||||
/// data is to be read into the current instance.
|
||||
/// </param>
|
||||
/// <param name="dsf_size">
|
||||
/// A <see cref="uint"/> value reference to be filled with
|
||||
/// the size of the RIFF data as read from the file.
|
||||
/// </param>
|
||||
/// <param name="tag_start">
|
||||
/// A <see cref="long" /> value reference to be filled with
|
||||
/// the absolute seek position at which the tagging data
|
||||
/// starts.
|
||||
/// </param>
|
||||
/// <param name="tag_end">
|
||||
/// A <see cref="long" /> value reference to be filled with
|
||||
/// the absolute seek position at which the tagging data
|
||||
/// ends.
|
||||
/// </param>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// The file does not begin with <see cref="FileIdentifier"
|
||||
/// />.
|
||||
/// </exception>
|
||||
void Read (bool read_tags, ReadStyle style, out uint dsf_size, out long tag_start, out long tag_end)
|
||||
{
|
||||
Seek (0);
|
||||
if (ReadBlock (4) != FileIdentifier)
|
||||
throw new CorruptFileException ("File does not begin with DSF identifier");
|
||||
|
||||
Seek (12);
|
||||
dsf_size = ReadBlock (8).ToUInt (false);
|
||||
|
||||
tag_start = (long)ReadBlock (8).ToULong (false);
|
||||
tag_end = -1;
|
||||
|
||||
// Get the properties of the file
|
||||
if (header_block == null && style != ReadStyle.None) {
|
||||
long fmt_chunk_pos = Find (FormatIdentifier, 0);
|
||||
|
||||
if (fmt_chunk_pos == -1) {
|
||||
throw new CorruptFileException ("No Format chunk available in DSF file.");
|
||||
}
|
||||
|
||||
Seek (fmt_chunk_pos);
|
||||
header_block = ReadBlock ((int)StreamHeader.Size);
|
||||
|
||||
var header = new StreamHeader (header_block, dsf_size);
|
||||
properties = new Properties (TimeSpan.Zero, header);
|
||||
}
|
||||
|
||||
// Now position to the ID3 chunk, which we read before
|
||||
if (tag_start > 0) {
|
||||
Seek (tag_start);
|
||||
if (ReadBlock (3) == ID3Identifier) {
|
||||
if (read_tags && tag == null) {
|
||||
tag = new Id3v2.Tag (this, tag_start, style);
|
||||
}
|
||||
|
||||
// Get the length of the tag out of the ID3 chunk
|
||||
Seek (tag_start + 6);
|
||||
uint tag_size = SynchData.ToUInt (ReadBlock (4)) + 10;
|
||||
|
||||
InvariantStartPosition = tag_start;
|
||||
tag_end = InvariantEndPosition = tag_start + tag_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8b09427e5619eec8580e4b303b312ac9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,292 @@
|
||||
//
|
||||
// StreamHeader.cs: Provides tagging and properties support for the DSD
|
||||
// (Direct Stream Digital) DSF properties.
|
||||
//
|
||||
// Author:
|
||||
// Helmut Wahrmann
|
||||
//
|
||||
// Copyright (C) 2014 Helmut Wahrmann
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License version
|
||||
// 2.1 as published by the Free Software Foundation.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
// USA
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace TagLib.Dsf
|
||||
{
|
||||
/// <summary>
|
||||
/// This struct implements <see cref="IAudioCodec" /> to provide
|
||||
/// support for reading DSF stream properties.
|
||||
/// </summary>
|
||||
public struct StreamHeader : IAudioCodec, ILosslessAudioCodec
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Contains the version.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (12-15).
|
||||
/// Currently only value of 1 is valid.
|
||||
/// </remarks>
|
||||
readonly ushort version;
|
||||
|
||||
/// <summary>
|
||||
/// The Format Id.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (16-19).
|
||||
/// 0: DSD Raw
|
||||
/// </remarks>
|
||||
readonly ushort format_id;
|
||||
|
||||
/// <summary>
|
||||
/// The Channel Type.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (20-23).
|
||||
/// 1: mono
|
||||
/// 2:stereo
|
||||
/// 3:3 channels
|
||||
/// 4: quad
|
||||
/// 5: 4 channels
|
||||
/// 6: 5 channels
|
||||
/// 7: 5.1 channels
|
||||
/// </remarks>
|
||||
readonly ushort channel_type;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of channels.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (24-27).
|
||||
/// 1 is monophonic, 2 is stereo, 4 means 4 channels, etc..
|
||||
/// up to 6 channels may be represented
|
||||
/// </remarks>
|
||||
readonly ushort channels;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the sample rate.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (28-31).
|
||||
/// the sample rate at which the sound is to be played back,
|
||||
/// in Hz: 2822400, 5644800
|
||||
/// </remarks>
|
||||
readonly ulong sample_rate;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of bits per sample.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (32-35).
|
||||
/// It can be any number from 1 to 8.
|
||||
/// </remarks>
|
||||
readonly ushort bits_per_sample;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the number of sample frames per channel.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (36-43).
|
||||
/// </remarks>
|
||||
readonly ulong sample_count;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the Block size per channel.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is stored in bytes (44-47).
|
||||
/// Always: 4096
|
||||
/// </remarks>
|
||||
readonly uint channel_blksize;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the length of the audio stream.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is provided by the constructor.
|
||||
/// </remarks>
|
||||
readonly long stream_length;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Static Fields
|
||||
|
||||
/// <summary>
|
||||
/// The size of an DSF Format chunk
|
||||
/// </summary>
|
||||
public const uint Size = 52;
|
||||
|
||||
/// <summary>
|
||||
/// The identifier used to recognize a DSF file.
|
||||
/// Altough an DSF file start with "DSD ", we're interested
|
||||
/// in the Format chunk only, which contains the properties we need.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// "fmt "
|
||||
/// </value>
|
||||
public static readonly ReadOnlyByteVector FileIdentifier = "fmt ";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and initializes a new instance of <see
|
||||
/// cref="StreamHeader" /> for a specified header block and
|
||||
/// stream length.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// A <see cref="ByteVector" /> object containing the stream
|
||||
/// header data.
|
||||
/// </param>
|
||||
/// <param name="streamLength">
|
||||
/// A <see cref="long" /> value containing the length of the
|
||||
/// DSF Audio stream in bytes.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="data" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
/// <exception cref="CorruptFileException">
|
||||
/// <paramref name="data" /> does not begin with <see
|
||||
/// cref="FileIdentifier" />
|
||||
/// </exception>
|
||||
public StreamHeader (ByteVector data, long streamLength)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException (nameof (data));
|
||||
|
||||
|
||||
if (!data.StartsWith (FileIdentifier))
|
||||
throw new CorruptFileException ("Data does not begin with identifier.");
|
||||
|
||||
stream_length = streamLength;
|
||||
|
||||
// The first 12 bytes contain the Format chunk identifier "fmt "
|
||||
// And the size of the format chunk, which is always 52
|
||||
version = data.Mid (12, 4).ToUShort (false);
|
||||
format_id = data.Mid (16, 4).ToUShort (false);
|
||||
channel_type = data.Mid (20, 4).ToUShort (false);
|
||||
channels = data.Mid (24, 4).ToUShort (false);
|
||||
sample_rate = data.Mid (28, 4).ToULong (false);
|
||||
bits_per_sample = data.Mid (32, 4).ToUShort (false);
|
||||
sample_count = data.Mid (36, 8).ToULong (false);
|
||||
channel_blksize = data.Mid (44, 4).ToUShort (false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the duration of the media represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="TimeSpan" /> containing the duration of the
|
||||
/// media represented by the current instance.
|
||||
/// </value>
|
||||
public TimeSpan Duration {
|
||||
get {
|
||||
if (sample_rate <= 0 || sample_count <= 0)
|
||||
return TimeSpan.Zero;
|
||||
|
||||
return TimeSpan.FromSeconds (sample_count / (double)sample_rate);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the types of media represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Always <see cref="MediaTypes.Audio" />.
|
||||
/// </value>
|
||||
public MediaTypes MediaTypes {
|
||||
get { return MediaTypes.Audio; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a text description of the media represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string" /> object containing a description
|
||||
/// of the media represented by the current instance.
|
||||
/// </value>
|
||||
public string Description {
|
||||
get { return "DSF Audio"; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bitrate of the audio represented by the current
|
||||
/// instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing a bitrate of the
|
||||
/// audio represented by the current instance.
|
||||
/// </value>
|
||||
public int AudioBitrate {
|
||||
get {
|
||||
TimeSpan d = Duration;
|
||||
if (d <= TimeSpan.Zero)
|
||||
return 0;
|
||||
|
||||
return (int)((stream_length * 8L) / d.TotalSeconds) / 1000;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sample rate of the audio represented by the
|
||||
/// current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the sample rate of
|
||||
/// the audio represented by the current instance.
|
||||
/// </value>
|
||||
public int AudioSampleRate {
|
||||
get { return (int)sample_rate; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of channels in the audio represented by
|
||||
/// the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the number of
|
||||
/// channels in the audio represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public int AudioChannels {
|
||||
get { return channels; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of bits per sample in the audio
|
||||
/// represented by the current instance.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="int" /> value containing the number of bits
|
||||
/// per sample in the audio represented by the current
|
||||
/// instance.
|
||||
/// </value>
|
||||
public int BitsPerSample {
|
||||
get { return bits_per_sample; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Loaded 100 of 2025 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user