stream.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,286 行 · 第 1/3 页
CPP
1,286 行
/////////////////////////////////////////////////////////////////////////////
// Name: src/common/stream.cpp
// Purpose: wxStream base classes
// Author: Guilhem Lavaux
// Modified by: VZ (23.11.00) to fix realloc()ing new[]ed memory,
// general code review
// Created: 11/07/98
// RCS-ID: $Id: stream.cpp,v 1.96.2.2 2006/03/09 18:15:53 VZ Exp $
// Copyright: (c) Guilhem Lavaux
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "stream.h"
#endif
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/defs.h"
#endif
#if wxUSE_STREAMS
#include <ctype.h>
#include "wx/stream.h"
#include "wx/datstrm.h"
#include "wx/textfile.h"
#include "wx/log.h"
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
// the temporary buffer size used when copying from stream to stream
#define BUF_TEMP_SIZE 4096
// ============================================================================
// implementation
// ============================================================================
// ----------------------------------------------------------------------------
// wxStreamBuffer
// ----------------------------------------------------------------------------
void wxStreamBuffer::SetError(wxStreamError err)
{
if ( m_stream && m_stream->m_lasterror == wxSTREAM_NO_ERROR )
m_stream->m_lasterror = err;
}
void wxStreamBuffer::InitBuffer()
{
m_buffer_start =
m_buffer_end =
m_buffer_pos = NULL;
m_buffer_size = 0;
// if we are going to allocate the buffer, we should free it later as well
m_destroybuf = true;
}
void wxStreamBuffer::Init()
{
InitBuffer();
m_fixed = true;
}
wxStreamBuffer::wxStreamBuffer(BufMode mode)
{
Init();
m_stream = NULL;
m_mode = mode;
m_flushable = false;
}
wxStreamBuffer::wxStreamBuffer(wxStreamBase& stream, BufMode mode)
{
Init();
m_stream = &stream;
m_mode = mode;
m_flushable = true;
}
wxStreamBuffer::wxStreamBuffer(const wxStreamBuffer& buffer)
{
// doing this has big chances to lead to a crash when the source buffer is
// destroyed (otherwise assume the caller knows what he does)
wxASSERT_MSG( !buffer.m_destroybuf,
_T("it's a bad idea to copy this buffer") );
m_buffer_start = buffer.m_buffer_start;
m_buffer_end = buffer.m_buffer_end;
m_buffer_pos = buffer.m_buffer_pos;
m_buffer_size = buffer.m_buffer_size;
m_fixed = buffer.m_fixed;
m_flushable = buffer.m_flushable;
m_stream = buffer.m_stream;
m_mode = buffer.m_mode;
m_destroybuf = false;
}
void wxStreamBuffer::FreeBuffer()
{
if ( m_destroybuf )
{
free(m_buffer_start);
m_buffer_start = NULL;
}
}
wxStreamBuffer::~wxStreamBuffer()
{
FreeBuffer();
}
wxInputStream *wxStreamBuffer::GetInputStream() const
{
return m_mode == write ? NULL : (wxInputStream *)m_stream;
}
wxOutputStream *wxStreamBuffer::GetOutputStream() const
{
return m_mode == read ? NULL : (wxOutputStream *)m_stream;
}
void wxStreamBuffer::SetBufferIO(void *buffer_start,
void *buffer_end,
bool takeOwnership)
{
SetBufferIO(buffer_start, (char *)buffer_end - (char *)buffer_start,
takeOwnership);
}
void wxStreamBuffer::SetBufferIO(void *start,
size_t len,
bool takeOwnership)
{
// start by freeing the old buffer
FreeBuffer();
m_buffer_start = (char *)start;
m_buffer_end = m_buffer_start + len;
m_buffer_size = len;
// if we own it, we free it
m_destroybuf = takeOwnership;
ResetBuffer();
}
void wxStreamBuffer::SetBufferIO(size_t bufsize)
{
if ( bufsize )
{
// this will free the old buffer and allocate the new one
SetBufferIO(malloc(bufsize), bufsize, true /* take ownership */);
}
else // no buffer size => no buffer
{
// still free the old one
FreeBuffer();
InitBuffer();
}
}
void wxStreamBuffer::ResetBuffer()
{
if ( m_stream )
{
m_stream->Reset();
m_stream->m_lastcount = 0;
}
m_buffer_pos = m_mode == read && m_flushable
? m_buffer_end
: m_buffer_start;
}
// fill the buffer with as much data as possible (only for read buffers)
bool wxStreamBuffer::FillBuffer()
{
wxInputStream *inStream = GetInputStream();
// It's legal to have no stream, so we don't complain about it just return false
if ( !inStream )
return false;
size_t count = inStream->OnSysRead(m_buffer_start, m_buffer_size);
if ( !count )
return false;
m_buffer_end = m_buffer_start + count;
m_buffer_pos = m_buffer_start;
return true;
}
// write the buffer contents to the stream (only for write buffers)
bool wxStreamBuffer::FlushBuffer()
{
wxCHECK_MSG( m_flushable, false, _T("can't flush this buffer") );
// FIXME: what is this check for? (VZ)
if ( m_buffer_pos == m_buffer_start )
return false;
wxOutputStream *outStream = GetOutputStream();
wxCHECK_MSG( outStream, false, _T("should have a stream in wxStreamBuffer") );
size_t current = m_buffer_pos - m_buffer_start;
size_t count = outStream->OnSysWrite(m_buffer_start, current);
if ( count != current )
return false;
m_buffer_pos = m_buffer_start;
return true;
}
size_t wxStreamBuffer::GetDataLeft()
{
/* Why is this done? RR. */
if ( m_buffer_pos == m_buffer_end && m_flushable)
FillBuffer();
return GetBytesLeft();
}
// copy up to size bytes from our buffer into the provided one
void wxStreamBuffer::GetFromBuffer(void *buffer, size_t size)
{
// don't get more bytes than left in the buffer
size_t left = GetBytesLeft();
if ( size > left )
size = left;
memcpy(buffer, m_buffer_pos, size);
m_buffer_pos += size;
}
// copy the contents of the provided buffer into this one
void wxStreamBuffer::PutToBuffer(const void *buffer, size_t size)
{
size_t left = GetBytesLeft();
if ( size > left )
{
if ( m_fixed )
{
// we can't realloc the buffer, so just copy what we can
size = left;
}
else // !m_fixed
{
// realloc the buffer to have enough space for the data
size_t delta = m_buffer_pos - m_buffer_start;
char *startOld = m_buffer_start;
m_buffer_size += size;
m_buffer_start = (char *)realloc(m_buffer_start, m_buffer_size);
if ( !m_buffer_start )
{
// don't leak memory if realloc() failed
m_buffer_start = startOld;
m_buffer_size -= size;
// what else can we do?
return;
}
// adjust the pointers invalidated by realloc()
m_buffer_pos = m_buffer_start + delta;
m_buffer_end = m_buffer_start + m_buffer_size;
}
}
memcpy(m_buffer_pos, buffer, size);
m_buffer_pos += size;
}
void wxStreamBuffer::PutChar(char c)
{
wxOutputStream *outStream = GetOutputStream();
wxCHECK_RET( outStream, _T("should have a stream in wxStreamBuffer") );
// if we don't have buffer at all, just forward this call to the stream,
if ( !HasBuffer() )
{
outStream->OnSysWrite(&c, sizeof(c));
}
else
{
// otherwise check we have enough space left
if ( !GetDataLeft() && !FlushBuffer() )
{
// we don't
SetError(wxSTREAM_WRITE_ERROR);
}
else
{
PutToBuffer(&c, sizeof(c));
m_stream->m_lastcount = 1;
}
}
}
char wxStreamBuffer::Peek()
{
wxCHECK_MSG( m_stream && HasBuffer(), 0,
_T("should have the stream and the buffer in wxStreamBuffer") );
if ( !GetDataLeft() )
{
SetError(wxSTREAM_READ_ERROR);
return 0;
}
char c;
GetFromBuffer(&c, sizeof(c));
m_buffer_pos--;
return c;
}
char wxStreamBuffer::GetChar()
{
wxInputStream *inStream = GetInputStream();
wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") );
char c;
if ( !HasBuffer() )
{
inStream->OnSysRead(&c, sizeof(c));
}
else
{
if ( !GetDataLeft() )
{
SetError(wxSTREAM_READ_ERROR);
c = 0;
}
else
{
GetFromBuffer(&c, sizeof(c));
m_stream->m_lastcount = 1;
}
}
return c;
}
size_t wxStreamBuffer::Read(void *buffer, size_t size)
{
// lasterror is reset before all new IO calls
if ( m_stream )
m_stream->Reset();
size_t readBytes;
if ( !HasBuffer() )
{
wxInputStream *inStream = GetInputStream();
wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") );
readBytes = inStream->OnSysRead(buffer, size);
}
else // we have a buffer, use it
{
size_t orig_size = size;
while ( size > 0 )
{
size_t left = GetDataLeft();
// if the requested number of bytes if greater than the buffer
// size, read data in chunks
if ( size > left )
{
GetFromBuffer(buffer, left);
size -= left;
buffer = (char *)buffer + left;
if ( !FillBuffer() )
{
SetError(wxSTREAM_EOF);
break;
}
}
else // otherwise just do it in one gulp
{
GetFromBuffer(buffer, size);
size = 0;
}
}
readBytes = orig_size - size;
}
if ( m_stream )
m_stream->m_lastcount = readBytes;
return readBytes;
}
// this should really be called "Copy()"
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?