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 + -
显示快捷键?