add oversampler
This commit is contained in:
847
oversampling/WDL/fileread.h
Normal file
847
oversampling/WDL/fileread.h
Normal file
@@ -0,0 +1,847 @@
|
||||
/*
|
||||
WDL - fileread.h
|
||||
Copyright (C) 2005 and later Cockos Incorporated
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
|
||||
This file provides the WDL_FileRead object, which can be used to read files.
|
||||
On windows systems it supports reading synchronous, asynchronous, memory mapped, and asynchronous unbuffered.
|
||||
On non-windows systems it acts as a wrapper for fopen()/etc.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _WDL_FILEREAD_H_
|
||||
#define _WDL_FILEREAD_H_
|
||||
|
||||
|
||||
|
||||
|
||||
#include "ptrlist.h"
|
||||
|
||||
|
||||
|
||||
#if defined(_WIN32) && !defined(WDL_NO_WIN32_FILEREAD)
|
||||
#ifndef WDL_WIN32_NATIVE_READ
|
||||
#define WDL_WIN32_NATIVE_READ
|
||||
#endif
|
||||
#else
|
||||
#ifdef WDL_WIN32_NATIVE_READ
|
||||
#undef WDL_WIN32_NATIVE_READ
|
||||
#endif
|
||||
|
||||
#if !defined(WDL_NO_POSIX_FILEREAD)
|
||||
#define WDL_POSIX_NATIVE_READ
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/mman.h>
|
||||
#ifdef __APPLE__
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
#endif
|
||||
extern struct stat wdl_stat_chk;
|
||||
// if this fails on linux, use CFLAGS += -D_FILE_OFFSET_BITS=64
|
||||
typedef char wdl_fileread_assert_failed_stat_not_64[sizeof(wdl_stat_chk.st_size)!=8 ? -1 : 1];
|
||||
typedef char wdl_fileread_assert_failed_off_t_64[sizeof(off_t)!=8 ? -1 : 1];
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define WDL_FILEREAD_POSTYPE __int64
|
||||
#else
|
||||
#define WDL_FILEREAD_POSTYPE long long
|
||||
#endif
|
||||
class WDL_FileRead
|
||||
{
|
||||
|
||||
#ifdef WDL_WIN32_NATIVE_READ
|
||||
|
||||
|
||||
class WDL_FileRead__ReadEnt
|
||||
{
|
||||
public:
|
||||
WDL_FileRead__ReadEnt(int sz, char *buf)
|
||||
{
|
||||
m_size=0;
|
||||
memset(&m_ol,0,sizeof(m_ol));
|
||||
m_ol.hEvent=CreateEvent(NULL,TRUE,TRUE,NULL);
|
||||
m_buf=buf;
|
||||
}
|
||||
~WDL_FileRead__ReadEnt()
|
||||
{
|
||||
CloseHandle(m_ol.hEvent);
|
||||
}
|
||||
|
||||
OVERLAPPED m_ol;
|
||||
DWORD m_size;
|
||||
LPVOID m_buf;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && !defined(WDL_NO_SUPPORT_UTF8)
|
||||
BOOL HasUTF8(const char *_str)
|
||||
{
|
||||
const unsigned char *str = (const unsigned char *)_str;
|
||||
if (!str) return FALSE;
|
||||
while (*str)
|
||||
{
|
||||
unsigned char c = *str;
|
||||
if (c >= 0xC2)
|
||||
{
|
||||
if (c <= 0xDF && str[1] >=0x80 && str[1] <= 0xBF) return TRUE;
|
||||
else if (c <= 0xEF && str[1] >=0x80 && str[1] <= 0xBF && str[2] >=0x80 && str[2] <= 0xBF) return TRUE;
|
||||
else if (c <= 0xF4 && str[1] >=0x80 && str[1] <= 0xBF && str[2] >=0x80 && str[2] <= 0xBF) return TRUE;
|
||||
}
|
||||
str++;
|
||||
if (((const char *)str-_str) >= 256) return TRUE; // long filenames get converted to wide
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
// allow_async=1 for unbuffered async, 2 for buffered async, =-1 for unbuffered sync
|
||||
// async aspect is unused on OS X, but the buffered mode affects F_NOCACHE
|
||||
WDL_FileRead(const char *filename, int allow_async=1, int bufsize=8192, int nbufs=4, unsigned int mmap_minsize=0, unsigned int mmap_maxsize=0) : m_bufspace(4096 WDL_HEAPBUF_TRACEPARM("WDL_FileRead"))
|
||||
{
|
||||
m_async_hashaderr=false;
|
||||
m_sync_bufmode_used=m_sync_bufmode_pos=0;
|
||||
m_async_readpos=m_file_position=0;
|
||||
m_fsize=0;
|
||||
m_fsize_maychange=false;
|
||||
m_syncrd_firstbuf=true;
|
||||
m_mmap_view=0;
|
||||
m_mmap_totalbufmode=0;
|
||||
|
||||
#define WDL_UNBUF_ALIGN 8192
|
||||
if (bufsize&(WDL_UNBUF_ALIGN-1)) bufsize=(bufsize&~(WDL_UNBUF_ALIGN-1))+WDL_UNBUF_ALIGN; // ensure bufsize is multiple of 4kb
|
||||
|
||||
#ifdef WDL_WIN32_NATIVE_READ
|
||||
|
||||
m_mmap_fmap=0;
|
||||
|
||||
#ifdef WDL_SUPPORT_WIN9X
|
||||
const bool isNT = GetVersion()<0x80000000;
|
||||
#else
|
||||
const bool isNT = true;
|
||||
#endif
|
||||
m_async = isNT ? allow_async : 0;
|
||||
|
||||
int flags=FILE_ATTRIBUTE_NORMAL;
|
||||
if (m_async>0)
|
||||
{
|
||||
flags|=FILE_FLAG_OVERLAPPED;
|
||||
if (m_async==1) flags|=FILE_FLAG_NO_BUFFERING;
|
||||
}
|
||||
else if (nbufs*bufsize>=WDL_UNBUF_ALIGN && !mmap_maxsize && m_async==-1)
|
||||
flags|=FILE_FLAG_NO_BUFFERING; // non-async mode unbuffered if we do our own buffering
|
||||
|
||||
#ifndef WDL_NO_SUPPORT_UTF8
|
||||
m_fh = INVALID_HANDLE_VALUE;
|
||||
if (isNT && HasUTF8(filename)) // only convert to wide if there are UTF-8 chars
|
||||
{
|
||||
int szreq=MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,filename,-1,NULL,0);
|
||||
if (szreq > 1000)
|
||||
{
|
||||
WDL_TypedBuf<WCHAR> wfilename;
|
||||
wfilename.Resize(szreq+20);
|
||||
|
||||
if (MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,filename,-1,wfilename.Get(),wfilename.GetSize()-10))
|
||||
{
|
||||
correctlongpath(wfilename.Get());
|
||||
m_fh = CreateFileW(wfilename.Get(),GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,flags,NULL);
|
||||
if (m_fh == INVALID_HANDLE_VALUE && GetLastError()==ERROR_SHARING_VIOLATION)
|
||||
{
|
||||
m_fh = CreateFileW(wfilename.Get(),GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,flags,NULL);
|
||||
m_fsize_maychange=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WCHAR wfilename[1024];
|
||||
|
||||
if (MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,filename,-1,wfilename,1024-10))
|
||||
{
|
||||
correctlongpath(wfilename);
|
||||
m_fh = CreateFileW(wfilename,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,flags,NULL);
|
||||
if (m_fh == INVALID_HANDLE_VALUE && GetLastError()==ERROR_SHARING_VIOLATION)
|
||||
{
|
||||
m_fh = CreateFileW(wfilename,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,flags,NULL);
|
||||
m_fsize_maychange=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_fh == INVALID_HANDLE_VALUE)
|
||||
#endif
|
||||
{
|
||||
m_fh = CreateFileA(filename,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,flags,NULL);
|
||||
if (m_fh == INVALID_HANDLE_VALUE && GetLastError()==ERROR_SHARING_VIOLATION)
|
||||
{
|
||||
m_fh = CreateFileA(filename,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,flags,NULL);
|
||||
m_fsize_maychange=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_fh != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD h=0;
|
||||
DWORD l=GetFileSize(m_fh,&h);
|
||||
m_fsize=(((WDL_FILEREAD_POSTYPE)h)<<32)|l;
|
||||
if (m_fsize<0 || (l == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)) m_fsize=0;
|
||||
|
||||
if (!h && l < mmap_maxsize && m_async<=0)
|
||||
{
|
||||
if (l >= mmap_minsize)
|
||||
{
|
||||
m_mmap_fmap=CreateFileMapping(m_fh,NULL,PAGE_READONLY,NULL,0,NULL);
|
||||
if (m_mmap_fmap)
|
||||
{
|
||||
m_mmap_view=MapViewOfFile(m_mmap_fmap,FILE_MAP_READ,0,0,(int)m_fsize);
|
||||
if (!m_mmap_view)
|
||||
{
|
||||
CloseHandle(m_mmap_fmap);
|
||||
m_mmap_fmap=0;
|
||||
}
|
||||
else m_fsize_maychange=false;
|
||||
}
|
||||
}
|
||||
else if (l>0)
|
||||
{
|
||||
m_mmap_totalbufmode = malloc(l);
|
||||
if (m_mmap_totalbufmode)
|
||||
{
|
||||
DWORD sz;
|
||||
ReadFile(m_fh,m_mmap_totalbufmode,l,&sz,NULL);
|
||||
}
|
||||
m_fsize_maychange=false;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_async>0)
|
||||
{
|
||||
m_async_bufsize=bufsize;
|
||||
int x;
|
||||
char *bptr=(char *)m_bufspace.Resize(nbufs*bufsize + (WDL_UNBUF_ALIGN-1));
|
||||
int a=((int)(INT_PTR)bptr)&(WDL_UNBUF_ALIGN-1);
|
||||
if (a) bptr += WDL_UNBUF_ALIGN-a;
|
||||
for (x = 0; x < nbufs; x ++)
|
||||
{
|
||||
WDL_FileRead__ReadEnt *t=new WDL_FileRead__ReadEnt(m_async_bufsize,bptr);
|
||||
m_empties.Add(t);
|
||||
bptr+=m_async_bufsize;
|
||||
}
|
||||
}
|
||||
else if (!m_mmap_view && !m_mmap_totalbufmode && nbufs*bufsize>=WDL_UNBUF_ALIGN)
|
||||
{
|
||||
m_bufspace.Resize(nbufs*bufsize+(WDL_UNBUF_ALIGN-1));
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(WDL_POSIX_NATIVE_READ)
|
||||
m_filedes_locked=false;
|
||||
m_filedes_rdpos=0;
|
||||
m_filedes=open(filename,O_RDONLY
|
||||
// todo: use fcntl() for platforms when O_CLOEXEC is not available (if we ever need to support them)
|
||||
// (currently the only platform that meets this criteria is macOS w/ old SDK, but we don't use execve()
|
||||
// there
|
||||
#ifdef O_CLOEXEC
|
||||
| O_CLOEXEC
|
||||
#endif
|
||||
);
|
||||
if (m_filedes>=0)
|
||||
{
|
||||
if (flock(m_filedes,LOCK_SH|LOCK_NB)>=0) // get shared lock
|
||||
m_filedes_locked=true;
|
||||
else
|
||||
m_fsize_maychange=true; // if couldnt get shared lock, then it may change
|
||||
|
||||
#ifdef __APPLE__
|
||||
if (allow_async==1 || allow_async==-1)
|
||||
{
|
||||
struct statfs sfs;
|
||||
if (fstatfs(m_filedes,&sfs)||(sfs.f_flags&MNT_LOCAL)) // don't use F_NOCACHE on nfs/smb/afp mounts, we need caching there!
|
||||
fcntl(m_filedes,F_NOCACHE,1);
|
||||
}
|
||||
#endif
|
||||
m_fsize=lseek(m_filedes,0,SEEK_END);
|
||||
lseek(m_filedes,0,SEEK_SET);
|
||||
if (m_fsize<0) m_fsize=0;
|
||||
|
||||
if (m_fsize < mmap_maxsize)
|
||||
{
|
||||
if (m_fsize >= mmap_minsize)
|
||||
{
|
||||
m_mmap_view = mmap(NULL,(size_t)m_fsize,PROT_READ,MAP_SHARED,m_filedes,0);
|
||||
if (m_mmap_view == MAP_FAILED) m_mmap_view = 0;
|
||||
else m_fsize_maychange=false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_mmap_totalbufmode = malloc((size_t)m_fsize);
|
||||
if (m_mmap_totalbufmode)
|
||||
m_fsize = pread(m_filedes,m_mmap_totalbufmode,(size_t)m_fsize,0);
|
||||
m_fsize_maychange=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!m_mmap_view && !m_mmap_totalbufmode && m_filedes>=0 && nbufs*bufsize>=WDL_UNBUF_ALIGN)
|
||||
m_bufspace.Resize(nbufs*bufsize+(WDL_UNBUF_ALIGN-1));
|
||||
|
||||
#else
|
||||
m_fp=fopen(filename,"rb");
|
||||
if(m_fp)
|
||||
{
|
||||
fseek(m_fp,0,SEEK_END);
|
||||
m_fsize=ftell(m_fp);
|
||||
fseek(m_fp,0,SEEK_SET);
|
||||
}
|
||||
if (m_fp && nbufs*bufsize>=WDL_UNBUF_ALIGN)
|
||||
m_bufspace.Resize(nbufs*bufsize+(WDL_UNBUF_ALIGN-1));
|
||||
#endif
|
||||
}
|
||||
|
||||
~WDL_FileRead()
|
||||
{
|
||||
free(m_mmap_totalbufmode);
|
||||
m_mmap_totalbufmode=0;
|
||||
|
||||
#ifdef WDL_WIN32_NATIVE_READ
|
||||
int x;
|
||||
for (x = 0; x < m_empties.GetSize();x ++) delete m_empties.Get(x);
|
||||
m_empties.Empty();
|
||||
for (x = 0; x < m_full.GetSize();x ++) delete m_full.Get(x);
|
||||
m_full.Empty();
|
||||
for (x = 0; x < m_pending.GetSize();x ++)
|
||||
{
|
||||
WaitForSingleObject(m_pending.Get(x)->m_ol.hEvent,INFINITE);
|
||||
delete m_pending.Get(x);
|
||||
}
|
||||
m_pending.Empty();
|
||||
|
||||
if (m_mmap_view) UnmapViewOfFile(m_mmap_view);
|
||||
m_mmap_view=0;
|
||||
|
||||
if (m_mmap_fmap) CloseHandle(m_mmap_fmap);
|
||||
m_mmap_fmap=0;
|
||||
|
||||
if (m_fh != INVALID_HANDLE_VALUE) CloseHandle(m_fh);
|
||||
m_fh=INVALID_HANDLE_VALUE;
|
||||
#elif defined(WDL_POSIX_NATIVE_READ)
|
||||
if (m_mmap_view) munmap(m_mmap_view,(size_t)m_fsize);
|
||||
m_mmap_view=0;
|
||||
if (m_filedes>=0)
|
||||
{
|
||||
if (m_filedes_locked) flock(m_filedes,LOCK_UN); // release shared lock
|
||||
close(m_filedes);
|
||||
}
|
||||
m_filedes=-1;
|
||||
#else
|
||||
if (m_fp) fclose(m_fp);
|
||||
m_fp=0;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
bool IsOpen()
|
||||
{
|
||||
#ifdef WDL_WIN32_NATIVE_READ
|
||||
return (m_fh != INVALID_HANDLE_VALUE);
|
||||
#elif defined(WDL_POSIX_NATIVE_READ)
|
||||
return m_filedes >= 0;
|
||||
#else
|
||||
return m_fp != NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CloseHandlesIfFullyInMemory()
|
||||
{
|
||||
if (!m_mmap_totalbufmode) return;
|
||||
#ifdef WDL_WIN32_NATIVE_READ
|
||||
if (m_fh != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(m_fh);
|
||||
m_fh=INVALID_HANDLE_VALUE;
|
||||
}
|
||||
#elif defined(WDL_POSIX_NATIVE_READ)
|
||||
if (m_filedes>=0)
|
||||
{
|
||||
if (m_filedes_locked) flock(m_filedes,LOCK_UN); // release shared lock
|
||||
close(m_filedes);
|
||||
m_filedes=-1;
|
||||
}
|
||||
#else
|
||||
if (m_fp)
|
||||
{
|
||||
fclose(m_fp);
|
||||
m_fp=NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef WDL_WIN32_NATIVE_READ
|
||||
|
||||
int RunReads()
|
||||
{
|
||||
while (m_pending.GetSize())
|
||||
{
|
||||
WDL_FileRead__ReadEnt *ent=m_pending.Get(0);
|
||||
DWORD s=0;
|
||||
|
||||
if (!ent->m_size && !GetOverlappedResult(m_fh,&ent->m_ol,&s,FALSE)) break;
|
||||
m_pending.Delete(0);
|
||||
if (!ent->m_size) ent->m_size=s;
|
||||
m_full.Add(ent);
|
||||
}
|
||||
|
||||
|
||||
if (m_empties.GetSize()>0)
|
||||
{
|
||||
if (m_async_readpos < m_file_position) m_async_readpos = m_file_position;
|
||||
|
||||
if (m_async==1) m_async_readpos &= ~((WDL_FILEREAD_POSTYPE) WDL_UNBUF_ALIGN-1);
|
||||
|
||||
if (m_async_readpos >= m_fsize) return 0;
|
||||
|
||||
const int rdidx=m_empties.GetSize()-1;
|
||||
WDL_FileRead__ReadEnt *t=m_empties.Get(rdidx);
|
||||
|
||||
ResetEvent(t->m_ol.hEvent);
|
||||
|
||||
*(WDL_FILEREAD_POSTYPE *)&t->m_ol.Offset = m_async_readpos;
|
||||
|
||||
m_async_readpos += m_async_bufsize;
|
||||
DWORD dw;
|
||||
if (ReadFile(m_fh,t->m_buf,m_async_bufsize,&dw,&t->m_ol))
|
||||
{
|
||||
if (!dw) return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GetLastError() != ERROR_IO_PENDING) return 1;
|
||||
dw=0;
|
||||
}
|
||||
t->m_size=dw;
|
||||
m_empties.Delete(rdidx);
|
||||
m_pending.Add(t);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AsyncRead(char *buf, int maxlen)
|
||||
{
|
||||
int lenout=0;
|
||||
if (m_file_position+maxlen > m_fsize)
|
||||
{
|
||||
maxlen=(int) (m_fsize-m_file_position);
|
||||
}
|
||||
if (maxlen<1) return 0;
|
||||
|
||||
int errcnt=!!m_async_hashaderr;
|
||||
do
|
||||
{
|
||||
while (m_full.GetSize() > 0)
|
||||
{
|
||||
WDL_FileRead__ReadEnt *ti=m_full.Get(0);
|
||||
WDL_FILEREAD_POSTYPE tiofs=*(WDL_FILEREAD_POSTYPE *)&ti->m_ol.Offset;
|
||||
if (m_file_position >= tiofs && m_file_position < tiofs + ti->m_size)
|
||||
{
|
||||
if (maxlen < 1) break;
|
||||
|
||||
int l=ti->m_size-(int) (m_file_position-tiofs);
|
||||
if (l > maxlen) l=maxlen;
|
||||
|
||||
memcpy(buf,(char *)ti->m_buf+m_file_position - tiofs,l);
|
||||
buf += l;
|
||||
m_file_position += l;
|
||||
maxlen -= l;
|
||||
lenout += l;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_empties.Add(ti);
|
||||
m_full.Delete(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (maxlen > 0 && m_async_readpos != m_file_position)
|
||||
{
|
||||
int x;
|
||||
for (x = 0; x < m_pending.GetSize(); x ++)
|
||||
{
|
||||
WDL_FileRead__ReadEnt *ent=m_pending.Get(x);
|
||||
WDL_FILEREAD_POSTYPE tiofs=*(WDL_FILEREAD_POSTYPE *)&ent->m_ol.Offset;
|
||||
if (m_file_position >= tiofs && m_file_position < tiofs + m_async_bufsize) break;
|
||||
}
|
||||
if (x == m_pending.GetSize())
|
||||
{
|
||||
m_async_readpos=m_file_position;
|
||||
}
|
||||
}
|
||||
|
||||
errcnt+=RunReads();
|
||||
|
||||
if (maxlen > 0 && m_pending.GetSize() && !m_full.GetSize())
|
||||
{
|
||||
WDL_FileRead__ReadEnt *ent=m_pending.Get(0);
|
||||
m_pending.Delete(0);
|
||||
|
||||
if (ent->m_size) m_full.Add(ent);
|
||||
else
|
||||
{
|
||||
// WaitForSingleObject(ent->m_ol.hEvent,INFINITE);
|
||||
|
||||
DWORD s=0;
|
||||
if (GetOverlappedResult(m_fh,&ent->m_ol,&s,TRUE) && s)
|
||||
{
|
||||
ent->m_size=s;
|
||||
m_full.Add(ent);
|
||||
}
|
||||
else // failed read, set the error flag
|
||||
{
|
||||
errcnt++;
|
||||
ent->m_size=0;
|
||||
m_empties.Add(ent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (maxlen > 0 && (m_pending.GetSize()||m_full.GetSize()) && !errcnt);
|
||||
if (!errcnt) RunReads();
|
||||
else m_async_hashaderr=true;
|
||||
|
||||
return lenout;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void *GetMappedView(int offs, int *len)
|
||||
{
|
||||
if (!m_mmap_view && !m_mmap_totalbufmode) return 0;
|
||||
|
||||
int maxl=(int) (m_fsize-(WDL_FILEREAD_POSTYPE)offs);
|
||||
if (*len > maxl) *len=maxl;
|
||||
if (m_mmap_view)
|
||||
return (char *)m_mmap_view + offs;
|
||||
else
|
||||
return (char *)m_mmap_totalbufmode + offs;
|
||||
}
|
||||
|
||||
int Read(void *buf, int len)
|
||||
{
|
||||
if (m_mmap_view||m_mmap_totalbufmode)
|
||||
{
|
||||
int maxl=(int) (m_fsize-m_file_position);
|
||||
if (maxl > len) maxl=len;
|
||||
if (maxl < 0) maxl=0;
|
||||
if (maxl>0)
|
||||
{
|
||||
if (m_mmap_view)
|
||||
memcpy(buf,(char *)m_mmap_view + (int)m_file_position,maxl);
|
||||
else
|
||||
memcpy(buf,(char *)m_mmap_totalbufmode + (int)m_file_position,maxl);
|
||||
|
||||
}
|
||||
m_file_position+=maxl;
|
||||
return maxl;
|
||||
}
|
||||
|
||||
if (m_fsize_maychange) GetSize(); // update m_fsize
|
||||
|
||||
#ifdef WDL_WIN32_NATIVE_READ
|
||||
if (m_fh == INVALID_HANDLE_VALUE||len<1) return 0;
|
||||
|
||||
if (m_async>0)
|
||||
{
|
||||
return AsyncRead((char *)buf,len);
|
||||
}
|
||||
#elif defined(WDL_POSIX_NATIVE_READ)
|
||||
if (m_filedes<0 || len<1) return 0;
|
||||
|
||||
#else
|
||||
if (!m_fp || len<1) return 0;
|
||||
|
||||
#endif
|
||||
|
||||
if (m_bufspace.GetSize()>=WDL_UNBUF_ALIGN*2-1)
|
||||
{
|
||||
int rdout=0;
|
||||
int sz=m_bufspace.GetSize()-(WDL_UNBUF_ALIGN-1);
|
||||
char *srcbuf=(char *)m_bufspace.Get(); // read size
|
||||
if (((int)(INT_PTR)srcbuf)&(WDL_UNBUF_ALIGN-1)) srcbuf += WDL_UNBUF_ALIGN-(((int)(INT_PTR)srcbuf)&(WDL_UNBUF_ALIGN-1));
|
||||
while (len > rdout)
|
||||
{
|
||||
int a=m_sync_bufmode_used-m_sync_bufmode_pos;
|
||||
if (a>(len-rdout)) a=(len-rdout);
|
||||
if (a>0)
|
||||
{
|
||||
memcpy((char*)buf+rdout,srcbuf+m_sync_bufmode_pos,a);
|
||||
rdout+=a;
|
||||
m_sync_bufmode_pos+=a;
|
||||
m_file_position+=a;
|
||||
}
|
||||
|
||||
if (len > rdout)
|
||||
{
|
||||
m_sync_bufmode_used=0;
|
||||
m_sync_bufmode_pos=0;
|
||||
|
||||
int thissz=sz;
|
||||
if (m_syncrd_firstbuf) // this is a scheduling mechanism to avoid having reads on various files always happening at the same time -- not needed in async modes, only in sync with large buffers
|
||||
{
|
||||
m_syncrd_firstbuf=false;
|
||||
const int blocks = thissz/WDL_UNBUF_ALIGN;
|
||||
if (blocks > 1)
|
||||
{
|
||||
static int rrs; // may not be ideal on multithread, but having it incorrect isnt a big deal.
|
||||
if (blocks>7) thissz >>= (rrs++)&3;
|
||||
else thissz>>= (rrs++)&1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WDL_WIN32_NATIVE_READ
|
||||
DWORD o;
|
||||
if (m_async==-1)
|
||||
{
|
||||
if (m_file_position&(WDL_UNBUF_ALIGN-1))
|
||||
{
|
||||
int offs = (int)(m_file_position&(WDL_UNBUF_ALIGN-1));
|
||||
LONG high=(LONG) ((m_file_position-offs)>>32);
|
||||
SetFilePointer(m_fh,(LONG)((m_file_position-offs)&((WDL_FILEREAD_POSTYPE)0xFFFFFFFF)),&high,FILE_BEGIN);
|
||||
m_sync_bufmode_pos=offs;
|
||||
}
|
||||
}
|
||||
if (!ReadFile(m_fh,srcbuf,thissz,&o,NULL) || o<1 || m_sync_bufmode_pos>=(int)o)
|
||||
{
|
||||
break;
|
||||
}
|
||||
#elif defined(WDL_POSIX_NATIVE_READ)
|
||||
int o=(int)pread(m_filedes,srcbuf,thissz,m_filedes_rdpos);
|
||||
if (o>0) m_filedes_rdpos+=o;
|
||||
if (o<1 || m_sync_bufmode_pos>=o) break;
|
||||
|
||||
#else
|
||||
int o=(int)fread(srcbuf,1,thissz,m_fp);
|
||||
if (o<1 || m_sync_bufmode_pos>=o) break;
|
||||
#endif
|
||||
m_sync_bufmode_used=o;
|
||||
}
|
||||
|
||||
}
|
||||
return rdout;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef WDL_WIN32_NATIVE_READ
|
||||
DWORD dw=0;
|
||||
ReadFile(m_fh,buf,len,&dw,NULL);
|
||||
m_file_position+=dw;
|
||||
return dw;
|
||||
#elif defined(WDL_POSIX_NATIVE_READ)
|
||||
|
||||
int ret=(int)pread(m_filedes,buf,len,m_filedes_rdpos);
|
||||
if (ret>0) m_filedes_rdpos+=ret;
|
||||
m_file_position+=ret;
|
||||
return ret;
|
||||
#else
|
||||
int ret=fread(buf,1,len,m_fp);
|
||||
m_file_position+=ret;
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
WDL_FILEREAD_POSTYPE GetSize()
|
||||
{
|
||||
if (m_mmap_totalbufmode) return m_fsize;
|
||||
#ifdef WDL_WIN32_NATIVE_READ
|
||||
if (m_fh == INVALID_HANDLE_VALUE) return 0;
|
||||
#elif defined(WDL_POSIX_NATIVE_READ)
|
||||
if (m_filedes<0) return -1;
|
||||
|
||||
#else
|
||||
if (!m_fp) return -1;
|
||||
#endif
|
||||
|
||||
if (m_fsize_maychange)
|
||||
{
|
||||
#ifdef WDL_WIN32_NATIVE_READ
|
||||
DWORD h=0;
|
||||
DWORD l=GetFileSize(m_fh,&h);
|
||||
m_fsize=(((WDL_FILEREAD_POSTYPE)h)<<32)|l;
|
||||
#elif defined(WDL_POSIX_NATIVE_READ)
|
||||
struct stat st;
|
||||
if (!fstat(m_filedes,&st)) m_fsize = st.st_size;
|
||||
#endif
|
||||
}
|
||||
|
||||
return m_fsize;
|
||||
}
|
||||
|
||||
WDL_FILEREAD_POSTYPE GetPosition()
|
||||
{
|
||||
if (m_mmap_totalbufmode) return m_file_position;
|
||||
#ifdef WDL_WIN32_NATIVE_READ
|
||||
if (m_fh == INVALID_HANDLE_VALUE) return -1;
|
||||
#elif defined(WDL_POSIX_NATIVE_READ)
|
||||
if (m_filedes<0) return -1;
|
||||
#else
|
||||
if (!m_fp) return -1;
|
||||
#endif
|
||||
return m_file_position;
|
||||
}
|
||||
|
||||
bool SetPosition(WDL_FILEREAD_POSTYPE pos) // returns 0 on success
|
||||
{
|
||||
m_async_hashaderr=false;
|
||||
|
||||
if (!m_mmap_totalbufmode)
|
||||
{
|
||||
#ifdef WDL_WIN32_NATIVE_READ
|
||||
if (m_fh == INVALID_HANDLE_VALUE) return true;
|
||||
#elif defined(WDL_POSIX_NATIVE_READ)
|
||||
if (m_filedes<0) return true;
|
||||
#else
|
||||
if (!m_fp) return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (m_fsize_maychange) GetSize();
|
||||
|
||||
if (pos < 0) pos=0;
|
||||
if (pos > m_fsize) pos=m_fsize;
|
||||
WDL_FILEREAD_POSTYPE oldpos=m_file_position;
|
||||
if (m_file_position!=pos) m_file_position=pos;
|
||||
else return false;
|
||||
|
||||
if (m_mmap_view||m_mmap_totalbufmode) return false;
|
||||
|
||||
#ifdef WDL_WIN32_NATIVE_READ
|
||||
if (m_async>0)
|
||||
{
|
||||
WDL_FileRead__ReadEnt *ent;
|
||||
|
||||
if (pos > m_async_readpos || !(ent=m_full.Get(0)) || pos < *(WDL_FILEREAD_POSTYPE *)&ent->m_ol.Offset)
|
||||
{
|
||||
m_async_readpos=pos;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if (m_bufspace.GetSize()>=WDL_UNBUF_ALIGN*2-1)
|
||||
{
|
||||
if (pos >= oldpos-m_sync_bufmode_pos && pos < oldpos-m_sync_bufmode_pos + m_sync_bufmode_used)
|
||||
{
|
||||
int diff=(int) (pos-oldpos);
|
||||
m_sync_bufmode_pos+=diff;
|
||||
|
||||
return 0;
|
||||
}
|
||||
m_sync_bufmode_pos=m_sync_bufmode_used=0;
|
||||
}
|
||||
|
||||
m_syncrd_firstbuf=true;
|
||||
#ifdef WDL_WIN32_NATIVE_READ
|
||||
LONG high=(LONG) (m_file_position>>32);
|
||||
return SetFilePointer(m_fh,(LONG)(m_file_position&((WDL_FILEREAD_POSTYPE)0xFFFFFFFF)),&high,FILE_BEGIN)==0xFFFFFFFF && GetLastError() != NO_ERROR;
|
||||
#elif defined(WDL_POSIX_NATIVE_READ)
|
||||
m_filedes_rdpos = m_file_position;
|
||||
return false;
|
||||
#else
|
||||
return !!fseek(m_fp,m_file_position,SEEK_SET);
|
||||
#endif
|
||||
}
|
||||
|
||||
WDL_HeapBuf m_bufspace;
|
||||
int m_sync_bufmode_used, m_sync_bufmode_pos;
|
||||
|
||||
WDL_FILEREAD_POSTYPE m_file_position,m_async_readpos;
|
||||
WDL_FILEREAD_POSTYPE m_fsize;
|
||||
|
||||
void *m_mmap_view;
|
||||
void *m_mmap_totalbufmode;
|
||||
|
||||
#ifdef WDL_WIN32_NATIVE_READ
|
||||
HANDLE GetHandle() { return m_fh; }
|
||||
HANDLE m_fh;
|
||||
HANDLE m_mmap_fmap;
|
||||
int m_mmap_size;
|
||||
int m_async; // 1=nobuf, 2=buffered async, -1=unbuffered sync
|
||||
|
||||
int m_async_bufsize;
|
||||
WDL_PtrList<WDL_FileRead__ReadEnt> m_empties;
|
||||
WDL_PtrList<WDL_FileRead__ReadEnt> m_pending;
|
||||
WDL_PtrList<WDL_FileRead__ReadEnt> m_full;
|
||||
|
||||
#elif defined(WDL_POSIX_NATIVE_READ)
|
||||
WDL_FILEREAD_POSTYPE m_filedes_rdpos;
|
||||
int m_filedes;
|
||||
bool m_filedes_locked;
|
||||
|
||||
int GetHandle() { return m_filedes; }
|
||||
#else
|
||||
FILE *m_fp;
|
||||
|
||||
int GetHandle() { return fileno(m_fp); }
|
||||
#endif
|
||||
|
||||
bool m_fsize_maychange;
|
||||
bool m_syncrd_firstbuf;
|
||||
bool m_async_hashaderr;
|
||||
|
||||
#ifdef _WIN32
|
||||
static void correctlongpath(WCHAR *buf) // this also exists as wdl_utf8_correctlongpath
|
||||
{
|
||||
const WCHAR *insert;
|
||||
WCHAR *wr;
|
||||
int skip = 0;
|
||||
if (!buf || !buf[0] || wcslen(buf) < 256) return;
|
||||
if (buf[1] == ':') insert=L"\\\\?\\";
|
||||
else if (buf[0] == '\\' && buf[1] == '\\') { insert = L"\\\\?\\UNC\\"; skip=2; }
|
||||
else return;
|
||||
|
||||
wr = buf + wcslen(insert);
|
||||
memmove(wr, buf + skip, (wcslen(buf+skip)+1)*2);
|
||||
memmove(buf,insert,wcslen(insert)*2);
|
||||
while (*wr)
|
||||
{
|
||||
if (*wr == '/') *wr = '\\';
|
||||
wr++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} WDL_FIXALIGN;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user