1//
2// BufferedStreamBuf.h
3//
4// Library: Foundation
5// Package: Streams
6// Module: StreamBuf
7//
8// Definition of template BasicBufferedStreamBuf and class BufferedStreamBuf.
9//
10// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
11// and Contributors.
12//
13// SPDX-License-Identifier: BSL-1.0
14//
15
16
17#ifndef Foundation_BufferedStreamBuf_INCLUDED
18#define Foundation_BufferedStreamBuf_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 BasicBufferedStreamBuf: public std::basic_streambuf<ch, tr>
34 /// This is an implementation of a buffered streambuf
35 /// 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 /// This streambuf only supports unidirectional streams.
41 /// In other words, the BasicBufferedStreamBuf can be
42 /// used for the implementation of an istream or an
43 /// ostream, but not for 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 BasicBufferedStreamBuf(std::streamsize bufferSize, openmode mode):
58 _bufsize(bufferSize),
59 _pBuffer(Allocator::allocate(_bufsize)),
60 _mode(mode)
61 {
62 this->setg(_pBuffer + 4, _pBuffer + 4, _pBuffer + 4);
63 this->setp(_pBuffer, _pBuffer + (_bufsize - 1));
64 }
65
66 ~BasicBufferedStreamBuf()
67 {
68 try
69 {
70 Allocator::deallocate(_pBuffer, _bufsize);
71 } catch (...)
72 {
73 poco_unexpected();
74 }
75 }
76
77 virtual int_type overflow(int_type c)
78 {
79 if (!(_mode & IOS::out)) return char_traits::eof();
80
81 if (c != char_traits::eof())
82 {
83 *this->pptr() = char_traits::to_char_type(c);
84 this->pbump(1);
85 }
86 if (flushBuffer() == std::streamsize(-1)) return char_traits::eof();
87
88 return c;
89 }
90
91 virtual int_type underflow()
92 {
93 if (!(_mode & IOS::in)) return char_traits::eof();
94
95 if (this->gptr() && (this->gptr() < this->egptr()))
96 return char_traits::to_int_type(*this->gptr());
97
98 int putback = int(this->gptr() - this->eback());
99 if (putback > 4) putback = 4;
100
101 char_traits::move(_pBuffer + (4 - putback), this->gptr() - putback, putback);
102
103 int n = readFromDevice(_pBuffer + 4, _bufsize - 4);
104 if (n <= 0) return char_traits::eof();
105
106 this->setg(_pBuffer + (4 - putback), _pBuffer + 4, _pBuffer + 4 + n);
107
108 // return next character
109 return char_traits::to_int_type(*this->gptr());
110 }
111
112 virtual int sync()
113 {
114 if (this->pptr() && this->pptr() > this->pbase())
115 {
116 if (flushBuffer() == -1) return -1;
117 }
118 return 0;
119 }
120
121protected:
122 void setMode(openmode mode)
123 {
124 _mode = mode;
125 }
126
127 openmode getMode() const
128 {
129 return _mode;
130 }
131
132private:
133 virtual int readFromDevice(char_type* /*buffer*/, std::streamsize /*length*/)
134 {
135 return 0;
136 }
137
138 virtual int writeToDevice(const char_type* /*buffer*/, std::streamsize /*length*/)
139 {
140 return 0;
141 }
142
143 int flushBuffer()
144 {
145 int n = int(this->pptr() - this->pbase());
146 if (writeToDevice(this->pbase(), n) == n)
147 {
148 this->pbump(-n);
149 return n;
150 }
151 return -1;
152 }
153
154 std::streamsize _bufsize;
155 char_type* _pBuffer;
156 openmode _mode;
157
158 BasicBufferedStreamBuf(const BasicBufferedStreamBuf&);
159 BasicBufferedStreamBuf& operator = (const BasicBufferedStreamBuf&);
160};
161
162
163//
164// We provide an instantiation for char.
165//
166// Visual C++ needs a workaround - explicitly importing the template
167// instantiation - to avoid duplicate symbols due to multiple
168// instantiations in different libraries.
169//
170#if defined(_MSC_VER) && defined(POCO_DLL) && !defined(Foundation_EXPORTS)
171template class Foundation_API BasicBufferedStreamBuf<char, std::char_traits<char> >;
172#endif
173typedef BasicBufferedStreamBuf<char, std::char_traits<char> > BufferedStreamBuf;
174
175
176} // namespace Poco
177
178
179#endif // Foundation_BufferedStreamBuf_INCLUDED
180