1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-03-25 16:43:33 +00:00

Move ConstrainedStreamBuf into separate file

This commit is contained in:
elsid 2022-04-14 17:01:36 +02:00
parent ddd01ac777
commit 9d6d0c6ffb
No known key found for this signature in database
GPG Key ID: B845CB9FEE18AB40
5 changed files with 120 additions and 107 deletions

View File

@ -206,7 +206,7 @@ IF(NOT WIN32 AND NOT APPLE)
ENDIF() ENDIF()
add_component_dir (files add_component_dir (files
linuxpath androidpath windowspath macospath fixedpath multidircollection collections configurationmanager 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 add_component_dir (compiler

View File

@ -1,109 +1,8 @@
#include "constrainedfilestream.hpp" #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 namespace Files
{ {
class ConstrainedFileStreamBuf : public std::streambuf ConstrainedFileStream::ConstrainedFileStream(std::unique_ptr<ConstrainedFileStreamBuf> buf)
{
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)
: std::istream(buf.get()) : std::istream(buf.get())
, mBuf(std::move(buf)) , mBuf(std::move(buf))
{ {

View File

@ -1,6 +1,8 @@
#ifndef OPENMW_CONSTRAINEDFILESTREAM_H #ifndef OPENMW_CONSTRAINEDFILESTREAM_H
#define OPENMW_CONSTRAINEDFILESTREAM_H #define OPENMW_CONSTRAINEDFILESTREAM_H
#include "constrainedfilestreambuf.hpp"
#include <istream> #include <istream>
#include <memory> #include <memory>
#include <limits> #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. /// 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: public:
ConstrainedFileStream(std::unique_ptr<std::streambuf> buf); explicit ConstrainedFileStream(std::unique_ptr<ConstrainedFileStreamBuf> buf);
virtual ~ConstrainedFileStream() {};
private: private:
std::unique_ptr<std::streambuf> mBuf; std::unique_ptr<ConstrainedFileStreamBuf> mBuf;
}; };
typedef std::shared_ptr<std::istream> IStreamPtr; typedef std::shared_ptr<std::istream> IStreamPtr;

View File

@ -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;
}
}

View File

@ -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