winamp/Src/Plugins/Input/in_vorbis/localfile.cpp

260 lines
5.2 KiB
C++

#include "main.h"
#include "../nu/AutoChar.h"
extern CfgInt cfg_fullbuf;
int VorbisFile::_f_close(void *) {return 0;}
int VorbisFile::_f_seek(void* rs,__int64 offset,int whence)
{
return ((VorbisFile*)rs)->f_seek(offset,whence);
}
size_t VorbisFile::_f_read(void* ptr,size_t size,size_t nmemb,void * rs)
{
return ((VorbisFile*)rs)->f_read((UINT)(size*nmemb),ptr);
}
long VorbisFile::_f_tell(void* rs)
{
return ((VorbisFile*)rs)->f_tell();
}
ov_callbacks VorbisFile::oc={_f_read,_f_seek,_f_close,_f_tell};
static __int64 Seek64(HANDLE hf, __int64 distance, DWORD MoveMethod)
{
LARGE_INTEGER li;
li.QuadPart = distance;
li.LowPart = SetFilePointer (hf, li.LowPart, &li.HighPart, MoveMethod);
if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
{
li.QuadPart = -1;
}
return li.QuadPart;
}
static __int64 FileSize64(HANDLE file)
{
LARGE_INTEGER position;
position.QuadPart=0;
position.LowPart = GetFileSize(file, (LPDWORD)&position.HighPart);
if (position.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)
return INVALID_FILE_SIZE;
else
return position.QuadPart;
}
class VorbisFile_Local : public VorbisFile
{
private:
HANDLE hFile;
protected:
int f_seek(__int64 offset,int whence)
{
if(whence==SEEK_SET) offset+=baseoffs;
if (Seek64(hFile,offset,whence) != INVALID_SET_FILE_POINTER) return 0;
else return -1;
}
size_t f_read(UINT siz,void * ptr)
{
DWORD bw=0;
ReadFile(hFile,ptr,siz,&bw,0);
return bw;
}
UINT f_tell()
{
return (UINT)(SetFilePointer(hFile,0,0,FILE_CURRENT)-baseoffs);
}
UINT FileSize()
{
return (UINT)(FileSize64(hFile)-baseoffs);
}
public:
virtual int GetType() {return TYPE_LOCAL;}
VorbisFile_Local(HANDLE f,const wchar_t * u,bool is_info) : VorbisFile(u,is_info) {hFile=f;}
~VorbisFile_Local() {CloseHandle(hFile);}
};
class VorbisFile_Mem : public VorbisFile
{
BYTE * block;
UINT size,ptr;
protected:
int f_seek(__int64 offset,int whence)
{
switch(whence)
{
case SEEK_SET:
ptr=(UINT)(offset+baseoffs);
break;
case SEEK_CUR:
ptr+=(UINT)offset;
break;
case SEEK_END:
ptr=size+whence;
break;
}
if (ptr<=size) return 0;
else {ptr=size;return -1;}
}
size_t f_read(UINT siz,void * out)
{
UINT d=size-ptr;
if (d>siz) d=siz;
memcpy(out,block+ptr,d);
ptr+=d;
return d;
}
UINT f_tell()
{
return (UINT)(ptr-baseoffs);
}
UINT FileSize()
{
return (UINT)(size-baseoffs);
}
public:
virtual int GetType() {return TYPE_LOCAL;}
VorbisFile_Mem(HANDLE f,const wchar_t * u,bool is_info) : VorbisFile(u,is_info)
{
size=GetFileSize(f,0);
ptr=0;
block=(BYTE*)malloc(size);
DWORD br = 0;
ReadFile(f,block,size,&br,0);
CloseHandle(f);
}
~VorbisFile_Mem() {free(block);}
};
VorbisFile * VorbisFile::Create(const wchar_t *url, bool is_info)
{
VorbisFile * r;
if (PathIsURLW(url))
{
if (is_info) return 0;
r=Create_HTTP(AutoChar(url),is_info);
}
else
{
__int64 baseoffs=0;
HANDLE f=CreateFileW(url,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,0,OPEN_EXISTING,0,0);
if (f==INVALID_HANDLE_VALUE) return 0;
{
DWORD dw = 0, br = 0;
ReadFile(f,&dw,4,&br,0);
if(br==4 && dw=='SggO')
{
SetFilePointer(f,0,0,FILE_BEGIN);
}
else if(br==4 && dw=='FFIR')
{
//RIFF file
DWORD wavhdr = 0, nb = 0;
SetFilePointer(f,4,0,FILE_CURRENT);
ReadFile(f,&wavhdr,4,&nb,0);
if(nb!=4 || wavhdr!='EVAW')
{
goto abort;
}
//find data starting point
char tmp[1024] = {0};
ReadFile(f,&tmp,1024,&nb,0);
for(int i=0;i<1020;i++)
if(tmp[i]=='d'&&tmp[i+1]=='a'&&tmp[i+2]=='t'&&tmp[i+3]=='a')
{
baseoffs=i+12+8;
Seek64(f, baseoffs, FILE_BEGIN);
}
if(!baseoffs) goto abort;
}
else
{
abort:
CloseHandle(f);
return 0;
}
}
r=cfg_fullbuf ? (VorbisFile*)new VorbisFile_Mem(f,url,is_info) : (VorbisFile*)new VorbisFile_Local(f,url,is_info);
r->setBaseOffset(baseoffs);
}
if (r && !r->init())
{
delete r;
r=0;
}
return r;
}
bool VorbisFile::init()
{
if (ov_open_callbacks(this,&vf,0,0,oc)) return 0;
//TODO bitrate
UINT siz=FileSize();
double len=Length();
if (siz>0 && len>0)
{
UINT divisor = (UINT)(len*125.0);
if (divisor)
avg_kbps=siz/divisor;
}
post_init();
return 1;
}
int is_http(const char* url)
{
return (!_strnicmp(url,"http://",7) || !_strnicmp(url,"https://",8));
}
void VorbisFile::set_meta(const vorbis_comment * vc,int links)
{
if (links == vf.links)
{
int n;
for(n=0;n<links;n++)
{
vorbis_comment_clear(vf.vc+n);
/*
extern void vorbis_comment_init(vorbis_comment *vc);
extern void vorbis_comment_add(vorbis_comment *vc, char *comment);
extern void vorbis_comment_add_tag(vorbis_comment *vc,char *tag, char *contents);
extern char *vorbis_comment_query(vorbis_comment *vc, char *tag, int count);
extern int vorbis_comment_query_count(vorbis_comment *vc, char *tag);
extern void vorbis_comment_clear(vorbis_comment *vc);
*/
}
_ogg_free(vf.vc);
vf.vc = (vorbis_comment*) _ogg_calloc(links,sizeof(vorbis_comment));
for(n=0;n<links;n++)
{
vorbis_comment_init(vf.vc+n);
int c;
for(c=0;c<vc[n].comments;c++)
{
vorbis_comment_add(vf.vc+n,vc[n].user_comments[c]);
}
vf.vc[n].vendor = _strdup(vc[n].vendor);
}
}
}