add oversampler
This commit is contained in:
707
oversampling/WDL/filewrite.h
Normal file
707
oversampling/WDL/filewrite.h
Normal file
@@ -0,0 +1,707 @@
|
||||
/*
|
||||
WDL - filewrite.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_FileWrite object, which can be used to create/write files.
|
||||
On windows systems it supports writing synchronously, asynchronously, and asynchronously without buffering.
|
||||
On windows systems it supports files larger than 4gb.
|
||||
On non-windows systems it acts as a wrapper for fopen()/etc.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _WDL_FILEWRITE_H_
|
||||
#define _WDL_FILEWRITE_H_
|
||||
|
||||
#ifndef WDL_FILEWRITE_ON_ERROR
|
||||
#define WDL_FILEWRITE_ON_ERROR(is_full)
|
||||
#endif
|
||||
|
||||
#include "ptrlist.h"
|
||||
|
||||
|
||||
|
||||
#if defined(_WIN32) && !defined(WDL_NO_WIN32_FILEWRITE)
|
||||
#ifndef WDL_WIN32_NATIVE_WRITE
|
||||
#define WDL_WIN32_NATIVE_WRITE
|
||||
#endif
|
||||
#else
|
||||
#ifdef WDL_WIN32_NATIVE_WRITE
|
||||
#undef WDL_WIN32_NATIVE_WRITE
|
||||
#endif
|
||||
#if !defined(WDL_NO_POSIX_FILEWRITE)
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/errno.h>
|
||||
#define WDL_POSIX_NATIVE_WRITE
|
||||
extern struct stat wdl_stat_chk;
|
||||
// if this fails on linux, use CFLAGS += -D_FILE_OFFSET_BITS=64
|
||||
typedef char wdl_filewrite_assert_failed_stat_not_64[sizeof(wdl_stat_chk.st_size)!=8 ? -1 : 1];
|
||||
typedef char wdl_filewrite_assert_failed_off_t_64[sizeof(off_t)!=8 ? -1 : 1];
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define WDL_FILEWRITE_POSTYPE __int64
|
||||
#else
|
||||
#define WDL_FILEWRITE_POSTYPE long long
|
||||
#endif
|
||||
|
||||
class WDL_FileWrite
|
||||
{
|
||||
#ifdef WDL_WIN32_NATIVE_WRITE
|
||||
|
||||
class WDL_FileWrite__WriteEnt
|
||||
{
|
||||
public:
|
||||
WDL_FileWrite__WriteEnt(int sz)
|
||||
{
|
||||
m_last_writepos=0;
|
||||
m_bufused=0;
|
||||
m_bufsz=sz;
|
||||
m_bufptr = (char *)__buf.Resize(sz+4095);
|
||||
int a=((int)(INT_PTR)m_bufptr)&4095;
|
||||
if (a) m_bufptr += 4096-a;
|
||||
|
||||
memset(&m_ol,0,sizeof(m_ol));
|
||||
m_ol.hEvent=CreateEvent(NULL,TRUE,TRUE,NULL);
|
||||
}
|
||||
~WDL_FileWrite__WriteEnt()
|
||||
{
|
||||
CloseHandle(m_ol.hEvent);
|
||||
}
|
||||
|
||||
WDL_FILEWRITE_POSTYPE m_last_writepos;
|
||||
|
||||
int m_bufused,m_bufsz;
|
||||
OVERLAPPED m_ol;
|
||||
char *m_bufptr;
|
||||
WDL_TypedBuf<char> __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:
|
||||
// async==2 is write-through
|
||||
// async==3 is non-buffered (win32-only)
|
||||
WDL_FileWrite(const char *filename, int allow_async=1, int bufsize=8192, int minbufs=16, int maxbufs=16, bool wantAppendTo=false, bool noFileLocking=false)
|
||||
{
|
||||
m_file_position=0;
|
||||
m_file_max_position=0;
|
||||
if(!filename)
|
||||
{
|
||||
#ifdef WDL_WIN32_NATIVE_WRITE
|
||||
m_fh = INVALID_HANDLE_VALUE;
|
||||
m_async = 0;
|
||||
#elif defined(WDL_POSIX_NATIVE_WRITE)
|
||||
m_filedes_locked=false;
|
||||
m_filedes=-1;
|
||||
m_bufspace_used=0;
|
||||
#else
|
||||
m_fp = NULL;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef WDL_WIN32_NATIVE_WRITE
|
||||
#ifdef WDL_SUPPORT_WIN9X
|
||||
const bool isNT = (GetVersion()<0x80000000);
|
||||
#else
|
||||
const bool isNT = true;
|
||||
#endif
|
||||
m_async = allow_async && isNT ? 1 : 0;
|
||||
if (m_async && allow_async == 3 && !wantAppendTo)
|
||||
{
|
||||
m_async = 3;
|
||||
bufsize = (bufsize+4095)&~4095;
|
||||
if (bufsize<4096) bufsize=4096;
|
||||
}
|
||||
|
||||
int rwflag = GENERIC_WRITE;
|
||||
int createFlag= wantAppendTo?OPEN_ALWAYS:CREATE_ALWAYS;
|
||||
int shareFlag = noFileLocking ? (FILE_SHARE_READ|FILE_SHARE_WRITE) : FILE_SHARE_READ;
|
||||
int flag = FILE_ATTRIBUTE_NORMAL;
|
||||
|
||||
if (m_async)
|
||||
{
|
||||
rwflag |= GENERIC_READ;
|
||||
if (m_async == 3)
|
||||
flag |= FILE_FLAG_OVERLAPPED|FILE_FLAG_NO_BUFFERING|FILE_FLAG_WRITE_THROUGH;
|
||||
else
|
||||
flag |= FILE_FLAG_OVERLAPPED|(allow_async>1 ? FILE_FLAG_WRITE_THROUGH: 0);
|
||||
}
|
||||
|
||||
{
|
||||
#ifndef WDL_NO_SUPPORT_UTF8
|
||||
m_fh=INVALID_HANDLE_VALUE;
|
||||
if (isNT && HasUTF8(filename))
|
||||
{
|
||||
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(),rwflag,shareFlag,NULL,createFlag,flag,NULL);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WCHAR wfilename[1024];
|
||||
if (MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,filename,-1,wfilename,1024-10))
|
||||
{
|
||||
correctlongpath(wfilename);
|
||||
m_fh = CreateFileW(wfilename,rwflag,shareFlag,NULL,createFlag,flag,NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_fh == INVALID_HANDLE_VALUE)
|
||||
#endif
|
||||
m_fh = CreateFileA(filename,rwflag,shareFlag,NULL,createFlag,flag,NULL);
|
||||
}
|
||||
|
||||
if (m_async && m_fh != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
m_async_bufsize=bufsize;
|
||||
m_async_maxbufs=maxbufs;
|
||||
m_async_minbufs=minbufs;
|
||||
int x;
|
||||
for (x = 0; x < m_async_minbufs; x ++)
|
||||
{
|
||||
WDL_FileWrite__WriteEnt *t=new WDL_FileWrite__WriteEnt(m_async_bufsize);
|
||||
m_empties.Add(t);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_fh != INVALID_HANDLE_VALUE && wantAppendTo)
|
||||
SetPosition(GetSize());
|
||||
|
||||
#elif defined(WDL_POSIX_NATIVE_WRITE)
|
||||
m_bufspace_used=0;
|
||||
m_filedes_locked=false;
|
||||
m_filedes=open(filename,O_WRONLY|O_CREAT
|
||||
// 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
|
||||
,0644);
|
||||
if (m_filedes>=0)
|
||||
{
|
||||
|
||||
if (!noFileLocking)
|
||||
{
|
||||
m_filedes_locked = !flock(m_filedes,LOCK_EX|LOCK_NB);
|
||||
if (!m_filedes_locked)
|
||||
{
|
||||
// this check might not be necessary, it might be sufficient to just fail and close if no exclusive lock possible
|
||||
if (errno == EWOULDBLOCK)
|
||||
{
|
||||
// FAILED exclusive locking because someone else has a lock
|
||||
close(m_filedes);
|
||||
m_filedes=-1;
|
||||
}
|
||||
else // failed for some other reason, try to keep a shared lock at least
|
||||
{
|
||||
m_filedes_locked = !flock(m_filedes,LOCK_SH|LOCK_NB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_filedes>=0)
|
||||
{
|
||||
if (!wantAppendTo)
|
||||
{
|
||||
if (ftruncate(m_filedes,0) < 0)
|
||||
{
|
||||
WDL_ASSERT( false /* ftruncate() failed in WDL_FileWrite */ );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
struct stat st;
|
||||
if (!fstat(m_filedes,&st)) SetPosition(st.st_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
if (m_filedes >= 0 && allow_async>1) fcntl(m_filedes,F_NOCACHE,1);
|
||||
#endif
|
||||
}
|
||||
if (minbufs * bufsize >= 16384) m_bufspace.Resize((minbufs*bufsize+4095)&~4095);
|
||||
#else
|
||||
m_fp=fopen(filename,wantAppendTo ? "a+b" : "wb");
|
||||
if (wantAppendTo && m_fp)
|
||||
fseek(m_fp,0,SEEK_END);
|
||||
#endif
|
||||
}
|
||||
|
||||
~WDL_FileWrite()
|
||||
{
|
||||
#ifdef WDL_WIN32_NATIVE_WRITE
|
||||
// todo, async close stuff?
|
||||
if (m_fh != INVALID_HANDLE_VALUE && m_async)
|
||||
{
|
||||
SyncOutput(true);
|
||||
}
|
||||
|
||||
m_empties.Empty(true);
|
||||
m_pending.Empty(true);
|
||||
|
||||
if (m_fh != INVALID_HANDLE_VALUE) CloseHandle(m_fh);
|
||||
m_fh=INVALID_HANDLE_VALUE;
|
||||
#elif defined(WDL_POSIX_NATIVE_WRITE)
|
||||
if (m_filedes >= 0)
|
||||
{
|
||||
if (m_bufspace.GetSize() > 0 && m_bufspace_used>0)
|
||||
{
|
||||
int v=(int)pwrite(m_filedes,m_bufspace.Get(),m_bufspace_used,m_file_position);
|
||||
if (v>0) m_file_position+=v;
|
||||
if (m_file_position > m_file_max_position) m_file_max_position=m_file_position;
|
||||
m_bufspace_used=0;
|
||||
}
|
||||
if (m_filedes_locked) flock(m_filedes,LOCK_UN);
|
||||
close(m_filedes);
|
||||
}
|
||||
m_filedes=-1;
|
||||
|
||||
#else
|
||||
if (m_fp) fclose(m_fp);
|
||||
m_fp=0;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
bool IsOpen()
|
||||
{
|
||||
#ifdef WDL_WIN32_NATIVE_WRITE
|
||||
return (m_fh != INVALID_HANDLE_VALUE);
|
||||
#elif defined(WDL_POSIX_NATIVE_WRITE)
|
||||
return m_filedes >= 0;
|
||||
#else
|
||||
return m_fp != NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int Write(const void *buf, int len)
|
||||
{
|
||||
#ifdef WDL_WIN32_NATIVE_WRITE
|
||||
if (m_fh == INVALID_HANDLE_VALUE) return 0;
|
||||
|
||||
if (m_async)
|
||||
{
|
||||
int rdpos = 0;
|
||||
while (len > 0)
|
||||
{
|
||||
if (!m_empties.GetSize())
|
||||
{
|
||||
WDL_FileWrite__WriteEnt *ent=m_pending.Get(0);
|
||||
DWORD s=0;
|
||||
if (ent)
|
||||
{
|
||||
bool wasabort=false;
|
||||
DWORD err;
|
||||
if (GetOverlappedResult(m_fh,&ent->m_ol,&s,FALSE)||
|
||||
(wasabort=((err=GetLastError())==ERROR_OPERATION_ABORTED)))
|
||||
{
|
||||
m_pending.Delete(0);
|
||||
|
||||
if (wasabort)
|
||||
{
|
||||
if (!RunAsyncWrite(ent,false)) m_empties.Add(ent);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_empties.Add(ent);
|
||||
ent->m_bufused=0;
|
||||
}
|
||||
}
|
||||
else if (err != ERROR_IO_PENDING && err != ERROR_IO_INCOMPLETE)
|
||||
{
|
||||
WDL_FILEWRITE_ON_ERROR(err == ERROR_DISK_FULL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WDL_FileWrite__WriteEnt *ent=m_empties.Get(0);
|
||||
if (!ent)
|
||||
{
|
||||
if (m_pending.GetSize()>=m_async_maxbufs)
|
||||
{
|
||||
SyncOutput(false);
|
||||
}
|
||||
|
||||
if (!(ent=m_empties.Get(0)))
|
||||
m_empties.Add(ent = new WDL_FileWrite__WriteEnt(m_async_bufsize)); // new buffer
|
||||
|
||||
|
||||
}
|
||||
|
||||
int ml=ent->m_bufsz-ent->m_bufused;
|
||||
if (ml>len) ml=len;
|
||||
memcpy(ent->m_bufptr+ent->m_bufused,(const char *)buf + rdpos,ml);
|
||||
|
||||
ent->m_bufused+=ml;
|
||||
len-=ml;
|
||||
rdpos+=ml;
|
||||
|
||||
if (ent->m_bufused >= ent->m_bufsz)
|
||||
{
|
||||
if (RunAsyncWrite(ent,true)) m_empties.Delete(0); // if queued remove from list
|
||||
}
|
||||
}
|
||||
return rdpos;
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD dw=0;
|
||||
if (!WriteFile(m_fh,buf,len,&dw,NULL))
|
||||
{
|
||||
WDL_FILEWRITE_ON_ERROR(GetLastError() == ERROR_DISK_FULL)
|
||||
}
|
||||
m_file_position+=dw;
|
||||
if (m_file_position>m_file_max_position) m_file_max_position=m_file_position;
|
||||
return dw;
|
||||
}
|
||||
#elif defined(WDL_POSIX_NATIVE_WRITE)
|
||||
if (m_bufspace.GetSize()>0)
|
||||
{
|
||||
char *rdptr = (char *)buf;
|
||||
int rdlen = len;
|
||||
while (rdlen>0)
|
||||
{
|
||||
int amt = m_bufspace.GetSize() - m_bufspace_used;
|
||||
if (amt>0)
|
||||
{
|
||||
if (amt>rdlen) amt=rdlen;
|
||||
memcpy((char *)m_bufspace.Get()+m_bufspace_used,rdptr,amt);
|
||||
m_bufspace_used += amt;
|
||||
rdptr+=amt;
|
||||
rdlen -= amt;
|
||||
|
||||
if (m_file_position+m_bufspace_used > m_file_max_position) m_file_max_position=m_file_position + m_bufspace_used;
|
||||
}
|
||||
if (m_bufspace_used >= m_bufspace.GetSize())
|
||||
{
|
||||
int v=(int)pwrite(m_filedes,m_bufspace.Get(),m_bufspace_used,m_file_position);
|
||||
if (v != m_bufspace_used) { WDL_FILEWRITE_ON_ERROR(v>=0 || errno == EDQUOT || errno == ENOSPC) }
|
||||
if (v>0) m_file_position+=v;
|
||||
m_bufspace_used=0;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
else
|
||||
{
|
||||
int v=(int)pwrite(m_filedes,buf,len,m_file_position);
|
||||
if (v != len) { WDL_FILEWRITE_ON_ERROR(v>=0 || errno == EDQUOT || errno == ENOSPC) }
|
||||
if (v>0) m_file_position+=v;
|
||||
if (m_file_position > m_file_max_position) m_file_max_position=m_file_position;
|
||||
return v;
|
||||
}
|
||||
#else
|
||||
int written = (int)fwrite(buf,1,len,m_fp);
|
||||
if (written != len) { WDL_FILEWRITE_ON_ERROR(false) }
|
||||
return written;
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
WDL_FILEWRITE_POSTYPE GetSize()
|
||||
{
|
||||
#ifdef WDL_WIN32_NATIVE_WRITE
|
||||
if (m_fh == INVALID_HANDLE_VALUE) return 0;
|
||||
DWORD h=0;
|
||||
DWORD l=GetFileSize(m_fh,&h);
|
||||
WDL_FILEWRITE_POSTYPE tmp=(((WDL_FILEWRITE_POSTYPE)h)<<32)|l;
|
||||
WDL_FILEWRITE_POSTYPE tmp2=GetPosition();
|
||||
if (tmp<m_file_max_position) return m_file_max_position;
|
||||
if (tmp<tmp2) return tmp2;
|
||||
|
||||
return tmp;
|
||||
#elif defined(WDL_POSIX_NATIVE_WRITE)
|
||||
if (m_filedes < 0) return -1;
|
||||
return m_file_max_position;
|
||||
#else
|
||||
if (!m_fp) return -1;
|
||||
int opos=ftell(m_fp);
|
||||
fseek(m_fp,0,SEEK_END);
|
||||
int a=ftell(m_fp);
|
||||
fseek(m_fp,opos,SEEK_SET);
|
||||
return a;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
WDL_FILEWRITE_POSTYPE GetPosition()
|
||||
{
|
||||
#ifdef WDL_WIN32_NATIVE_WRITE
|
||||
if (m_fh == INVALID_HANDLE_VALUE) return -1;
|
||||
|
||||
WDL_FILEWRITE_POSTYPE pos=m_file_position;
|
||||
if (m_async)
|
||||
{
|
||||
WDL_FileWrite__WriteEnt *ent=m_empties.Get(0);
|
||||
if (ent) pos+=ent->m_bufused;
|
||||
}
|
||||
return pos;
|
||||
#elif defined(WDL_POSIX_NATIVE_WRITE)
|
||||
if (m_filedes < 0) return -1;
|
||||
return m_file_position + m_bufspace_used;
|
||||
#else
|
||||
if (!m_fp) return -1;
|
||||
return ftell(m_fp);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef WDL_WIN32_NATIVE_WRITE
|
||||
|
||||
bool RunAsyncWrite(WDL_FileWrite__WriteEnt *ent, bool updatePosition) // returns true if ent is added to pending
|
||||
{
|
||||
if (ent && ent->m_bufused>0)
|
||||
{
|
||||
if (updatePosition)
|
||||
{
|
||||
ent->m_last_writepos = m_file_position;
|
||||
m_file_position += ent->m_bufused;
|
||||
if (m_file_position>m_file_max_position) m_file_max_position=m_file_position;
|
||||
}
|
||||
|
||||
if (m_async == 3 && (ent->m_bufused&4095))
|
||||
{
|
||||
int offs=(ent->m_bufused&4095);
|
||||
char tmp[4096];
|
||||
memset(tmp,0,4096);
|
||||
|
||||
*(WDL_FILEWRITE_POSTYPE *)&ent->m_ol.Offset = ent->m_last_writepos + ent->m_bufused - offs;
|
||||
ResetEvent(ent->m_ol.hEvent);
|
||||
|
||||
DWORD dw=0;
|
||||
if (!ReadFile(m_fh,tmp,4096,&dw,&ent->m_ol))
|
||||
{
|
||||
if (GetLastError() == ERROR_IO_PENDING)
|
||||
WaitForSingleObject(ent->m_ol.hEvent,INFINITE);
|
||||
}
|
||||
memcpy(ent->m_bufptr+ent->m_bufused,tmp+offs,4096-offs);
|
||||
|
||||
ent->m_bufused += 4096-offs;
|
||||
}
|
||||
|
||||
DWORD d=0;
|
||||
|
||||
*(WDL_FILEWRITE_POSTYPE *)&ent->m_ol.Offset = ent->m_last_writepos;
|
||||
|
||||
ResetEvent(ent->m_ol.hEvent);
|
||||
|
||||
if (!WriteFile(m_fh,ent->m_bufptr,ent->m_bufused,&d,&ent->m_ol))
|
||||
{
|
||||
if (GetLastError()==ERROR_IO_PENDING)
|
||||
{
|
||||
m_pending.Add(ent);
|
||||
return true;
|
||||
}
|
||||
else { WDL_FILEWRITE_ON_ERROR(GetLastError()==ERROR_DISK_FULL) }
|
||||
}
|
||||
ent->m_bufused=0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SyncOutput(bool syncall)
|
||||
{
|
||||
if (syncall)
|
||||
{
|
||||
if (RunAsyncWrite(m_empties.Get(0),true)) m_empties.Delete(0);
|
||||
}
|
||||
for (;;)
|
||||
{
|
||||
WDL_FileWrite__WriteEnt *ent=m_pending.Get(0);
|
||||
if (!ent) break;
|
||||
DWORD s=0;
|
||||
m_pending.Delete(0);
|
||||
BOOL ok = GetOverlappedResult(m_fh,&ent->m_ol,&s,TRUE);
|
||||
int errcode;
|
||||
if (!ok && (errcode=GetLastError())==ERROR_OPERATION_ABORTED)
|
||||
{
|
||||
// rewrite this one
|
||||
if (!RunAsyncWrite(ent,false)) m_empties.Add(ent);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ok) { WDL_FILEWRITE_ON_ERROR(errcode==ERROR_DISK_FULL) }
|
||||
m_empties.Add(ent);
|
||||
ent->m_bufused=0;
|
||||
if (!syncall) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
bool SetPosition(WDL_FILEWRITE_POSTYPE pos) // returns 0 on success
|
||||
{
|
||||
#ifdef WDL_WIN32_NATIVE_WRITE
|
||||
if (m_fh == INVALID_HANDLE_VALUE) return true;
|
||||
if (m_async)
|
||||
{
|
||||
SyncOutput(true);
|
||||
m_file_position=pos;
|
||||
if (m_file_position>m_file_max_position) m_file_max_position=m_file_position;
|
||||
|
||||
if (m_async==3 && (m_file_position&4095))
|
||||
{
|
||||
WDL_FileWrite__WriteEnt *ent=m_empties.Get(0);
|
||||
if (ent)
|
||||
{
|
||||
int psz=(int) (m_file_position&4095);
|
||||
|
||||
m_file_position -= psz;
|
||||
*(WDL_FILEWRITE_POSTYPE *)&ent->m_ol.Offset = m_file_position;
|
||||
ResetEvent(ent->m_ol.hEvent);
|
||||
|
||||
DWORD dwo=0;
|
||||
if (!ReadFile(m_fh,ent->m_bufptr,4096,&dwo,&ent->m_ol))
|
||||
{
|
||||
if (GetLastError() == ERROR_IO_PENDING)
|
||||
WaitForSingleObject(ent->m_ol.hEvent,INFINITE);
|
||||
}
|
||||
ent->m_bufused=(int)psz;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
m_file_position=pos;
|
||||
if (m_file_position>m_file_max_position) m_file_max_position=m_file_position;
|
||||
|
||||
LONG high=(LONG) (m_file_position>>32);
|
||||
return SetFilePointer(m_fh,(LONG)(m_file_position&((WDL_FILEWRITE_POSTYPE)0xFFFFFFFF)),&high,FILE_BEGIN)==0xFFFFFFFF && GetLastError() != NO_ERROR;
|
||||
#elif defined(WDL_POSIX_NATIVE_WRITE)
|
||||
|
||||
if (m_filedes < 0) return true;
|
||||
if (m_bufspace.GetSize() > 0 && m_bufspace_used>0)
|
||||
{
|
||||
int v=(int)pwrite(m_filedes,m_bufspace.Get(),m_bufspace_used,m_file_position);
|
||||
if (v>0) m_file_position+=v;
|
||||
if (m_file_position > m_file_max_position) m_file_max_position=m_file_position;
|
||||
m_bufspace_used=0;
|
||||
}
|
||||
|
||||
m_file_position = pos; // seek!
|
||||
if (m_file_position>m_file_max_position) m_file_max_position=m_file_position;
|
||||
return false;
|
||||
#else
|
||||
if (!m_fp) return true;
|
||||
return !!fseek(m_fp,pos,SEEK_SET);
|
||||
#endif
|
||||
}
|
||||
|
||||
WDL_FILEWRITE_POSTYPE m_file_position, m_file_max_position;
|
||||
|
||||
#ifdef WDL_WIN32_NATIVE_WRITE
|
||||
HANDLE GetHandle() { return m_fh; }
|
||||
HANDLE m_fh;
|
||||
int m_async; // 3 = unbuffered
|
||||
|
||||
int m_async_bufsize, m_async_minbufs, m_async_maxbufs;
|
||||
|
||||
WDL_PtrList<WDL_FileWrite__WriteEnt> m_empties;
|
||||
WDL_PtrList<WDL_FileWrite__WriteEnt> m_pending;
|
||||
|
||||
#elif defined(WDL_POSIX_NATIVE_WRITE)
|
||||
int GetHandle() { return m_filedes; }
|
||||
|
||||
WDL_HeapBuf m_bufspace;
|
||||
int m_bufspace_used;
|
||||
int m_filedes;
|
||||
|
||||
bool m_filedes_locked;
|
||||
|
||||
#else
|
||||
int GetHandle() { return fileno(m_fp); }
|
||||
|
||||
FILE *m_fp;
|
||||
#endif
|
||||
|
||||
#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