Move ConstrainedStreamBuf into separate file

pull/3226/head
elsid 3 years ago
parent ddd01ac777
commit 9d6d0c6ffb
No known key found for this signature in database
GPG Key ID: B845CB9FEE18AB40

@ -206,7 +206,7 @@ IF(NOT WIN32 AND NOT APPLE)
ENDIF()
add_component_dir (files
linuxpath androidpath windowspath macospath fixedpath multidircollection collections configurationmanager
lowlevelfile constrainedfilestream memorystream hash configfileparser openfile
lowlevelfile constrainedfilestream memorystream hash configfileparser openfile constrainedfilestreambuf
)
add_component_dir (compiler

@ -1,109 +1,8 @@
#include "constrainedfilestream.hpp"
#include <streambuf>
#include <algorithm>
#include "lowlevelfile.hpp"
namespace
{
// somewhat arbitrary though 64KB buffers didn't seem to improve performance any
const size_t sBufferSize = 8192;
}
namespace Files
{
class ConstrainedFileStreamBuf : public std::streambuf
{
size_t mOrigin;
size_t mSize;
LowLevelFile mFile;
char mBuffer[sBufferSize]{0};
public:
ConstrainedFileStreamBuf(const std::string &fname, size_t start, size_t length)
{
mFile.open (fname.c_str ());
mSize = length != std::numeric_limits<std::size_t>::max() ? length : mFile.size () - start;
if (start != 0)
mFile.seek(start);
setg(nullptr,nullptr,nullptr);
mOrigin = start;
}
int_type underflow() override
{
if(gptr() == egptr())
{
size_t toRead = std::min((mOrigin+mSize)-(mFile.tell()), sBufferSize);
// Read in the next chunk of data, and set the read pointers on success
// Failure will throw exception in LowLevelFile
size_t got = mFile.read(mBuffer, toRead);
setg(&mBuffer[0], &mBuffer[0], &mBuffer[0]+got);
}
if(gptr() == egptr())
return traits_type::eof();
return traits_type::to_int_type(*gptr());
}
pos_type seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode) override
{
if((mode&std::ios_base::out) || !(mode&std::ios_base::in))
return traits_type::eof();
// new file position, relative to mOrigin
size_t newPos;
switch (whence)
{
case std::ios_base::beg:
newPos = offset;
break;
case std::ios_base::cur:
newPos = (mFile.tell() - mOrigin - (egptr() - gptr())) + offset;
break;
case std::ios_base::end:
newPos = mSize + offset;
break;
default:
return traits_type::eof();
}
if (newPos > mSize)
return traits_type::eof();
mFile.seek(mOrigin+newPos);
// Clear read pointers so underflow() gets called on the next read attempt.
setg(nullptr, nullptr, nullptr);
return newPos;
}
pos_type seekpos(pos_type pos, std::ios_base::openmode mode) override
{
if((mode&std::ios_base::out) || !(mode&std::ios_base::in))
return traits_type::eof();
if ((size_t)pos > mSize)
return traits_type::eof();
mFile.seek(mOrigin + pos);
// Clear read pointers so underflow() gets called on the next read attempt.
setg(nullptr, nullptr, nullptr);
return pos;
}
};
ConstrainedFileStream::ConstrainedFileStream(std::unique_ptr<std::streambuf> buf)
ConstrainedFileStream::ConstrainedFileStream(std::unique_ptr<ConstrainedFileStreamBuf> buf)
: std::istream(buf.get())
, mBuf(std::move(buf))
{

@ -1,6 +1,8 @@
#ifndef OPENMW_CONSTRAINEDFILESTREAM_H
#define OPENMW_CONSTRAINEDFILESTREAM_H
#include "constrainedfilestreambuf.hpp"
#include <istream>
#include <memory>
#include <limits>
@ -10,14 +12,13 @@ namespace Files
{
/// A file stream constrained to a specific region in the file, specified by the 'start' and 'length' parameters.
class ConstrainedFileStream : public std::istream
class ConstrainedFileStream final : public std::istream
{
public:
ConstrainedFileStream(std::unique_ptr<std::streambuf> buf);
virtual ~ConstrainedFileStream() {};
explicit ConstrainedFileStream(std::unique_ptr<ConstrainedFileStreamBuf> buf);
private:
std::unique_ptr<std::streambuf> mBuf;
std::unique_ptr<ConstrainedFileStreamBuf> mBuf;
};
typedef std::shared_ptr<std::istream> IStreamPtr;

@ -0,0 +1,83 @@
#include "constrainedfilestreambuf.hpp"
#include <algorithm>
#include <limits>
namespace Files
{
ConstrainedFileStreamBuf::ConstrainedFileStreamBuf(const std::string& fname, std::size_t start, std::size_t length)
: mOrigin(start)
{
mFile.open(fname.c_str());
mSize = length != std::numeric_limits<std::size_t>::max() ? length : mFile.size () - start;
if (start != 0)
mFile.seek(start);
setg(nullptr, nullptr, nullptr);
}
std::streambuf::int_type ConstrainedFileStreamBuf::underflow()
{
if (gptr() == egptr())
{
const std::size_t toRead = std::min((mOrigin + mSize) - (mFile.tell()), sizeof(mBuffer));
// Read in the next chunk of data, and set the read pointers on success
// Failure will throw exception in LowLevelFile
const std::size_t got = mFile.read(mBuffer, toRead);
setg(&mBuffer[0], &mBuffer[0], &mBuffer[0] + got);
}
if (gptr() == egptr())
return traits_type::eof();
return traits_type::to_int_type(*gptr());
}
std::streambuf::pos_type ConstrainedFileStreamBuf::seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode)
{
if ((mode & std::ios_base::out) || !(mode & std::ios_base::in))
return traits_type::eof();
// new file position, relative to mOrigin
size_t newPos;
switch (whence)
{
case std::ios_base::beg:
newPos = offset;
break;
case std::ios_base::cur:
newPos = (mFile.tell() - mOrigin - (egptr() - gptr())) + offset;
break;
case std::ios_base::end:
newPos = mSize + offset;
break;
default:
return traits_type::eof();
}
if (newPos > mSize)
return traits_type::eof();
mFile.seek(mOrigin + newPos);
// Clear read pointers so underflow() gets called on the next read attempt.
setg(nullptr, nullptr, nullptr);
return newPos;
}
std::streambuf::pos_type ConstrainedFileStreamBuf::seekpos(pos_type pos, std::ios_base::openmode mode)
{
if ((mode & std::ios_base::out) || !(mode & std::ios_base::in))
return traits_type::eof();
if (static_cast<std::size_t>(pos) > mSize)
return traits_type::eof();
mFile.seek(mOrigin + pos);
// Clear read pointers so underflow() gets called on the next read attempt.
setg(nullptr, nullptr, nullptr);
return pos;
}
}

@ -0,0 +1,30 @@
#ifndef OPENMW_CONSTRAINEDFILESTREAMBUF_H
#define OPENMW_CONSTRAINEDFILESTREAMBUF_H
#include "lowlevelfile.hpp"
#include <streambuf>
namespace Files
{
/// A file streambuf constrained to a specific region in the file, specified by the 'start' and 'length' parameters.
class ConstrainedFileStreamBuf final : public std::streambuf
{
public:
ConstrainedFileStreamBuf(const std::string& fname, std::size_t start, std::size_t length);
int_type underflow() final;
pos_type seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode) final;
pos_type seekpos(pos_type pos, std::ios_base::openmode mode) final;
private:
std::size_t mOrigin;
std::size_t mSize;
LowLevelFile mFile;
char mBuffer[8192]{0};
};
}
#endif
Loading…
Cancel
Save