diff --git a/CUETools.Processor/CUETools.Processor.csproj b/CUETools.Processor/CUETools.Processor.csproj index 28c52e9..d1dfd50 100644 --- a/CUETools.Processor/CUETools.Processor.csproj +++ b/CUETools.Processor/CUETools.Processor.csproj @@ -98,6 +98,7 @@ + diff --git a/CUETools.Processor/Processor.cs b/CUETools.Processor/Processor.cs index c3a2a24..16a72b4 100644 --- a/CUETools.Processor/Processor.cs +++ b/CUETools.Processor/Processor.cs @@ -61,6 +61,7 @@ namespace CUETools.Processor { None, Verify, + VerifyPlusCRCs, VerifyThenConvert, VerifyAndConvert } @@ -479,9 +480,23 @@ namespace CUETools.Processor public bool ContinueOperation = true; } + public class CUEToolsSourceFile + { + public string path; + public string contents; + public bool isEAC; + + public CUEToolsSourceFile(string _path, StreamReader reader) + { + path = _path; + contents = reader.ReadToEnd(); + reader.Close(); + } + } + public class CUEToolsSelectionEventArgs { - public string[] choices; + public object[] choices; public int selection = -1; } @@ -740,22 +755,13 @@ namespace CUETools.Processor cueSheet = CUESheet.CreateDummyCUESheet(pathIn, "*." + _config.udc1Extension); if (cueSheet == null) throw new Exception("Input directory doesn't contain supported audio files."); - sr = new StringReader(cueSheet); - if (CUEToolsSelection != null) - { - CUEToolsSelectionEventArgs e = new CUEToolsSelectionEventArgs(); - e.choices = Directory.GetFiles(pathIn, "*.log"); - if (e.choices.Length > 0) - { - CUEToolsSelection(this, e); - if (e.selection != -1) - { - StreamReader logReader = new StreamReader(e.choices[e.selection], CUESheet.Encoding); - _eacLog = logReader.ReadToEnd(); - logReader.Close(); - } - } - } + sr = new StringReader(cueSheet); + + List logFiles = new List(); + foreach (string logPath in Directory.GetFiles(pathIn, "*.log")) + logFiles.Add(new CUEToolsSourceFile(logPath, new StreamReader(logPath, CUESheet.Encoding))); + CUEToolsSourceFile selectedLogFile = ChooseFile(logFiles, null, false); + _eacLog = selectedLogFile != null ? selectedLogFile.contents : null; } else if (Path.GetExtension(pathIn).ToLower() == ".zip" || Path.GetExtension(pathIn).ToLower() == ".rar") { @@ -795,64 +801,28 @@ namespace CUETools.Processor } } - string cueName = null, cueText = null, logName = null; - List cueNames = new List(); - List logNames = new List(); - + List logFiles = new List(); + List cueFiles = new List(); foreach (string s in _archiveContents) { - if (Path.GetExtension(s).ToLower() == ".cue") - cueNames.Add(s); - if (Path.GetExtension(s).ToLower() == ".log") - logNames.Add(s); + if (Path.GetExtension(s).ToLower() == ".cue" || Path.GetExtension(s).ToLower() == ".log") + { + Stream archiveStream = OpenArchive(s, false); + CUEToolsSourceFile sourceFile = new CUEToolsSourceFile(s, new StreamReader(archiveStream, CUESheet.Encoding)); + archiveStream.Close(); + if (Path.GetExtension(s).ToLower() == ".cue") + cueFiles.Add(sourceFile); + else + logFiles.Add(sourceFile); + } } - if (cueNames.Count == 0) - throw new Exception("Input archive doesn't contain a cue sheet."); - if (cueNames.Count == 1) - cueName = cueNames[0]; - if (cueName == null && CUEToolsSelection != null) - { - CUEToolsSelectionEventArgs e = new CUEToolsSelectionEventArgs(); - e.choices = cueNames.ToArray(); - CUEToolsSelection(this, e); - if (e.selection != -1) - cueName = e.choices[e.selection]; - } - if (cueName == null) - throw new Exception("Input archive contains several cue sheets."); - - if (logNames.Contains(Path.ChangeExtension(cueName, ".log"))) - logName = Path.ChangeExtension(cueName, ".log"); - if (logName == null && CUEToolsSelection != null && logNames.Count > 0) - { - CUEToolsSelectionEventArgs e = new CUEToolsSelectionEventArgs(); - e.choices = logNames.ToArray(); - CUEToolsSelection(this, e); - if (e.selection != -1) - logName = e.choices[e.selection]; - } - - if (cueName != null) - { - Stream archiveStream = OpenArchive(cueName, false); - StreamReader cueReader = new StreamReader(archiveStream, CUESheet.Encoding); - cueText = cueReader.ReadToEnd(); - cueReader.Close(); - archiveStream.Close(); - if (cueText == "") - throw new Exception("Empty cue sheet."); - } - if (cueText == null) - throw new Exception("Input archive doesn't contain a cue sheet."); - if (logName != null) - { - Stream archiveStream = OpenArchive(logName, false); - StreamReader logReader = new StreamReader(archiveStream, CUESheet.Encoding); - _eacLog = logReader.ReadToEnd(); - logReader.Close(); - archiveStream.Close(); - } - _archiveCUEpath = Path.GetDirectoryName(cueName); + CUEToolsSourceFile selectedCUEFile = ChooseFile(cueFiles, null, true); + if (selectedCUEFile == null || selectedCUEFile.contents == "") + throw new Exception("Input archive doesn't contain a usable cue sheet."); + CUEToolsSourceFile selectedLogFile = ChooseFile(logFiles, Path.GetFileNameWithoutExtension(selectedCUEFile.path), true); + _eacLog = selectedLogFile != null ? selectedLogFile.contents : null; + _archiveCUEpath = Path.GetDirectoryName(selectedCUEFile.path); + string cueText = selectedCUEFile.contents; if (_config.autoCorrectFilenames) cueText = CorrectAudioFilenames(_archiveCUEpath, cueText, false, _archiveContents); sr = new StringReader(cueText); @@ -864,29 +834,13 @@ namespace CUETools.Processor else sr = new StreamReader (pathIn, CUESheet.Encoding); - string logPath = Path.ChangeExtension(pathIn, ".log"); - if (System.IO.File.Exists(logPath)) - { - StreamReader logReader = new StreamReader(logPath, CUESheet.Encoding); - _eacLog = logReader.ReadToEnd(); - logReader.Close(); - } - else if (CUEToolsSelection != null) - { - CUEToolsSelectionEventArgs e = new CUEToolsSelectionEventArgs(); - e.choices = Directory.GetFiles(cueDir == "" ? "." : cueDir, "*.log"); - if (e.choices.Length > 0) - { - CUEToolsSelection(this, e); - if (e.selection != -1) - { - StreamReader logReader = new StreamReader(e.choices[e.selection], CUESheet.Encoding); - _eacLog = logReader.ReadToEnd(); - logReader.Close(); - } - } - } - } else + List logFiles = new List(); + foreach (string logPath in Directory.GetFiles(cueDir == "" ? "." : cueDir, "*.log")) + logFiles.Add(new CUEToolsSourceFile(logPath, new StreamReader(logPath, CUESheet.Encoding))); + CUEToolsSourceFile selectedLogFile = ChooseFile(logFiles, Path.GetFileNameWithoutExtension(pathIn), false); + _eacLog = selectedLogFile != null ? selectedLogFile.contents : null; + } + else { string cuesheetTag = null; TagLib.File fileInfo; @@ -1332,6 +1286,43 @@ namespace CUETools.Processor } } + internal CUEToolsSourceFile ChooseFile(List sourceFiles, string defaultFileName, bool quietIfSingle) + { + if (sourceFiles.Count <= 0) + return null; + + if (defaultFileName != null) + { + CUEToolsSourceFile defaultFile = null; + foreach (CUEToolsSourceFile file in sourceFiles) + if (Path.GetFileNameWithoutExtension(file.path).ToLower() == defaultFileName.ToLower()) + { + if (defaultFile != null) + { + defaultFile = null; + break; + } + defaultFile = file; + } + if (defaultFile != null) + return defaultFile; + } + + if (quietIfSingle && sourceFiles.Count == 1) + return sourceFiles[0]; + + if (CUEToolsSelection == null) + return null; + + CUEToolsSelectionEventArgs e = new CUEToolsSelectionEventArgs(); + e.choices = sourceFiles.ToArray(); + CUEToolsSelection(this, e); + if (e.selection == -1) + return null; + + return sourceFiles[e.selection]; + } + internal Stream OpenArchive(string fileName, bool showProgress) { #if !MONO @@ -1347,9 +1338,9 @@ namespace CUETools.Processor if (Path.GetExtension(_archivePath).ToLower() == ".zip") { SeekableZipStream zipStream = new SeekableZipStream(_archivePath, fileName); - zipStream.PasswordRequired += new PasswordRequiredHandler(unrar_PasswordRequired); + zipStream.PasswordRequired += new ZipPasswordRequiredHandler(unzip_PasswordRequired); if (showProgress) - zipStream.ExtractionProgress += new ExtractionProgressHandler(unrar_ExtractionProgress); + zipStream.ExtractionProgress += new ZipExtractionProgressHandler(unzip_ExtractionProgress); return zipStream; } throw new Exception("Unknown archive type."); @@ -1370,16 +1361,7 @@ namespace CUETools.Processor #if !MONO private void CDReadProgress(object sender, ReadProgressArgs e) { - lock (this) - { - if (_stop) - throw new StopException(); - if (_pause) - { - ShowProgress("Paused...", 0, 0, null, null); - Monitor.Wait(this); - } - } + CheckStop(); if (this.CUEToolsProgress == null) return; CDDriveReader audioSource = (CDDriveReader)sender; @@ -1406,6 +1388,7 @@ namespace CUETools.Processor private void unrar_ExtractionProgress(object sender, ExtractionProgressEventArgs e) { + CheckStop(); if (this.CUEToolsProgress == null) return; _progress.percentTrck = e.PercentComplete/100; @@ -1436,6 +1419,38 @@ namespace CUETools.Processor } #endif + private void unzip_ExtractionProgress(object sender, ZipExtractionProgressEventArgs e) + { + CheckStop(); + if (this.CUEToolsProgress == null) + return; + _progress.percentTrck = e.PercentComplete / 100; + this.CUEToolsProgress(this, _progress); + } + + private void unzip_PasswordRequired(object sender, ZipPasswordRequiredEventArgs e) + { + if (_archivePassword != null) + { + e.ContinueOperation = true; + e.Password = _archivePassword; + return; + } + if (this.PasswordRequired != null) + { + ArchivePasswordRequiredEventArgs e1 = new ArchivePasswordRequiredEventArgs(); + this.PasswordRequired(this, e1); + if (e1.ContinueOperation && e1.Password != "") + { + _archivePassword = e1.Password; + e.ContinueOperation = true; + e.Password = e1.Password; + return; + } + } + throw new IOException("Password is required for extraction."); + } + public delegate string GetStringTagProvider(TagLib.File file); public string GetCommonTag(GetStringTagProvider provider) @@ -1943,7 +1958,7 @@ namespace CUETools.Processor } } - if (_accurateRipMode != AccurateRipMode.Verify) + if (_accurateRipMode != AccurateRipMode.Verify && _accurateRipMode != AccurateRipMode.VerifyPlusCRCs) for (int i = 0; i < destPaths.Length; i++) for (int j = 0; j < _sourcePaths.Count; j++) if (destPaths[i].ToLower() == _sourcePaths[j].ToLower()) @@ -1972,17 +1987,10 @@ namespace CUETools.Processor break; } ShowProgress((string)"Contacting AccurateRip database...", 0, (dtl - minDTL) / 75.0, null, null); + CheckStop(); lock (this) { - if (_stop) - throw new StopException(); - if (_pause) - { - ShowProgress("Paused...", 0, 0, null, null); - Monitor.Wait(this); - } - else - Monitor.Wait(this, 1000); + Monitor.Wait(this, 1000); } } if (_arVerify.AccResult != HttpStatusCode.OK) @@ -1993,6 +2001,23 @@ namespace CUETools.Processor else _arVerify.ContactAccurateRip(_accurateRipId); + if (_accurateRipMode == AccurateRipMode.Verify) + { + if (_arVerify.AccResult != HttpStatusCode.OK) + { + if (_config.writeArLogOnVerify) + { + if (!Directory.Exists(dir)) + Directory.CreateDirectory(dir); + StreamWriter sw = new StreamWriter(Path.ChangeExtension(_cuePath, ".accurip"), + false, CUESheet.Encoding); + GenerateAccurateRipLog(sw); + sw.Close(); + } + return; + } + } + if (_accurateRipMode == AccurateRipMode.VerifyThenConvert) { if (_arVerify.AccResult != HttpStatusCode.OK && !_isCD) @@ -2047,16 +2072,16 @@ namespace CUETools.Processor if (!SkipOutput) { - if (_accurateRipMode != AccurateRipMode.Verify) + if (_accurateRipMode != AccurateRipMode.Verify && _accurateRipMode != AccurateRipMode.VerifyPlusCRCs) { if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); } if (_isCD) destLengths = CalculateAudioFileLengths(style); // need to recalc, might have changed after scanning the CD - if (_outputFormat != OutputAudioFormat.NoAudio || _accurateRipMode == AccurateRipMode.Verify) - WriteAudioFilesPass(dir, style, destPaths, destLengths, htoaToFile, _accurateRipMode == AccurateRipMode.Verify); - if (_accurateRipMode != AccurateRipMode.Verify) + if (_outputFormat != OutputAudioFormat.NoAudio || _accurateRipMode == AccurateRipMode.Verify || _accurateRipMode == AccurateRipMode.VerifyPlusCRCs) + WriteAudioFilesPass(dir, style, destPaths, destLengths, htoaToFile, _accurateRipMode == AccurateRipMode.Verify || _accurateRipMode == AccurateRipMode.VerifyPlusCRCs); + if (_accurateRipMode != AccurateRipMode.Verify && _accurateRipMode != AccurateRipMode.VerifyPlusCRCs) { string logContents = LOGContents(); string cueContents = CUESheetContents(style); @@ -2140,11 +2165,12 @@ namespace CUETools.Processor } } - if (_accurateRipMode == AccurateRipMode.Verify || + if (_accurateRipMode == AccurateRipMode.Verify || + _accurateRipMode == AccurateRipMode.VerifyPlusCRCs || (_accurateRipMode != AccurateRipMode.None && _outputFormat != OutputAudioFormat.NoAudio)) { ShowProgress((string)"Generating AccurateRip report...", 0, 0, null, null); - if (_accurateRipMode == AccurateRipMode.Verify && _config.writeArTagsOnVerify && _writeOffset == 0 && !_isArchive && !_isCD) + if ((_accurateRipMode == AccurateRipMode.Verify || _accurateRipMode == AccurateRipMode.VerifyPlusCRCs) && _config.writeArTagsOnVerify && _writeOffset == 0 && !_isArchive && !_isCD) { uint tracksMatch; int bestOffset; @@ -2174,8 +2200,8 @@ namespace CUETools.Processor } } - if ((_accurateRipMode != AccurateRipMode.Verify && _config.writeArLogOnConvert) || - (_accurateRipMode == AccurateRipMode.Verify && _config.writeArLogOnVerify)) + if ((_accurateRipMode != AccurateRipMode.Verify && _accurateRipMode != AccurateRipMode.VerifyPlusCRCs && _config.writeArLogOnConvert) || + ((_accurateRipMode == AccurateRipMode.Verify || _accurateRipMode == AccurateRipMode.VerifyPlusCRCs) && _config.writeArLogOnVerify)) { if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); @@ -2525,16 +2551,7 @@ namespace CUETools.Processor samplesRemIndex -= copyCount; samplesRemSource -= copyCount; - lock (this) - { - if (_stop) - throw new StopException(); - if (_pause) - { - ShowProgress("Paused...", 0, 0, null, null); - Monitor.Wait(this); - } - } + CheckStop(); } } } @@ -2734,6 +2751,20 @@ namespace CUETools.Processor return fileLengths; } + private void CheckStop() + { + lock (this) + { + if (_stop) + throw new StopException(); + if (_pause) + { + ShowProgress("Paused...", 0, 0, null, null); + Monitor.Wait(this); + } + } + } + public void Stop() { lock (this) { if (_pause) @@ -2766,6 +2797,14 @@ namespace CUETools.Processor } } + public CDImageLayout TOC + { + get + { + return _toc; + } + } + private IAudioDest GetAudioDest(string path, int finalSampleCount, int bps, bool noOutput) { if (noOutput) @@ -3007,123 +3046,6 @@ namespace CUETools.Processor } } - public class SeekableZipStream : Stream - { - ZipFile zipFile; - ZipEntry zipEntry; - Stream zipStream; - long position; - byte[] temp; - - public SeekableZipStream(string path, string fileName) - { - zipFile = new ZipFile(path); - zipEntry = zipFile.GetEntry(fileName); - if (zipEntry == null) - throw new Exception("Archive entry not found."); - zipStream = zipFile.GetInputStream(zipEntry); - temp = new byte[65536]; - position = 0; - } - public override bool CanRead - { - get { return true; } - } - public override bool CanSeek - { - get { return true; } - } - public override bool CanWrite - { - get { return false; } - } - public override long Length - { - get - { - return zipEntry.Size; - } - } - public override long Position - { - get { return position; } - set { Seek(value, SeekOrigin.Begin); } - } - public override void Close() - { - zipStream.Close(); - zipEntry = null; - zipFile.Close(); - } - public override void Flush() - { - throw new NotSupportedException(); - } - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - public override int Read(byte[] buffer, int offset, int count) - { - if (position == 0 && zipEntry.IsCrypted && ((ZipInputStream)zipStream).Password == null && PasswordRequired != null) - { - PasswordRequiredEventArgs e = new PasswordRequiredEventArgs(); - PasswordRequired(this, e); - if (e.ContinueOperation && e.Password.Length > 0) - ((ZipInputStream)zipStream).Password = e.Password; - } - // TODO: always save to a local temp circular buffer for optimization of the backwards seek. - int total = zipStream.Read(buffer, offset, count); - position += total; - if (ExtractionProgress != null) - { - ExtractionProgressEventArgs e = new ExtractionProgressEventArgs(); - e.BytesExtracted = position; - e.FileName = zipEntry.Name; - e.FileSize = zipEntry.Size; - e.PercentComplete = 100.0 * position / zipEntry.Size; - ExtractionProgress(this, e); - } - return total; - } - public override long Seek(long offset, SeekOrigin origin) - { - long seek_to; - switch (origin) - { - case SeekOrigin.Begin: - seek_to = offset; - break; - case SeekOrigin.Current: - seek_to = Position + offset; - break; - case SeekOrigin.End: - seek_to = Length + offset; - break; - default: - throw new NotSupportedException(); - } - if (seek_to < 0 || seek_to > Length) - throw new IOException("Invalid seek"); - if (seek_to < position) - { - zipStream.Close(); - zipStream = zipFile.GetInputStream(zipEntry); - position = 0; - } - while (seek_to > position) - if (Read(temp, 0, (int) Math.Min(seek_to - position, (long) temp.Length)) <= 0) - throw new IOException("Invalid seek"); - return position; - } - public override void Write(byte[] array, int offset, int count) - { - throw new NotSupportedException(); - } - public event PasswordRequiredHandler PasswordRequired; - public event ExtractionProgressHandler ExtractionProgress; - } - public class ArchiveFileAbstraction : TagLib.File.IFileAbstraction { private string name; diff --git a/CUETools.Processor/SeekableZipStream.cs b/CUETools.Processor/SeekableZipStream.cs new file mode 100644 index 0000000..4346ff9 --- /dev/null +++ b/CUETools.Processor/SeekableZipStream.cs @@ -0,0 +1,167 @@ +using System; +using System.IO; +using ICSharpCode.SharpZipLib.Zip; + +namespace CUETools.Processor +{ + #region Event Delegate Definitions + + /// + /// Represents the method that will handle extraction progress events + /// + public delegate void ZipExtractionProgressHandler(object sender, ZipExtractionProgressEventArgs e); + /// + /// Represents the method that will handle password required events + /// + public delegate void ZipPasswordRequiredHandler(object sender, ZipPasswordRequiredEventArgs e); + + #endregion + + public class SeekableZipStream : Stream + { + ZipFile zipFile; + ZipEntry zipEntry; + Stream zipStream; + long position; + byte[] temp; + + public SeekableZipStream(string path, string fileName) + { + zipFile = new ZipFile(path); + zipEntry = zipFile.GetEntry(fileName); + if (zipEntry == null) + throw new Exception("Archive entry not found."); + zipStream = zipFile.GetInputStream(zipEntry); + temp = new byte[65536]; + position = 0; + } + + public override bool CanRead + { + get { return true; } + } + + public override bool CanSeek + { + get { return true; } + } + + public override bool CanWrite + { + get { return false; } + } + + public override long Length + { + get + { + return zipEntry.Size; + } + } + + public override long Position + { + get { return position; } + set { Seek(value, SeekOrigin.Begin); } + } + + public override void Close() + { + zipStream.Close(); + zipEntry = null; + zipFile.Close(); + } + + public override void Flush() + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (position == 0 && zipEntry.IsCrypted && ((ZipInputStream)zipStream).Password == null && PasswordRequired != null) + { + ZipPasswordRequiredEventArgs e = new ZipPasswordRequiredEventArgs(); + PasswordRequired(this, e); + if (e.ContinueOperation && e.Password.Length > 0) + ((ZipInputStream)zipStream).Password = e.Password; + } + // TODO: always save to a local temp circular buffer for optimization of the backwards seek. + int total = zipStream.Read(buffer, offset, count); + position += total; + if (ExtractionProgress != null) + { + ZipExtractionProgressEventArgs e = new ZipExtractionProgressEventArgs(); + e.BytesExtracted = position; + e.FileName = zipEntry.Name; + e.FileSize = zipEntry.Size; + e.PercentComplete = 100.0 * position / zipEntry.Size; + ExtractionProgress(this, e); + } + return total; + } + + public override long Seek(long offset, SeekOrigin origin) + { + long seek_to; + switch (origin) + { + case SeekOrigin.Begin: + seek_to = offset; + break; + case SeekOrigin.Current: + seek_to = Position + offset; + break; + case SeekOrigin.End: + seek_to = Length + offset; + break; + default: + throw new NotSupportedException(); + } + if (seek_to < 0 || seek_to > Length) + throw new IOException("Invalid seek"); + if (seek_to < position) + { + zipStream.Close(); + zipStream = zipFile.GetInputStream(zipEntry); + position = 0; + } + while (seek_to > position) + if (Read(temp, 0, (int)Math.Min(seek_to - position, (long)temp.Length)) <= 0) + throw new IOException("Invalid seek"); + return position; + } + + public override void Write(byte[] array, int offset, int count) + { + throw new NotSupportedException(); + } + + public event ZipPasswordRequiredHandler PasswordRequired; + public event ZipExtractionProgressHandler ExtractionProgress; + } + + #region Event Argument Classes + + public class ZipPasswordRequiredEventArgs + { + public string Password = string.Empty; + public bool ContinueOperation = true; + } + + public class ZipExtractionProgressEventArgs + { + public string FileName; + public long FileSize; + public long BytesExtracted; + public double PercentComplete; + public bool ContinueOperation = true; + } + + #endregion +} diff --git a/CUETools.Processor/Tagging.cs b/CUETools.Processor/Tagging.cs index a3ef447..e762d96 100644 --- a/CUETools.Processor/Tagging.cs +++ b/CUETools.Processor/Tagging.cs @@ -18,6 +18,8 @@ namespace CUETools.Processor xiph.SetField(tag, tags.GetValues(tag)); return true; } + if (fileInfo is TagLib.Mpeg4.File) + return true; if (fileInfo is TagLib.UserDefined.File && !(fileInfo as TagLib.UserDefined.File).SupportsAPEv2) { if (!(fileInfo as TagLib.UserDefined.File).SupportsID3v2) diff --git a/CUETools.Processor/UserDefined.cs b/CUETools.Processor/UserDefined.cs index 2a1a061..98ffc70 100644 --- a/CUETools.Processor/UserDefined.cs +++ b/CUETools.Processor/UserDefined.cs @@ -1,80 +1,80 @@ -// -// File.cs: Provides tagging and properties support for WavPack files. -// -// Author: -// Brian Nickel (brian.nickel@gmail.com) -// -// Original Source: -// wvfile.cpp from libtunepimp -// -// Copyright (C) 2006-2007 Brian Nickel -// Copyright (C) 2006 by Lukáš Lalinský (Original Implementation) -// 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; -using TagLib; - -namespace TagLib.UserDefined { - /// - /// This class extends to - /// provide tagging and properties support for user defined format files. - /// - /// - /// A will be added automatically to - /// any file that doesn't contain one. This change does not effect - /// the file and can be reversed using the following method: - /// file.RemoveTags (file.TagTypes & ~file.TagTypesOnDisk); - /// - [SupportedMimeType("taglib/misc", "misc")] - public class File : TagLib.NonContainer.File - { - #region Private Fields - +// +// File.cs: Provides tagging and properties support for WavPack files. +// +// Author: +// Brian Nickel (brian.nickel@gmail.com) +// +// Original Source: +// wvfile.cpp from libtunepimp +// +// Copyright (C) 2006-2007 Brian Nickel +// Copyright (C) 2006 by Lukáš Lalinský (Original Implementation) +// 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; +using TagLib; + +namespace TagLib.UserDefined { + /// + /// This class extends to + /// provide tagging and properties support for user defined format files. + /// + /// + /// A will be added automatically to + /// any file that doesn't contain one. This change does not effect + /// the file and can be reversed using the following method: + /// file.RemoveTags (file.TagTypes & ~file.TagTypesOnDisk); + /// + [SupportedMimeType("taglib/misc", "misc")] + public class File : TagLib.NonContainer.File + { + #region Private Fields + private bool _supportsAPEv2 = true; - private bool _supportsID3v2 = true; - - #endregion - - - - #region Constructors - - /// - /// Constructs and initializes a new instance of for a specified path in the local file - /// system and specified read style. - /// - /// - /// A object containing the path of the - /// file to use in the new instance. - /// - /// - /// A value specifying at what level - /// of accuracy to read the media properties, or to ignore the properties. - /// - /// - /// is . - /// - public File (string path, ReadStyle propertiesStyle, bool supportsAPEv2, bool supportsID3v2) - : base (path, propertiesStyle) - { + private bool _supportsID3v2 = true; + + #endregion + + + + #region Constructors + + /// + /// Constructs and initializes a new instance of for a specified path in the local file + /// system and specified read style. + /// + /// + /// A object containing the path of the + /// file to use in the new instance. + /// + /// + /// A value specifying at what level + /// of accuracy to read the media properties, or to ignore the properties. + /// + /// + /// is . + /// + public File (string path, ReadStyle propertiesStyle, bool supportsAPEv2, bool supportsID3v2) + : base (path, propertiesStyle) + { _supportsAPEv2 = supportsAPEv2; _supportsID3v2 = supportsID3v2; // Make sure we have an APE tag. @@ -83,23 +83,23 @@ namespace TagLib.UserDefined { else if (_supportsID3v2) GetTag(TagTypes.Id3v2, true); - } - - /// - /// Constructs and initializes a new instance of for a specified path in the local file - /// system with an average read style. - /// - /// - /// A object containing the path of the - /// file to use in the new instance. - /// - /// - /// is . + } + + /// + /// Constructs and initializes a new instance of for a specified path in the local file + /// system with an average read style. + /// + /// + /// A object containing the path of the + /// file to use in the new instance. + /// + /// + /// is . /// public File(string path, bool supportsAPEv2, bool supportsID3v2) - : base(path) - { + : base(path) + { _supportsAPEv2 = supportsAPEv2; _supportsID3v2 = supportsID3v2; // Make sure we have an APE tag. @@ -108,56 +108,30 @@ namespace TagLib.UserDefined { else if (_supportsID3v2) GetTag(TagTypes.Id3v2, true); - } - - /// - /// Constructs and initializes a new instance of for a specified file abstraction and - /// specified read style. - /// - /// - /// A object to use when - /// reading from and writing to the file. - /// - /// - /// A value specifying at what level - /// of accuracy to read the media properties, or to ignore the properties. - /// - /// - /// is . - /// - public File (File.IFileAbstraction abstraction, - ReadStyle propertiesStyle, bool supportsAPEv2, bool supportsID3v2) - : base (abstraction, propertiesStyle) - { - _supportsAPEv2 = supportsAPEv2; - _supportsID3v2 = supportsID3v2; - // Make sure we have an APE tag. - if (_supportsAPEv2) - GetTag(TagTypes.Ape, true); - else - if (_supportsID3v2) - GetTag(TagTypes.Id3v2, true); - } - - /// - /// Constructs and initializes a new instance of for a specified file abstraction with an - /// average read style. - /// - /// - /// A object to use when - /// reading from and writing to the file. - /// - /// - /// is . + } + + /// + /// Constructs and initializes a new instance of for a specified file abstraction and + /// specified read style. + /// + /// + /// A object to use when + /// reading from and writing to the file. + /// + /// + /// A value specifying at what level + /// of accuracy to read the media properties, or to ignore the properties. + /// + /// + /// is . /// - public File(File.IFileAbstraction abstraction, bool supportsAPEv2, bool supportsID3v2) - : base (abstraction) - { + public File (File.IFileAbstraction abstraction, + ReadStyle propertiesStyle, bool supportsAPEv2, bool supportsID3v2) + : base (abstraction, propertiesStyle) + { _supportsAPEv2 = supportsAPEv2; _supportsID3v2 = supportsID3v2; // Make sure we have an APE tag. @@ -166,20 +140,46 @@ namespace TagLib.UserDefined { else if (_supportsID3v2) GetTag(TagTypes.Id3v2, true); - } - - #endregion - - - - #region Public Methods - - public bool SupportsAPEv2 - { - get - { - return _supportsAPEv2; - } + } + + /// + /// Constructs and initializes a new instance of for a specified file abstraction with an + /// average read style. + /// + /// + /// A object to use when + /// reading from and writing to the file. + /// + /// + /// is . + /// + public File(File.IFileAbstraction abstraction, bool supportsAPEv2, bool supportsID3v2) + : base (abstraction) + { + _supportsAPEv2 = supportsAPEv2; + _supportsID3v2 = supportsID3v2; + // Make sure we have an APE tag. + if (_supportsAPEv2) + GetTag(TagTypes.Ape, true); + else + if (_supportsID3v2) + GetTag(TagTypes.Id3v2, true); + } + + #endregion + + + + #region Public Methods + + public bool SupportsAPEv2 + { + get + { + return _supportsAPEv2; + } } public bool SupportsID3v2 @@ -188,133 +188,133 @@ namespace TagLib.UserDefined { { return _supportsID3v2; } - } - - - /// - /// Gets a tag of a specified type from the current instance, - /// optionally creating a new tag if possible. - /// - /// - /// A value indicating the - /// type of tag to read. - /// - /// - /// A value specifying whether or not to - /// try and create the tag if one is not found. - /// - /// - /// A object containing the tag that was - /// found in or added to the current instance. If no - /// matching tag was found and none was created, is returned. - /// - /// - /// If a is added to the - /// current instance, it will be placed at the start of the - /// file. On the other hand, - /// will be added to the end of - /// the file. All other tag types will be ignored. - /// - public override TagLib.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 - - /// - /// Reads format specific information at the start of the - /// file. - /// - /// - /// A value containing the seek position - /// at which the tags end and the media data begins. - /// - /// - /// A value specifying at what level - /// of accuracy to read the media properties, or to ignore the properties. - /// - protected override void ReadStart (long start, - ReadStyle propertiesStyle) - { - } - - /// - /// Reads format specific information at the end of the - /// file. - /// - /// - /// A value containing the seek position - /// at which the media data ends and the tags begin. - /// - /// - /// A value specifying at what level - /// of accuracy to read the media properties, or to ignore the properties. - /// - protected override void ReadEnd (long end, - ReadStyle propertiesStyle) - { - } - - /// - /// Reads the audio properties from the file represented by - /// the current instance. - /// - /// - /// A value containing the seek position - /// at which the tags end and the media data begins. - /// - /// - /// A value containing the seek position - /// at which the media data ends and the tags begin. - /// - /// - /// A value specifying at what level - /// of accuracy to read the media properties, or to ignore the properties. - /// - /// - /// A object describing the - /// media properties of the file represented by the current - /// instance. - /// - protected override Properties ReadProperties (long start, - long end, - ReadStyle propertiesStyle) - { - return new Properties (); - } - - #endregion - } - - public static class AdditionalFileTypes - { + } + + + /// + /// Gets a tag of a specified type from the current instance, + /// optionally creating a new tag if possible. + /// + /// + /// A value indicating the + /// type of tag to read. + /// + /// + /// A value specifying whether or not to + /// try and create the tag if one is not found. + /// + /// + /// A object containing the tag that was + /// found in or added to the current instance. If no + /// matching tag was found and none was created, is returned. + /// + /// + /// If a is added to the + /// current instance, it will be placed at the start of the + /// file. On the other hand, + /// will be added to the end of + /// the file. All other tag types will be ignored. + /// + public override TagLib.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 + + /// + /// Reads format specific information at the start of the + /// file. + /// + /// + /// A value containing the seek position + /// at which the tags end and the media data begins. + /// + /// + /// A value specifying at what level + /// of accuracy to read the media properties, or to ignore the properties. + /// + protected override void ReadStart (long start, + ReadStyle propertiesStyle) + { + } + + /// + /// Reads format specific information at the end of the + /// file. + /// + /// + /// A value containing the seek position + /// at which the media data ends and the tags begin. + /// + /// + /// A value specifying at what level + /// of accuracy to read the media properties, or to ignore the properties. + /// + protected override void ReadEnd (long end, + ReadStyle propertiesStyle) + { + } + + /// + /// Reads the audio properties from the file represented by + /// the current instance. + /// + /// + /// A value containing the seek position + /// at which the tags end and the media data begins. + /// + /// + /// A value containing the seek position + /// at which the media data ends and the tags begin. + /// + /// + /// A value specifying at what level + /// of accuracy to read the media properties, or to ignore the properties. + /// + /// + /// A object describing the + /// media properties of the file represented by the current + /// instance. + /// + protected override Properties ReadProperties (long start, + long end, + ReadStyle propertiesStyle) + { + return new Properties (); + } + + #endregion + } + + public static class AdditionalFileTypes + { private static bool inited = false; private static CUETools.Processor.CUEConfig _config; @@ -329,27 +329,27 @@ namespace TagLib.UserDefined { private static TagLib.File UserDefinedResolver(TagLib.File.IFileAbstraction abstraction, string mimetype, TagLib.ReadStyle style) { - if (mimetype == "taglib/flac" || mimetype == "taglib/wv" || mimetype == "taglib/ape" || mimetype == "taglib/wav" || mimetype == "taglib/ogg") + if (mimetype == "taglib/flac" || mimetype == "taglib/wv" || mimetype == "taglib/ape" || mimetype == "taglib/wav" || mimetype == "taglib/ogg" || mimetype == "taglib/m4a") return null; if (mimetype == "taglib/tta") return new File(abstraction, style, true, false); if (mimetype == "taglib/" + _config.udc1Extension) - return new File(abstraction, style, _config.udc1APEv2, _config.udc1ID3v2); + return new File(abstraction, style, _config.udc1APEv2, _config.udc1ID3v2); return null; } - - static AdditionalFileTypes () - { - Init(); - } - - internal static void Init() - { - if (inited) + + static AdditionalFileTypes () + { + Init(); + } + + internal static void Init() + { + if (inited) return; TagLib.File.AddFileTypeResolver(new TagLib.File.FileTypeResolver(UserDefinedResolver)); - //FileTypes.Register(typeof(TagLib.NonContainer.File)); - inited = true; - } - } -} + //FileTypes.Register(typeof(TagLib.NonContainer.File)); + inited = true; + } + } +} diff --git a/CUETools/CUETools.csproj b/CUETools/CUETools.csproj index 6cdf581..49be309 100644 --- a/CUETools/CUETools.csproj +++ b/CUETools/CUETools.csproj @@ -9,6 +9,7 @@ Properties JDP CUETools + Resources\cue.ico true @@ -203,6 +204,10 @@ + + {1DD41038-D885-46C5-8DDE-E0B82F066584} + CUETools.CDImage + {4911BD82-49EF-4858-8B51-5394F86739A4} CUETools.Processor @@ -222,6 +227,10 @@ + + + +