stream.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,286 行 · 第 1/3 页
CPP
1,286 行
size_t wxStreamBuffer::Read(wxStreamBuffer *dbuf)
{
wxCHECK_MSG( m_mode != write, 0, _T("can't read from this buffer") );
char buf[BUF_TEMP_SIZE];
size_t nRead,
total = 0;
do
{
nRead = Read(buf, WXSIZEOF(buf));
if ( nRead )
{
nRead = dbuf->Write(buf, nRead);
total += nRead;
}
}
while ( nRead );
return total;
}
size_t wxStreamBuffer::Write(const void *buffer, size_t size)
{
if (m_stream)
{
// lasterror is reset before all new IO calls
m_stream->Reset();
}
size_t ret;
if ( !HasBuffer() && m_fixed )
{
wxOutputStream *outStream = GetOutputStream();
wxCHECK_MSG( outStream, 0, _T("should have a stream in wxStreamBuffer") );
// no buffer, just forward the call to the stream
ret = outStream->OnSysWrite(buffer, size);
}
else // we [may] have a buffer, use it
{
size_t orig_size = size;
while ( size > 0 )
{
size_t left = GetBytesLeft();
// if the buffer is too large to fit in the stream buffer, split
// it in smaller parts
//
// NB: If stream buffer isn't fixed (as for wxMemoryOutputStream),
// we always go to the second case.
//
// FIXME: fine, but if it fails we should (re)try writing it by
// chunks as this will (hopefully) always work (VZ)
if ( size > left && m_fixed )
{
PutToBuffer(buffer, left);
size -= left;
buffer = (char *)buffer + left;
if ( !FlushBuffer() )
{
SetError(wxSTREAM_WRITE_ERROR);
break;
}
m_buffer_pos = m_buffer_start;
}
else // we can do it in one gulp
{
PutToBuffer(buffer, size);
size = 0;
}
}
ret = orig_size - size;
}
if (m_stream)
{
// i am not entirely sure what we do this for
m_stream->m_lastcount = ret;
}
return ret;
}
size_t wxStreamBuffer::Write(wxStreamBuffer *sbuf)
{
wxCHECK_MSG( m_mode != read, 0, _T("can't write to this buffer") );
wxCHECK_MSG( sbuf->m_mode != write, 0, _T("can't read from that buffer") );
char buf[BUF_TEMP_SIZE];
size_t nWrite,
total = 0;
do
{
size_t nRead = sbuf->Read(buf, WXSIZEOF(buf));
if ( nRead )
{
nWrite = Write(buf, nRead);
if ( nWrite < nRead )
{
// put back data we couldn't copy
wxInputStream *in_stream = (wxInputStream *)sbuf->GetStream();
in_stream->Ungetch(buf + nWrite, nRead - nWrite);
}
total += nWrite;
}
else
{
nWrite = 0;
}
}
while ( nWrite == WXSIZEOF(buf) );
return total;
}
wxFileOffset wxStreamBuffer::Seek(wxFileOffset pos, wxSeekMode mode)
{
wxFileOffset ret_off, diff;
wxFileOffset last_access = GetLastAccess();
if ( !m_flushable )
{
switch (mode)
{
case wxFromStart:
diff = pos;
break;
case wxFromCurrent:
diff = pos + GetIntPosition();
break;
case wxFromEnd:
diff = pos + last_access;
break;
default:
wxFAIL_MSG( _T("invalid seek mode") );
return wxInvalidOffset;
}
if (diff < 0 || diff > last_access)
return wxInvalidOffset;
size_t int_diff = (size_t)diff;
wxCHECK_MSG( (wxFileOffset)int_diff == diff, wxInvalidOffset, wxT("huge file not supported") );
SetIntPosition(int_diff);
return diff;
}
switch ( mode )
{
case wxFromStart:
// We'll try to compute an internal position later ...
ret_off = m_stream->OnSysSeek(pos, wxFromStart);
ResetBuffer();
return ret_off;
case wxFromCurrent:
diff = pos + GetIntPosition();
if ( (diff > last_access) || (diff < 0) )
{
// We must take into account the fact that we have read
// something previously.
ret_off = m_stream->OnSysSeek(diff-last_access, wxFromCurrent);
ResetBuffer();
return ret_off;
}
else
{
size_t int_diff = (size_t)diff;
wxCHECK_MSG( (wxFileOffset)int_diff == diff, wxInvalidOffset, wxT("huge file not supported") );
SetIntPosition(int_diff);
return pos;
}
case wxFromEnd:
// Hard to compute: always seek to the requested position.
ret_off = m_stream->OnSysSeek(pos, wxFromEnd);
ResetBuffer();
return ret_off;
}
return wxInvalidOffset;
}
wxFileOffset wxStreamBuffer::Tell() const
{
wxFileOffset pos;
// ask the stream for position if we have a real one
if ( m_stream )
{
pos = m_stream->OnSysTell();
if ( pos == wxInvalidOffset )
return wxInvalidOffset;
}
else // no associated stream
{
pos = 0;
}
pos += GetIntPosition();
if ( m_mode == read && m_flushable )
pos -= GetLastAccess();
return pos;
}
// ----------------------------------------------------------------------------
// wxStreamBase
// ----------------------------------------------------------------------------
wxStreamBase::wxStreamBase()
{
m_lasterror = wxSTREAM_NO_ERROR;
m_lastcount = 0;
}
wxStreamBase::~wxStreamBase()
{
}
size_t wxStreamBase::GetSize() const
{
wxFileOffset length = GetLength();
return length == wxInvalidOffset ? 0 : (size_t)length;
}
wxFileOffset wxStreamBase::OnSysSeek(wxFileOffset WXUNUSED(seek), wxSeekMode WXUNUSED(mode))
{
return wxInvalidOffset;
}
wxFileOffset wxStreamBase::OnSysTell() const
{
return wxInvalidOffset;
}
#if WXWIN_COMPATIBILITY_2_2
wxStreamError wxStreamBase::LastError() const
{
return m_lasterror;
}
size_t wxStreamBase::StreamSize() const
{
return GetSize();
}
#endif // WXWIN_COMPATIBILITY_2_2
// ----------------------------------------------------------------------------
// wxInputStream
// ----------------------------------------------------------------------------
wxInputStream::wxInputStream()
{
m_wback = NULL;
m_wbacksize =
m_wbackcur = 0;
}
wxInputStream::~wxInputStream()
{
free(m_wback);
}
bool wxInputStream::CanRead() const
{
// we don't know if there is anything to read or not and by default we
// prefer to be optimistic and try to read data unless we know for sure
// there is no more of it
return m_lasterror != wxSTREAM_EOF;
}
bool wxInputStream::Eof() const
{
// the only way the base class can know we're at EOF is when we'd already
// tried to read beyond it in which case last error is set accordingly
return GetLastError() == wxSTREAM_EOF;
}
char *wxInputStream::AllocSpaceWBack(size_t needed_size)
{
// get number of bytes left from previous wback buffer
size_t toget = m_wbacksize - m_wbackcur;
// allocate a buffer large enough to hold prev + new data
char *temp_b = (char *)malloc(needed_size + toget);
if (!temp_b)
return NULL;
// copy previous data (and free old buffer) if needed
if (m_wback)
{
memmove(temp_b + needed_size, m_wback + m_wbackcur, toget);
free(m_wback);
}
// done
m_wback = temp_b;
m_wbackcur = 0;
m_wbacksize = needed_size + toget;
return m_wback;
}
size_t wxInputStream::GetWBack(void *buf, size_t size)
{
if (!m_wback)
return 0;
// how many bytes do we have in the buffer?
size_t toget = m_wbacksize - m_wbackcur;
if ( size < toget )
{
// we won't read everything
toget = size;
}
// copy the data from the cache
memcpy(buf, m_wback + m_wbackcur, toget);
m_wbackcur += toget;
if ( m_wbackcur == m_wbacksize )
{
// TODO: should we really free it here all the time? maybe keep it?
free(m_wback);
m_wback = NULL;
m_wbacksize = 0;
m_wbackcur = 0;
}
// return the number of bytes copied
return toget;
}
size_t wxInputStream::Ungetch(const void *buf, size_t bufsize)
{
if ( m_lasterror != wxSTREAM_NO_ERROR && m_lasterror != wxSTREAM_EOF )
{
// can't operate on this stream until the error is cleared
return 0;
}
char *ptrback = AllocSpaceWBack(bufsize);
if (!ptrback)
return 0;
// Eof() shouldn't return true any longer
if ( m_lasterror == wxSTREAM_EOF )
m_lasterror = wxSTREAM_NO_ERROR;
memcpy(ptrback, buf, bufsize);
return bufsize;
}
bool wxInputStream::Ungetch(char c)
{
return Ungetch(&c, sizeof(c)) != 0;
}
char wxInputStream::GetC()
{
char c;
Read(&c, sizeof(c));
return c;
}
wxInputStream& wxInputStream::Read(void *buf, size_t size)
{
char *p = (char *)buf;
m_lastcount = 0;
size_t read = GetWBack(buf, size);
for ( ;; )
{
size -= read;
m_lastcount += read;
p += read;
if ( !size )
{
// we read the requested amount of data
break;
}
if ( p != buf && !CanRead() )
{
// we have already read something and we would block in OnSysRead()
// now: don't do it but return immediately
break;
}
read = OnSysRead(p, size);
if ( !read )
{
// no more data available
break;
}
}
return *this;
}
char wxInputStream::Peek()
{
char c;
Read(&c, sizeof(c));
if (m_lasterror == wxSTREAM_NO_ERROR)
{
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?