Skip to content

Commit 5e104ad

Browse files
Issue pocoproject#297 - Implemented BasicMemoryStreamBuf::seekoff
This change adds support for `tellp`, `tellg` and seeking. **Additional notes:** + `tellg` calls `rdbuf->pubseekoff(0, cur, out)` [lib.ostream.seeks] so need to provide an override of `seekoff`. + Requirements for `seekoff` are in 27.7.1.3. + 27.7.1.3 - Standard has a roundabout way of saying `cur` is valid if only one of `in` or `out` is specified (Condition 3). + `xend` is `egptr`/`epptr` (get area/put area). + `xbeg` is `eback`/`pbase` (get area/put area). + `xnext` is `gptr`/`pptr` (get area/put area). + `newoff` is a bit of a misnomer, the new offset into the stream is given by `newoff + off`. `newoff` is really the start point. + You can set `gnext` with `setg`, but you can't do that with `setp` you have to `pbump` by the new offset minus the current offset.
1 parent f79ab5b commit 5e104ad

3 files changed

Lines changed: 202 additions & 12 deletions

File tree

Foundation/include/Poco/MemoryStream.h

Lines changed: 71 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232
namespace Poco {
3333

3434

35-
template <typename ch, typename tr>
36-
class BasicMemoryStreamBuf: public std::basic_streambuf<ch, tr>
35+
template <typename charT, typename traits>
36+
class BasicMemoryStreamBuf: public std::basic_streambuf<charT, traits>
3737
/// BasicMemoryStreamBuf is a simple implementation of a
3838
/// stream buffer for reading and writing from a memory area.
3939
///
@@ -43,13 +43,11 @@ class BasicMemoryStreamBuf: public std::basic_streambuf<ch, tr>
4343
/// ostream, but not for an iostream.
4444
{
4545
protected:
46-
typedef std::basic_streambuf<ch, tr> Base;
47-
typedef std::basic_ios<ch, tr> IOS;
48-
typedef ch char_type;
49-
typedef tr char_traits;
50-
typedef typename Base::int_type int_type;
51-
typedef typename Base::pos_type pos_type;
52-
typedef typename Base::off_type off_type;
46+
typedef charT char_type;
47+
typedef typename traits::int_type int_type;
48+
typedef typename traits::pos_type pos_type;
49+
typedef typename traits::off_type off_type;
50+
typedef traits traits_type;
5351

5452
public:
5553
BasicMemoryStreamBuf(char_type* pBuffer, std::streamsize bufferSize):
@@ -66,12 +64,74 @@ class BasicMemoryStreamBuf: public std::basic_streambuf<ch, tr>
6664

6765
virtual int_type overflow(int_type /*c*/)
6866
{
69-
return char_traits::eof();
67+
return traits_type::eof();
7068
}
7169

7270
virtual int_type underflow()
7371
{
74-
return char_traits::eof();
72+
return traits_type::eof();
73+
}
74+
75+
virtual pos_type seekoff(off_type off, std::ios_base::seekdir way, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out)
76+
{
77+
const pos_type fail = off_type(-1);
78+
off_type newoff = off_type(-1);
79+
80+
if ((which & std::ios_base::in) != 0)
81+
{
82+
// Position the input sequence
83+
84+
if (gptr() == 0)
85+
return fail;
86+
87+
switch (way)
88+
{
89+
case std::ios_base::beg:
90+
newoff = 0;
91+
break;
92+
case std::ios_base::cur:
93+
// cur is not valid if both in and out are specified (Condition 3)
94+
if ((which & std::ios_base::out) != 0)
95+
return fail;
96+
newoff = gptr() - eback();
97+
break;
98+
case std::ios_base::end:
99+
newoff = egptr() - eback();
100+
break;
101+
}
102+
103+
if ((newoff + off) < 0 || (egptr() - eback()) < (newoff + off))
104+
return fail;
105+
this->setg(eback(), eback() + newoff + off, egptr());
106+
}
107+
108+
if ((which & std::ios_base::out) != 0)
109+
{
110+
if (pptr() == 0)
111+
return fail;
112+
113+
switch (way)
114+
{
115+
case std::ios_base::beg:
116+
newoff = 0;
117+
break;
118+
case std::ios_base::cur:
119+
// cur is not valid if both in and out are specified (Condition 3)
120+
if ((which & std::ios_base::in) != 0)
121+
return fail;
122+
newoff = pptr() - pbase();
123+
break;
124+
case std::ios_base::end:
125+
newoff = epptr() - pbase();
126+
break;
127+
}
128+
129+
if (newoff + off < 0 || (epptr() - pbase()) < newoff + off)
130+
return fail;
131+
this->pbump((int)(newoff + off - (pptr() - pbase())));
132+
}
133+
134+
return newoff;
75135
}
76136

77137
virtual int sync()

Foundation/testsuite/src/MemoryStreamTest.cpp

Lines changed: 127 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "Poco/Buffer.h"
1717
#include "Poco/MemoryStream.h"
1818

19+
#include <sstream>
1920

2021
using Poco::MemoryInputStream;
2122
using Poco::MemoryOutputStream;
@@ -87,7 +88,6 @@ void MemoryStreamTest::testOutput()
8788
assert (ostr2.fail());
8889
}
8990

90-
9191
void MemoryStreamTest::testTell()
9292
{
9393
Poco::Buffer<char> buffer(1024);
@@ -113,6 +113,128 @@ void MemoryStreamTest::testTell()
113113
}
114114

115115

116+
void MemoryStreamTest::testInputSeek()
117+
{
118+
Poco::Buffer<char> buffer(9);
119+
Poco::MemoryOutputStream ostr(buffer.begin(), buffer.size());
120+
ostr << '1' << '2' << '3' << '4' << '5' << '6' << '7' << '8' << '9';
121+
122+
Poco::MemoryInputStream istr(buffer.begin(), buffer.size());
123+
char c;
124+
125+
istr >> c;
126+
assert (c == '1');
127+
128+
istr.seekg(3, std::ios_base::beg); // 3 from beginning
129+
istr >> c; // now that makes 4
130+
assert (c == '4');
131+
132+
istr.seekg(2, std::ios_base::cur); // now that makes 6
133+
istr >> c; // now that makes 7
134+
assert (c == '7');
135+
136+
istr.seekg(-7, std::ios_base::end); // so that puts us at 2
137+
istr >> c; // now 3
138+
assert (c == '3');
139+
}
140+
141+
142+
void MemoryStreamTest::testInputSeekVsStringStream()
143+
{
144+
Poco::Buffer<char> buffer(9);
145+
Poco::MemoryOutputStream ostr(buffer.begin(), buffer.size());
146+
ostr << '1' << '2' << '3' << '4' << '5' << '6' << '7' << '8' << '9';
147+
148+
std::stringstream sss;
149+
sss << '1' << '2' << '3' << '4' << '5' << '6' << '7' << '8' << '9';
150+
151+
Poco::MemoryInputStream mis(buffer.begin(), buffer.size());
152+
153+
char x, y;
154+
155+
sss >> x;
156+
mis >> y;
157+
assert (x == y);
158+
159+
sss.seekg(3, std::ios_base::beg);
160+
mis.seekg(3, std::ios_base::beg);
161+
sss >> x;
162+
mis >> y;
163+
assert (x == y);
164+
165+
sss.seekg(2, std::ios_base::cur);
166+
mis.seekg(2, std::ios_base::cur);
167+
sss >> x;
168+
mis >> y;
169+
assert (x == y);
170+
171+
sss.seekg(-7, std::ios_base::end);
172+
mis.seekg(-7, std::ios_base::end);
173+
sss >> x;
174+
mis >> y;
175+
assert (x == y);
176+
}
177+
178+
179+
void MemoryStreamTest::testOutputSeek()
180+
{
181+
Poco::Buffer<char> buffer(9);
182+
Poco::MemoryOutputStream ostr(buffer.begin(), buffer.size());
183+
ostr << '1' << '2' << '3' << '4' << '5' << '6' << '7' << '8' << '9';
184+
185+
ostr.seekp(4, std::ios_base::beg); // 4 from beginning
186+
ostr << 'a'; // and that makes 5 (zero index 4)
187+
assert (buffer[4] == 'a');
188+
189+
ostr.seekp(2, std::ios_base::cur); // and this makes 7
190+
ostr << 'b'; // and this makes 8 (zero index 7)
191+
assert (buffer[7] == 'b');
192+
193+
ostr.seekp(-3, std::ios_base::end); // 10-7 from the beginning
194+
ostr << 'c'; // and this makes 4 (zero index 3)
195+
assert (buffer[6] == 'c');
196+
}
197+
198+
199+
void MemoryStreamTest::testOutputSeekVsStringStream()
200+
{
201+
Poco::Buffer<char> buffer(9);
202+
Poco::MemoryOutputStream mos(buffer.begin(), buffer.size());
203+
mos << '1' << '2' << '3' << '4' << '5' << '6' << '7' << '8' << '9';
204+
205+
std::ostringstream oss;
206+
oss << '1' << '2' << '3' << '4' << '5' << '6' << '7' << '8' << '9';
207+
208+
mos.seekp(4, std::ios_base::beg);
209+
oss.seekp(4, std::ios_base::beg);
210+
mos << 'a';
211+
oss << 'a';
212+
assert (oss.str()[4] == 'a');
213+
assert (buffer[4] == oss.str()[4]);
214+
215+
mos.seekp(2, std::ios_base::cur);
216+
oss.seekp(2, std::ios_base::cur);
217+
mos << 'b';
218+
oss << 'b';
219+
assert (oss.str()[7] == 'b');
220+
assert (buffer[7] == oss.str()[7]);
221+
222+
mos.seekp(-3, std::ios_base::end);
223+
oss.seekp(-3, std::ios_base::end);
224+
mos << 'c';
225+
oss << 'c';
226+
assert (oss.str()[6] == 'c');
227+
assert (buffer[6] == oss.str()[6]);
228+
229+
mos.seekp(-2, std::ios_base::cur);
230+
oss.seekp(-2, std::ios_base::cur);
231+
mos << 'd';
232+
oss << 'd';
233+
assert (oss.str()[5] == 'd');
234+
assert (buffer[5] == oss.str()[5]);
235+
}
236+
237+
116238
void MemoryStreamTest::setUp()
117239
{
118240
}
@@ -130,6 +252,10 @@ CppUnit::Test* MemoryStreamTest::suite()
130252
CppUnit_addTest(pSuite, MemoryStreamTest, testInput);
131253
CppUnit_addTest(pSuite, MemoryStreamTest, testOutput);
132254
CppUnit_addTest(pSuite, MemoryStreamTest, testTell);
255+
CppUnit_addTest(pSuite, MemoryStreamTest, testInputSeek);
256+
CppUnit_addTest(pSuite, MemoryStreamTest, testInputSeekVsStringStream);
257+
CppUnit_addTest(pSuite, MemoryStreamTest, testOutputSeek);
258+
CppUnit_addTest(pSuite, MemoryStreamTest, testOutputSeekVsStringStream);
133259

134260
return pSuite;
135261
}

Foundation/testsuite/src/MemoryStreamTest.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ class MemoryStreamTest: public CppUnit::TestCase
2929
void testInput();
3030
void testOutput();
3131
void testTell();
32+
void testInputSeek();
33+
void testInputSeekVsStringStream();
34+
void testOutputSeek();
35+
void testOutputSeekVsStringStream();
3236

3337
void setUp();
3438
void tearDown();

0 commit comments

Comments
 (0)