I'm attempting to create a custom std::streambuf
which acts as a sub-stream to a parent stream. This is an adaptation of the implementation outlined in this SO thread answer.
In this example below I am attempting to simply read the first 5 characters "Hello,"
of the stream. However, when I call ifstream.read()
into the buffer
, the buffer is filled with "ello, "
, as though it is off by one.
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
stringstream ss;
ss << "Hello, World!";
substreambuf asd(ss.rdbuf(), 0, 5);
istream istream(&asd);
char buffer[6] = { '\0' };
istream.read(buffer, sizeof(buffer));
cout << buffer << endl; //prints "ello, "
}
I am new to streambuf
s and I feel like I'm missing something obvious here. Any help would be appreciated.
Here is the definition for substreambuf
:
#include <iostream>
#include <sstream>
namespace std
{
struct substreambuf : public streambuf
{
explicit substreambuf(streambuf* sbuf, streampos pos, streampos len) :
m_sbuf(sbuf),
m_pos(pos),
m_len(len),
m_read(0)
{
m_sbuf->pubseekpos(pos);
setbuf(nullptr, 0);
}
protected:
int underflow()
{
if (m_read >= m_len)
{
return traits_type::eof();
}
return m_sbuf->sgetc();
}
int uflow()
{
if (m_read >= m_len)
{
return traits_type::eof();
}
m_read += 1;
return m_sbuf->snextc();
}
streampos seekoff(streamoff off, ios_base::seekdir seekdir, ios_base::openmode openmode = ios_base::in | ios_base::out)
{
if (seekdir == ios_base::beg)
{
off += m_pos;
}
else if (seekdir == ios_base::cur)
{
off += m_pos + m_read;
}
else if (seekdir == ios_base::end)
{
off += m_pos + m_len;
}
return m_sbuf->pubseekpos(off, openmode) - m_pos;
}
streampos seekpos(streampos streampos, ios_base::openmode openmode = ios_base::in | ios_base::out)
{
streampos += m_pos;
if (streampos > m_pos + m_len)
{
return -1;
}
return m_sbuf->pubseekpos(streampos, openmode) - m_pos;
}
private:
streambuf* m_sbuf;
streampos m_pos;
streamsize m_len;
streampos m_read;
};
};