Added wxBackingFile and wxBackedInputStream.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@42279 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Michael Wetherell
2006-10-23 14:47:07 +00:00
parent c06469f66f
commit f8f6c91a0f
23 changed files with 685 additions and 9 deletions

320
src/common/fileback.cpp Normal file
View File

@@ -0,0 +1,320 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/common/fileback.cpp
// Purpose: Back an input stream with memory or a file
// Author: Mike Wetherell
// RCS-ID: $Id$
// Copyright: (c) 2006 Mike Wetherell
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_BACKINGFILE
#ifndef WX_PRECOMP
#include "wx/stream.h"
#include "wx/utils.h"
#include "wx/log.h"
#endif
#include "wx/fileback.h"
#include "wx/private/filename.h"
// Prefer wxFFile unless wxFile has large file support but wxFFile does not.
//
#if wxUSE_FFILE && (defined WXFFILE_LARGEFILE || !defined WXFILE_LARGEFILE)
typedef wxFFile wxBFFile;
static const bool wxBadSeek = false;
#else
typedef wxFile wxBFFile;
static const wxFileOffset wxBadSeek = wxInvalidOffset;
#endif
/////////////////////////////////////////////////////////////////////////////
// Backing file implementation
class wxBackingFileImpl
{
public:
wxBackingFileImpl(wxInputStream *stream,
size_t bufsize,
const wxString& prefix);
~wxBackingFileImpl();
void Release() { if (--m_refcount == 0) delete this; }
wxBackingFileImpl *AddRef() { m_refcount++; return this; }
wxStreamError ReadAt(wxFileOffset pos, void *buffer, size_t *size);
wxFileOffset GetLength() const;
private:
int m_refcount;
wxInputStream *m_stream;
wxStreamError m_parenterror;
char *m_buf;
size_t m_bufsize;
size_t m_buflen;
wxString m_prefix;
wxString m_filename;
wxBFFile m_file;
wxFileOffset m_filelen;
};
wxBackingFileImpl::wxBackingFileImpl(wxInputStream *stream,
size_t bufsize,
const wxString& prefix)
: m_refcount(1),
m_stream(stream),
m_parenterror(wxSTREAM_NO_ERROR),
m_buf(NULL),
m_bufsize(bufsize),
m_buflen(0),
m_prefix(prefix),
m_filelen(0)
{
wxFileOffset len = m_stream->GetLength();
if (len >= 0 && len + size_t(0) < m_bufsize)
m_bufsize = len;
if (m_bufsize)
m_buf = new char[m_bufsize];
}
wxBackingFileImpl::~wxBackingFileImpl()
{
delete m_stream;
delete [] m_buf;
if (!m_filename.empty())
wxRemoveFile(m_filename);
}
wxStreamError wxBackingFileImpl::ReadAt(wxFileOffset pos,
void *buffer,
size_t *size)
{
size_t reqestedSize = *size;
*size = 0;
// size1 is the number of bytes it will read directly from the backing
// file. size2 is any remaining bytes not yet backed, these are returned
// from the buffer or read from the parent stream.
size_t size1, size2;
if (pos + reqestedSize <= m_filelen + size_t(0)) {
size1 = reqestedSize;
size2 = 0;
} else if (pos < m_filelen) {
size1 = m_filelen - pos;
size2 = reqestedSize - size1;
} else {
size1 = 0;
size2 = reqestedSize;
}
if (pos < 0)
return wxSTREAM_READ_ERROR;
// read the backing file
if (size1) {
if (m_file.Seek(pos) == wxBadSeek)
return wxSTREAM_READ_ERROR;
ssize_t n = m_file.Read(buffer, size1);
if (n > 0) {
*size = n;
pos += n;
}
if (*size < size1)
return wxSTREAM_READ_ERROR;
}
// read from the buffer or parent stream
if (size2)
{
while (*size < reqestedSize)
{
// if pos is further ahead than the parent has been read so far,
// then read forward in the parent stream
while (pos - m_filelen + size_t(0) >= m_buflen)
{
// if the parent is small enough, don't use a backing file
// just the buffer memory
if (!m_stream && m_filelen == 0)
return m_parenterror;
// before refilling the buffer write out the current buffer
// to the backing file if there is anything in it
if (m_buflen)
{
if (!m_file.IsOpened())
if (!wxCreateTempFile(m_prefix, &m_file, &m_filename))
return wxSTREAM_READ_ERROR;
if (m_file.Seek(m_filelen) == wxBadSeek)
return wxSTREAM_READ_ERROR;
size_t count = m_file.Write(m_buf, m_buflen);
m_filelen += count;
if (count < m_buflen) {
delete m_stream;
m_stream = NULL;
if (count > 0) {
delete m_buf;
m_buf = NULL;
m_buflen = 0;
}
m_parenterror = wxSTREAM_READ_ERROR;
return m_parenterror;
}
m_buflen = 0;
if (!m_stream) {
delete m_buf;
m_buf = NULL;
}
}
if (!m_stream)
return m_parenterror;
// refill buffer
m_buflen = m_stream->Read(m_buf, m_bufsize).LastRead();
if (m_buflen < m_bufsize) {
m_parenterror = m_stream->GetLastError();
if (m_parenterror == wxSTREAM_NO_ERROR)
m_parenterror = wxSTREAM_EOF;
delete m_stream;
m_stream = NULL;
}
}
// copy to the user's buffer
size_t start = pos - m_filelen;
size_t len = wxMin(m_buflen - start, reqestedSize - *size);
memcpy((char*)buffer + *size, m_buf + start, len);
*size += len;
pos += len;
}
}
return wxSTREAM_NO_ERROR;
}
wxFileOffset wxBackingFileImpl::GetLength() const
{
if (m_parenterror != wxSTREAM_EOF) {
wxLogNull nolog;
return m_stream->GetLength();
}
return m_filelen + m_buflen;
}
/////////////////////////////////////////////////////////////////////////////
// Backing File, the handle part
wxBackingFile::wxBackingFile(wxInputStream *stream,
size_t bufsize,
const wxString& prefix)
: m_impl(new wxBackingFileImpl(stream, bufsize, prefix))
{
}
wxBackingFile::wxBackingFile(const wxBackingFile& backer)
: m_impl(backer.m_impl ? backer.m_impl->AddRef() : NULL)
{
}
wxBackingFile& wxBackingFile::operator=(const wxBackingFile& backer)
{
if (backer.m_impl != m_impl) {
if (m_impl)
m_impl->Release();
m_impl = backer.m_impl;
if (m_impl)
m_impl->AddRef();
}
return *this;
}
wxBackingFile::~wxBackingFile()
{
if (m_impl)
m_impl->Release();
}
/////////////////////////////////////////////////////////////////////////////
// Input stream
wxBackedInputStream::wxBackedInputStream(const wxBackingFile& backer)
: m_backer(backer),
m_pos(0)
{
}
size_t wxBackedInputStream::OnSysRead(void *buffer, size_t size)
{
if (!IsOk())
return 0;
m_lasterror = m_backer.m_impl->ReadAt(m_pos, buffer, &size);
m_pos += size;
return size;
}
wxFileOffset wxBackedInputStream::GetLength() const
{
return m_backer.m_impl->GetLength();
}
wxFileOffset wxBackedInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode)
{
switch (mode) {
case wxFromCurrent:
{
m_pos += pos;
break;
}
case wxFromEnd:
{
wxFileOffset len = GetLength();
if (len == wxInvalidOffset)
return wxInvalidOffset;
m_pos = len + pos;
break;
}
default:
{
m_pos = pos;
break;
}
}
return m_pos;
}
wxFileOffset wxBackedInputStream::OnSysTell() const
{
return m_pos;
}
#endif // wxUSE_BACKINGFILE