1//
2// BufferedBidirectionalStreamBuf.h
3//
4// Library: Foundation
5// Package: Streams
6// Module: StreamBuf
7//
8// Definition of template BasicBufferedBidirectionalStreamBuf and class BufferedBidirectionalStreamBuf.
9//
10// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
11// and Contributors.
12//
13// SPDX-License-Identifier: BSL-1.0
14//
15
16
17#ifndef Foundation_BufferedBidirectionalStreamBuf_INCLUDED
18#define Foundation_BufferedBidirectionalStreamBuf_INCLUDED
19
20
21#include "Poco/Foundation.h"
22#include "Poco/BufferAllocator.h"
23#include "Poco/StreamUtil.h"
24#include <streambuf>
25#include <iosfwd>
26#include <ios>
27
28
29namespace Poco {
30
31
32template <typename ch, typename tr, typename ba = BufferAllocator<ch> >
33class BasicBufferedBidirectionalStreamBuf: public std::basic_streambuf<ch, tr>
34 /// This is an implementation of a buffered bidirectional
35 /// streambuf that greatly simplifies the implementation of
36 /// custom streambufs of various kinds.
37 /// Derived classes only have to override the methods
38 /// readFromDevice() or writeToDevice().
39 ///
40 /// In contrast to BasicBufferedStreambuf, this class supports
41 /// simultaneous read and write access, so in addition to
42 /// istream and ostream this streambuf can also be used
43 /// for implementing an iostream.
44{
45protected:
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 ba Allocator;
51 typedef typename Base::int_type int_type;
52 typedef typename Base::pos_type pos_type;
53 typedef typename Base::off_type off_type;
54 typedef typename IOS::openmode openmode;
55
56public:
57 BasicBufferedBidirectionalStreamBuf(std::streamsize bufferSize, openmode mode):
58 _bufsize(bufferSize),
59 _pReadBuffer(Allocator::allocate(_bufsize)),
60 _pWriteBuffer(Allocator::allocate(_bufsize)),
61 _mode(mode)
62 {
63 resetBuffers();
64 }
65
66 ~BasicBufferedBidirectionalStreamBuf()
67 {
68 Allocator::deallocate(_pReadBuffer, _bufsize);
69 Allocator::deallocate(_pWriteBuffer, _bufsize);
70 }
71
72 virtual int_type overflow(int_type c)
73 {
74 if (!(_mode & IOS::out)) return char_traits::eof();
75
76 if (flushBuffer() == std::streamsize(-1)) return char_traits::eof();
77 if (c != char_traits::eof())
78 {
79 *this->pptr() = char_traits::to_char_type(c);
80 this->pbump(1);
81 }
82
83 return c;
84 }
85
86 virtual int_type underflow()
87 {
88 if (!(_mode & IOS::in)) return char_traits::eof();
89
90 if (this->gptr() && (this->gptr() < this->egptr()))
91 return char_traits::to_int_type(*this->gptr());
92
93 int putback = int(this->gptr() - this->eback());
94 if (putback > 4) putback = 4;
95
96 char_traits::move(_pReadBuffer + (4 - putback), this->gptr() - putback, putback);
97
98 int n = readFromDevice(_pReadBuffer + 4, _bufsize - 4);
99 if (n <= 0) return char_traits::eof();
100
101 this->setg(_pReadBuffer + (4 - putback), _pReadBuffer + 4, _pReadBuffer + 4 + n);
102
103 // return next character
104 return char_traits::to_int_type(*this->gptr());
105 }
106
107 virtual int sync()
108 {
109 if (this->pptr() && this->pptr() > this->pbase())
110 {
111 if (flushBuffer() == -1) return -1;
112 }
113 return 0;
114 }
115
116protected:
117 void setMode(openmode mode)
118 {
119 _mode = mode;
120 }
121
122 openmode getMode() const
123 {
124 return _mode;
125 }
126
127 void resetBuffers()
128 {
129 this->setg(_pReadBuffer + 4, _pReadBuffer + 4, _pReadBuffer + 4);
130 this->setp(_pWriteBuffer, _pWriteBuffer + _bufsize);
131 }
132
133private:
134 virtual int readFromDevice(char_type* /*buffer*/, std::streamsize /*length*/)
135 {
136 return 0;
137 }
138
139 virtual int writeToDevice(const char_type* /*buffer*/, std::streamsize /*length*/)
140 {
141 return 0;
142 }
143
144 int flushBuffer()
145 {
146 int n = int(this->pptr() - this->pbase());
147 if (writeToDevice(this->pbase(), n) == n)
148 {
149 this->pbump(-n);
150 return n;
151 }
152 return -1;
153 }
154
155 std::streamsize _bufsize;
156 char_type* _pReadBuffer;
157 char_type* _pWriteBuffer;
158 openmode _mode;
159
160 BasicBufferedBidirectionalStreamBuf(const BasicBufferedBidirectionalStreamBuf&);
161 BasicBufferedBidirectionalStreamBuf& operator = (const BasicBufferedBidirectionalStreamBuf&);
162};
163
164
165//
166// We provide an instantiation for char.
167//
168// Visual C++ needs a workaround - explicitly importing the template
169// instantiation - to avoid duplicate symbols due to multiple
170// instantiations in different libraries.
171//
172#if defined(_MSC_VER) && defined(POCO_DLL) && !defined(Foundation_EXPORTS)
173template class Foundation_API BasicBufferedBidirectionalStreamBuf<char, std::char_traits<char> >;
174#endif
175typedef BasicBufferedBidirectionalStreamBuf<char, std::char_traits<char> > BufferedBidirectionalStreamBuf;
176
177
178} // namespace Poco
179
180
181#endif // Foundation_BufferedBidirectionalStreamBuf_INCLUDED
182