Files
wxWidgets/src/common/fileback.cpp
Vadim Zeitlin 3f66f6a5b3 Remove all lines containing cvs/svn "$Id$" keyword.
This keyword is not expanded by Git which means it's not replaced with the
correct revision value in the releases made using git-based scripts and it's
confusing to have lines with unexpanded "$Id$" in the released files. As
expanding them with Git is not that simple (it could be done with git archive
and export-subst attribute) and there are not many benefits in having them in
the first place, just remove all these lines.

If nothing else, this will make an eventual transition to Git simpler.

Closes #14487.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74602 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2013-07-26 16:02:46 +00:00

334 lines
8.4 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: src/common/fileback.cpp
// Purpose: Back an input stream with memory or a file
// Author: Mike Wetherell
// 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) {
wxDELETE(m_stream);
if (count > 0) {
wxDELETEA(m_buf);
m_buflen = 0;
}
m_parenterror = wxSTREAM_READ_ERROR;
return m_parenterror;
}
m_buflen = 0;
if (!m_stream) {
wxDELETEA(m_buf);
}
}
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;
wxDELETE(m_stream);
}
}
// 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