#include "WvDecoder.h" int can_seek(void *id) { return 1; } uint32_t get_length(void *id) { return (uint32_t)((CStream*)id)->Length(); } uint32_t get_pos(void *id) { return (uint32_t)((CStream*)id)->Tell(); } // Only used once in the wavpack source, and this should be sufficient int push_back_byte(void *id, int c) { if(((CStream*)id)->Seek(-1,SEEK_CUR)) return EOF; else return c; } int32_t read_bytes(void *id, void *data, int32_t bcount) { return ((CStream*)id)->Read(data,bcount); } int set_pos_abs(void *id, uint32_t pos) { return ((CStream*)id)->Seek(pos,SEEK_SET); } int set_pos_rel(void *id, int32_t delta, int mode) { return ((CStream*)id)->Seek(delta,mode); } CWvDecoder::CWvDecoder() { m_opened=0; } CWvDecoder::~CWvDecoder() { CloseFiles(); } CWvDecoder::CWvDecoder(const wchar_t *filename) { m_opened=0; m_stream.Open(filename,m_usemem); wstring str=filename; str+='c'; CStream* wvc=0; if(m_stream2.Open(str.c_str(),m_usemem)) wvc=&m_stream2; m_reader.can_seek=can_seek; m_reader.get_length=get_length; m_reader.get_pos=get_pos; m_reader.push_back_byte=push_back_byte; m_reader.read_bytes=read_bytes; m_reader.set_pos_abs=set_pos_abs; m_reader.set_pos_rel=set_pos_rel; char error[80]; m_wpc=WavpackOpenFileInputEx(&m_reader,&m_stream,wvc,error,OPEN_WVC,0); if(m_wpc) { m_samples=WavpackGetNumSamples(m_wpc); m_bps=WavpackGetBytesPerSample(m_wpc); m_channels=WavpackGetNumChannels(m_wpc); m_chunksize=WVSIZE/m_channels; int mode=WavpackGetMode(m_wpc); if((mode&MODE_MD5)&&(mode&MODE_LOSSLESS)) { m_calcmd5=1; md5_init(&m_md5); } else m_calcmd5=0; m_count=0; m_opened=1; } } void CWvDecoder::CloseFiles() { if(m_opened) WavpackCloseFile(m_wpc); m_stream.Close(); m_stream2.Close(); } const wchar_t* CWvDecoder::GetSupportedTypes() { return WVTYPES; } CDecoder* CWvDecoder::NewDecoder(const wchar_t* filename) { CWvDecoder* d=new CWvDecoder(filename); if(d->m_opened) return d; else { delete d; return 0; } } __int64 CWvDecoder::GetSampleCount() { return m_samples; } const wchar_t* CWvDecoder::GetLastError() { return m_error; } long CWvDecoder::Read() { long i=WavpackUnpackSamples(m_wpc,m_buffer,m_chunksize); if(i) { if(m_calcmd5) UpdateMD5(i*m_channels); m_count+=i; } else { int errors=WavpackGetNumErrors(m_wpc); if(errors) { swprintf(m_error,MAXERROR,L"%d BAD BLOC%s",errors,errors>1?L"KS":L"K"); i=-1; } else { if(m_count==m_samples) { if(m_calcmd5) { unsigned char a[16]; if(WavpackGetMD5Sum(m_wpc,a)) { unsigned char b[16]; md5_finish(&m_md5,b); if(memcmp(a,b,16)) { wcscpy_s(m_error,MAXERROR,L"MD5 MISMATCH"); return -1; } } } } else { swprintf(m_error,MAXERROR,L"%d %s",m_count> 8); } break; case 3: while(i--) { *dst++ = (unsigned char)(temp = *src++); *dst++ = (unsigned char)(temp >> 8); *dst++ = (unsigned char)(temp >> 16); } break; case 4: while(i--) { *dst++ = (unsigned char)(temp = *src++); *dst++ = (unsigned char)(temp >> 8); *dst++ = (unsigned char)(temp >> 16); *dst++ = (unsigned char)(temp >> 24); } } md5_append(&m_md5,(unsigned char*)m_buffer,count*m_bps); }