wxArchiveFSHandler for compatibilty. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@42651 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
339 lines
8.5 KiB
C++
339 lines
8.5 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// 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_FILESYSTEM
|
|
|
|
#include "wx/private/fileback.h"
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/utils.h"
|
|
#include "wx/log.h"
|
|
#endif
|
|
|
|
#include "wx/private/filename.h"
|
|
|
|
// Prefer wxFFile unless wxFile has large file support but wxFFile does not.
|
|
//
|
|
#if wxUSE_FFILE && (defined wxHAS_LARGE_FFILES || !defined wxHAS_LARGE_FILES)
|
|
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(1) < m_bufsize)
|
|
m_bufsize = size_t(len + 1);
|
|
|
|
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 = size_t(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 = size_t(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)
|
|
{
|
|
}
|
|
|
|
wxFileOffset wxBackedInputStream::GetLength() const
|
|
{
|
|
return m_backer.m_impl->GetLength();
|
|
}
|
|
|
|
wxFileOffset wxBackedInputStream::FindLength() const
|
|
{
|
|
wxFileOffset len = GetLength();
|
|
|
|
if (len == wxInvalidOffset && IsOk()) {
|
|
// read a byte at 7ff...ffe
|
|
wxFileOffset pos = 1;
|
|
pos <<= sizeof(pos) * 8 - 1;
|
|
pos = ~pos - 1;
|
|
char ch;
|
|
size_t size = 1;
|
|
m_backer.m_impl->ReadAt(pos, &ch, &size);
|
|
len = GetLength();
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
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::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_FILESYSTEM
|