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