#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