WavPack can also be read from RAR archive

This commit is contained in:
chudov
2008-11-10 12:39:07 +00:00
parent 9f4ceab16e
commit d4e68c5261
6 changed files with 254 additions and 47 deletions

View File

@@ -177,6 +177,7 @@ namespace APETagsDotNet
{ {
m_spIO = new FileStream(filename, FileMode.Open, isReadonly?FileAccess.Read:FileAccess.ReadWrite, FileShare.Read); m_spIO = new FileStream(filename, FileMode.Open, isReadonly?FileAccess.Read:FileAccess.ReadWrite, FileShare.Read);
m_spInfo = new FileInfo(filename); m_spInfo = new FileInfo(filename);
_closeIO = true;
m_lastModified = m_spInfo.LastWriteTime; m_lastModified = m_spInfo.LastWriteTime;
m_bAnalyzed = false; m_bAnalyzed = false;
m_aryFields = new APETagField[0]; m_aryFields = new APETagField[0];
@@ -185,9 +186,27 @@ namespace APETagsDotNet
if (analyze) Analyze (); if (analyze) Analyze ();
} }
// create an APE tags object
// bAnalyze determines whether it will analyze immediately or on the first request
// be careful with multiple threads / file pointer movement if you don't analyze immediately
public APETagDotNet(Stream IO, bool analyze)
{
m_spIO = IO;
_closeIO = false;
m_bAnalyzed = false;
m_aryFields = new APETagField[0];
m_nTagBytes = 0;
m_bIgnoreReadOnly = false;
if (analyze) Analyze();
}
public void Close () public void Close ()
{ {
m_spIO.Close (); if (_closeIO)
{
m_spIO.Close();
m_spIO = null;
}
ClearFields (); ClearFields ();
} }
@@ -629,7 +648,7 @@ namespace APETagsDotNet
//int GetFieldID3String(string pFieldName, char * pBuffer, int nBytes); //int GetFieldID3String(string pFieldName, char * pBuffer, int nBytes);
// private data // private data
private FileStream m_spIO; private Stream m_spIO;
private FileInfo m_spInfo; private FileInfo m_spInfo;
private DateTime m_lastModified; private DateTime m_lastModified;
private bool m_bAnalyzed; private bool m_bAnalyzed;
@@ -639,5 +658,6 @@ namespace APETagsDotNet
private int m_nAPETagVersion; private int m_nAPETagVersion;
//private bool m_bHasID3Tag; //private bool m_bHasID3Tag;
private bool m_bIgnoreReadOnly; private bool m_bIgnoreReadOnly;
private bool _closeIO;
}; };
} }

View File

@@ -18,7 +18,7 @@ namespace CUEToolsLib {
case ".flac": case ".flac":
return new FLACReader(path, null); return new FLACReader(path, null);
case ".wv": case ".wv":
return new WavPackReader(path); return new WavPackReader(path, null, null);
case ".ape": case ".ape":
return new APEReader(path); return new APEReader(path);
case ".m4a": case ".m4a":
@@ -37,6 +37,8 @@ namespace CUEToolsLib {
#if !MONO #if !MONO
case ".flac": case ".flac":
return new FLACReader(path, IO); return new FLACReader(path, IO);
case ".wv":
return new WavPackReader(path, IO, null);
case ".m4a": case ".m4a":
return new ALACReader(path, IO); return new ALACReader(path, IO);
#endif #endif
@@ -416,8 +418,8 @@ namespace CUEToolsLib {
class WavPackReader : IAudioSource { class WavPackReader : IAudioSource {
WavPackDotNet.WavPackReader _wavPackReader; WavPackDotNet.WavPackReader _wavPackReader;
public WavPackReader(string path) { public WavPackReader(string path, Stream IO, Stream IO_WVC) {
_wavPackReader = new WavPackDotNet.WavPackReader(path); _wavPackReader = new WavPackDotNet.WavPackReader(path, IO, IO_WVC);
} }
public void Close() { public void Close() {

View File

@@ -88,10 +88,7 @@ namespace FLACDotNet {
_sampleBuffer = nullptr; _sampleBuffer = nullptr;
_path = path; _path = path;
if (IO) _IO = (IO != nullptr) ? IO : gcnew FileStream (path, FileMode::Open, FileAccess::Read, FileShare::Read);
_IO = IO;
else
_IO = gcnew FileStream (path, FileMode::Open, FileAccess::Read, FileShare::Read);
_decoder = FLAC__stream_decoder_new(); _decoder = FLAC__stream_decoder_new();

View File

@@ -13,18 +13,20 @@ namespace UnRarDotNet
{ {
public class RarStream : Stream public class RarStream : Stream
{ {
public RarStream(string archive, string fileName) public RarStream(string path, string fileName)
{ {
_stop = false; _close = false;
_eof = false;
_rewind = false;
_unrar = new Unrar(); _unrar = new Unrar();
_buffer = null; _buffer = null;
_offset = 0; _offset = 0;
_length = 0; _length = 0;
_pos = 0; _pos = 0;
_path = path;
_fileName = fileName;
_unrar.PasswordRequired += new PasswordRequiredHandler(unrar_PasswordRequired); _unrar.PasswordRequired += new PasswordRequiredHandler(unrar_PasswordRequired);
_unrar.DataAvailable += new DataAvailableHandler(unrar_DataAvailable); _unrar.DataAvailable += new DataAvailableHandler(unrar_DataAvailable);
_unrar.Open(archive, Unrar.OpenMode.Extract);
_fileName = fileName;
_workThread = new Thread(Decompress); _workThread = new Thread(Decompress);
_workThread.Priority = ThreadPriority.BelowNormal; _workThread.Priority = ThreadPriority.BelowNormal;
_workThread.IsBackground = true; _workThread.IsBackground = true;
@@ -48,7 +50,7 @@ namespace UnRarDotNet
{ {
lock (this) lock (this)
{ {
while (_size == null && !_stop) while (_size == null && !_close)
Monitor.Wait(this); Monitor.Wait(this);
} }
if (_size == null) if (_size == null)
@@ -65,7 +67,7 @@ namespace UnRarDotNet
{ {
lock (this) lock (this)
{ {
_stop = true; _close = true;
Monitor.Pulse(this); Monitor.Pulse(this);
} }
if (_workThread != null) if (_workThread != null)
@@ -95,7 +97,7 @@ namespace UnRarDotNet
{ {
lock (this) lock (this)
{ {
while (_buffer == null && !_stop) while (_buffer == null && !_eof)
Monitor.Wait(this); Monitor.Wait(this);
if (_buffer == null) if (_buffer == null)
return total; return total;
@@ -139,7 +141,7 @@ namespace UnRarDotNet
{ {
lock (this) lock (this)
{ {
while (_size == null && !_stop) while (_size == null && !_close)
Monitor.Wait(this); Monitor.Wait(this);
if (_size == null) if (_size == null)
throw new NotSupportedException(); throw new NotSupportedException();
@@ -163,8 +165,15 @@ namespace UnRarDotNet
} }
if (_seek_to.Value < _pos) if (_seek_to.Value < _pos)
{ {
_seek_to = null; lock (this)
throw new NotSupportedException("cannot seek backwards"); {
_pos = 0;
_rewind = true;
_buffer = null;
Monitor.Pulse(this);
}
//_seek_to = null;
//throw new NotSupportedException("cannot seek backwards");
} }
return _seek_to.Value; return _seek_to.Value;
} }
@@ -176,12 +185,13 @@ namespace UnRarDotNet
private Unrar _unrar; private Unrar _unrar;
private string _fileName; private string _fileName;
private Thread _workThread; private Thread _workThread;
private bool _stop; private bool _close, _rewind, _eof;
private byte[] _buffer; private byte[] _buffer;
int _offset, _length; int _offset, _length;
long? _size; long? _size;
long? _seek_to; long? _seek_to;
long _pos; long _pos;
string _path;
private void unrar_PasswordRequired(object sender, PasswordRequiredEventArgs e) private void unrar_PasswordRequired(object sender, PasswordRequiredEventArgs e)
{ {
@@ -193,9 +203,15 @@ namespace UnRarDotNet
{ {
lock (this) lock (this)
{ {
while (_buffer != null && !_stop) while (_buffer != null && !_close)
Monitor.Wait(this); Monitor.Wait(this);
if (_stop) if (_close)
{
e.ContinueOperation = false;
Monitor.Pulse(this);
return;
}
if (_rewind)
{ {
e.ContinueOperation = false; e.ContinueOperation = false;
Monitor.Pulse(this); Monitor.Pulse(this);
@@ -213,28 +229,47 @@ namespace UnRarDotNet
{ {
//try //try
{ {
do
{
_unrar.Open(_path, Unrar.OpenMode.Extract);
while (_unrar.ReadHeader()) while (_unrar.ReadHeader())
{ {
if (_unrar.CurrentFile.FileName == _fileName) if (_unrar.CurrentFile.FileName == _fileName)
{ {
lock (this) lock (this)
{
if (_size == null)
{ {
_size = _unrar.CurrentFile.UnpackedSize; _size = _unrar.CurrentFile.UnpackedSize;
Monitor.Pulse(this); Monitor.Pulse(this);
} }
}
_unrar.Test(); _unrar.Test();
break; break;
} }
else else
_unrar.Skip(); _unrar.Skip();
} }
_unrar.Close();
lock (this)
{
_eof = true;
Monitor.Pulse(this);
while (!_rewind && !_close)
Monitor.Wait(this);
if (_close)
break;
_rewind = false;
_eof = false;
}
} while (true);
} }
//catch (StopExtractionException) //catch (StopExtractionException)
//{ //{
//} //}
lock (this) lock (this)
{ {
_stop = true; _close = true;
Monitor.Pulse(this); Monitor.Pulse(this);
} }
} }

View File

@@ -33,6 +33,7 @@ using namespace System;
using namespace System::Runtime::InteropServices; using namespace System::Runtime::InteropServices;
using namespace System::Collections::Specialized; using namespace System::Collections::Specialized;
using namespace System::Security::Cryptography; using namespace System::Security::Cryptography;
using namespace System::IO;
using namespace APETagsDotNet; using namespace APETagsDotNet;
#include <stdio.h> #include <stdio.h>
@@ -43,21 +44,60 @@ using namespace APETagsDotNet;
namespace WavPackDotNet { namespace WavPackDotNet {
int write_block(void *id, void *data, int32_t length); int write_block(void *id, void *data, int32_t length);
[UnmanagedFunctionPointer(CallingConvention::Cdecl)]
public delegate int32_t DecoderReadDelegate(void *id, void *data, int32_t bcount);
[UnmanagedFunctionPointer(CallingConvention::Cdecl)]
public delegate uint32_t DecoderTellDelegate(void *id);
[UnmanagedFunctionPointer(CallingConvention::Cdecl)]
public delegate int DecoderSeekDelegate(void *id, uint32_t pos);
[UnmanagedFunctionPointer(CallingConvention::Cdecl)]
public delegate int DecoderSeekRelativeDelegate(void *id, int32_t delta, int mode);
[UnmanagedFunctionPointer(CallingConvention::Cdecl)]
public delegate int DecoderPushBackDelegate(void *id, int c);
[UnmanagedFunctionPointer(CallingConvention::Cdecl)]
public delegate uint32_t DecoderLengthDelegate(void *id);
[UnmanagedFunctionPointer(CallingConvention::Cdecl)]
public delegate int DecoderCanSeekDelegate(void *id);
public ref class WavPackReader { public ref class WavPackReader {
public: public:
WavPackReader(String^ path) { WavPackReader(String^ path, Stream^ IO, Stream^ IO_WVC) {
IntPtr pathChars;
char errorMessage[256]; char errorMessage[256];
_readDel = gcnew DecoderReadDelegate (this, &WavPackReader::ReadCallback);
_tellDel = gcnew DecoderTellDelegate (this, &WavPackReader::TellCallback);
_seekDel = gcnew DecoderSeekDelegate (this, &WavPackReader::SeekCallback);
_seekRelDel = gcnew DecoderSeekRelativeDelegate (this, &WavPackReader::SeekRelCallback);
_pushBackDel = gcnew DecoderPushBackDelegate (this, &WavPackReader::PushBackCallback);
_lengthDel = gcnew DecoderLengthDelegate (this, &WavPackReader::LengthCallback);
_canSeekDel = gcnew DecoderCanSeekDelegate (this, &WavPackReader::CanSeekCallback);
ioReader = new WavpackStreamReader;
ioReader->read_bytes = (int32_t (*)(void *, void *, int32_t)) Marshal::GetFunctionPointerForDelegate(_readDel).ToPointer();
ioReader->get_pos = (uint32_t (*)(void *)) Marshal::GetFunctionPointerForDelegate(_tellDel).ToPointer();
ioReader->set_pos_abs = (int (*)(void *, uint32_t)) Marshal::GetFunctionPointerForDelegate(_seekDel).ToPointer();
ioReader->set_pos_rel = (int (*)(void *, int32_t, int)) Marshal::GetFunctionPointerForDelegate(_seekRelDel).ToPointer();
ioReader->push_back_byte = (int (*)(void *, int)) Marshal::GetFunctionPointerForDelegate(_pushBackDel).ToPointer();
ioReader->get_length = (uint32_t (*)(void *)) Marshal::GetFunctionPointerForDelegate(_lengthDel).ToPointer();
ioReader->can_seek = (int (*)(void *)) Marshal::GetFunctionPointerForDelegate(_canSeekDel).ToPointer();
ioReader->write_bytes = NULL;
_IO_ungetc = _IO_WVC_ungetc = -1;
_path = path; _path = path;
pathChars = Marshal::StringToHGlobalUni(path); _IO = (IO != nullptr) ? IO : gcnew FileStream (path, FileMode::Open, FileAccess::Read, FileShare::Read);
size_t pathLen = wcslen ((const wchar_t*)pathChars.ToPointer())+1; _IO_WVC = (IO != nullptr) ? IO_WVC : System::IO::File::Exists (path+"c") ? gcnew FileStream (path+"c", FileMode::Open, FileAccess::Read, FileShare::Read) : nullptr;
wchar_t * pPath = new wchar_t[pathLen];
memcpy ((void*) pPath, (const wchar_t*)pathChars.ToPointer(), pathLen*sizeof(wchar_t));
Marshal::FreeHGlobal(pathChars);
_wpc = WavpackOpenFileInput (pPath, errorMessage, OPEN_WVC, 0); //IntPtr pathChars;
//pathChars = Marshal::StringToHGlobalUni(path);
//size_t pathLen = wcslen ((const wchar_t*)pathChars.ToPointer())+1;
//wchar_t * pPath = new wchar_t[pathLen];
//memcpy ((void*) pPath, (const wchar_t*)pathChars.ToPointer(), pathLen*sizeof(wchar_t));
//Marshal::FreeHGlobal(pathChars);
//_wpc = WavpackOpenFileInput (pPath, errorMessage, OPEN_WVC, 0);
_wpc = WavpackOpenFileInputEx (ioReader, "v", _IO_WVC != nullptr ? "c" : NULL, errorMessage, OPEN_WVC, 0);
if (_wpc == NULL) { if (_wpc == NULL) {
throw gcnew Exception("Unable to initialize the decoder."); throw gcnew Exception("Unable to initialize the decoder.");
} }
@@ -71,6 +111,7 @@ namespace WavPackDotNet {
~WavPackReader() ~WavPackReader()
{ {
delete ioReader;
} }
property Int32 BitsPerSample { property Int32 BitsPerSample {
@@ -125,7 +166,7 @@ namespace WavPackDotNet {
NameValueCollection^ get () { NameValueCollection^ get () {
if (!_tags) if (!_tags)
{ {
APETagDotNet^ apeTag = gcnew APETagDotNet (_path, true, true); APETagDotNet^ apeTag = gcnew APETagDotNet (_IO, true);
_tags = apeTag->GetStringTags (true); _tags = apeTag->GetStringTags (true);
apeTag->Close (); apeTag->Close ();
} }
@@ -136,8 +177,19 @@ namespace WavPackDotNet {
} }
} }
void Close() { void Close()
{
_wpc = WavpackCloseFile(_wpc); _wpc = WavpackCloseFile(_wpc);
if (_IO != nullptr)
{
_IO->Close ();
_IO = nullptr;
}
if (_IO_WVC != nullptr)
{
_IO_WVC->Close ();
_IO_WVC = nullptr;
}
} }
void Read(array<Int32, 2>^ sampleBuffer, Int32 sampleCount) { void Read(array<Int32, 2>^ sampleBuffer, Int32 sampleCount) {
@@ -158,6 +210,106 @@ namespace WavPackDotNet {
Int32 _sampleCount, _sampleOffset; Int32 _sampleCount, _sampleOffset;
Int32 _bitsPerSample, _channelCount, _sampleRate; Int32 _bitsPerSample, _channelCount, _sampleRate;
String^ _path; String^ _path;
Stream^ _IO;
Stream^ _IO_WVC;
DecoderReadDelegate^ _readDel;
DecoderTellDelegate^ _tellDel;
DecoderSeekDelegate^ _seekDel;
DecoderSeekRelativeDelegate^ _seekRelDel;
DecoderPushBackDelegate^ _pushBackDel;
DecoderLengthDelegate^ _lengthDel;
DecoderCanSeekDelegate^ _canSeekDel;
array<unsigned char>^ _readBuffer;
int _IO_ungetc, _IO_WVC_ungetc;
WavpackStreamReader* ioReader;
int32_t ReadCallback (void *id, void *data, int32_t bcount)
{
Stream^ IO = (*(char*)id=='c') ? _IO_WVC : _IO;
int IO_ungetc = (*(char*)id=='c') ? _IO_WVC_ungetc : _IO_ungetc;
int unget_len = 0;
if (IO_ungetc != -1)
{
*(unsigned char*)data = (unsigned char) IO_ungetc;
if (IO == _IO)
_IO_ungetc = -1;
else
_IO_WVC_ungetc = -1;
bcount --;
if (!bcount)
return 1;
data = 1 + (unsigned char*)data;
unget_len = 1;
}
if (_readBuffer == nullptr || _readBuffer->Length < bcount)
_readBuffer = gcnew array<unsigned char>(bcount < 0x4000 ? 0x4000 : bcount);
int len = IO->Read (_readBuffer, 0, bcount);
if (len) Marshal::Copy (_readBuffer, 0, (IntPtr)data, len);
return len + unget_len;
}
uint32_t TellCallback(void *id)
{
Stream^ IO = (*(char*)id=='c') ? _IO_WVC : _IO;
return IO->Position;
}
int SeekCallback (void *id, uint32_t pos)
{
Stream^ IO = (*(char*)id=='c') ? _IO_WVC : _IO;
IO->Position = pos;
return 0;
}
int SeekRelCallback (void *id, int32_t delta, int mode)
{
Stream^ IO = (*(char*)id=='c') ? _IO_WVC : _IO;
switch (mode)
{
case SEEK_SET:
IO->Seek (delta, System::IO::SeekOrigin::Begin);
break;
case SEEK_END:
IO->Seek (delta, System::IO::SeekOrigin::End);
break;
case SEEK_CUR:
IO->Seek (delta, System::IO::SeekOrigin::Current);
break;
default:
return -1;
}
return 0;
}
int PushBackCallback (void *id, int c)
{
Stream^ IO = (*(char*)id=='c') ? _IO_WVC : _IO;
if (IO == _IO)
{
if (_IO_ungetc != -1)
throw gcnew Exception("Double PushBackCallback unsupported.");
_IO_ungetc = c;
} else
{
if (_IO_WVC_ungetc != -1)
throw gcnew Exception("Double PushBackCallback unsupported.");
_IO_WVC_ungetc = c;
}
}
uint32_t LengthCallback (void *id)
{
Stream^ IO = (*(char*)id=='c') ? _IO_WVC : _IO;
return IO->Length;
}
int CanSeekCallback(void *id)
{
Stream^ IO = (*(char*)id=='c') ? _IO_WVC : _IO;
return IO->CanSeek;
}
}; };
public ref class WavPackWriter { public ref class WavPackWriter {

View File

@@ -4,6 +4,7 @@
Version="8,00" Version="8,00"
Name="libwavpack" Name="libwavpack"
ProjectGUID="{5CCCB9CF-0384-458F-BA08-72B73866840F}" ProjectGUID="{5CCCB9CF-0384-458F-BA08-72B73866840F}"
RootNamespace="libwavpack"
Keyword="Win32Proj" Keyword="Win32Proj"
> >
<Platforms> <Platforms>
@@ -41,7 +42,7 @@
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
Optimization="0" Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;OPT_MMX" PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;OPT_MMX;NO_USE_FSTREAMS;NO_TAGS"
MinimalRebuild="true" MinimalRebuild="true"
BasicRuntimeChecks="3" BasicRuntimeChecks="3"
RuntimeLibrary="3" RuntimeLibrary="3"
@@ -103,7 +104,7 @@
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
Optimization="0" Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;OPT_SSE2" PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;OPT_SSE2;NO_USE_FSTREAMS;NO_TAGS"
MinimalRebuild="true" MinimalRebuild="true"
BasicRuntimeChecks="3" BasicRuntimeChecks="3"
RuntimeLibrary="3" RuntimeLibrary="3"
@@ -167,7 +168,7 @@
EnableIntrinsicFunctions="true" EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="1" FavorSizeOrSpeed="1"
OmitFramePointers="true" OmitFramePointers="true"
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;OPT_MMX" PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;OPT_MMX;NO_USE_FSTREAMS;NO_TAGS"
StringPooling="true" StringPooling="true"
ExceptionHandling="0" ExceptionHandling="0"
RuntimeLibrary="2" RuntimeLibrary="2"
@@ -239,7 +240,7 @@
EnableIntrinsicFunctions="true" EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="1" FavorSizeOrSpeed="1"
OmitFramePointers="true" OmitFramePointers="true"
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;OPT_SSE2" PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;OPT_SSE2;NO_USE_FSTREAMS;NO_TAGS"
StringPooling="true" StringPooling="true"
ExceptionHandling="0" ExceptionHandling="0"
RuntimeLibrary="2" RuntimeLibrary="2"