/src/poco/Foundation/include/Poco/MemoryStream.h
Line | Count | Source |
1 | | // |
2 | | // MemoryStream.h |
3 | | // |
4 | | // Library: Foundation |
5 | | // Package: Streams |
6 | | // Module: MemoryStream |
7 | | // |
8 | | // Definition of MemoryStreamBuf, MemoryInputStream, MemoryOutputStream |
9 | | // |
10 | | // Copyright (c) 2009, Applied Informatics Software Engineering GmbH. |
11 | | // and Contributors. |
12 | | // |
13 | | // SPDX-License-Identifier: BSL-1.0 |
14 | | // |
15 | | |
16 | | |
17 | | #ifndef Foundation_MemoryStream_INCLUDED |
18 | | #define Foundation_MemoryStream_INCLUDED |
19 | | |
20 | | |
21 | | #include "Poco/Bugcheck.h" |
22 | | #include "Poco/Foundation.h" |
23 | | #include "Poco/StreamUtil.h" |
24 | | #include <streambuf> |
25 | | #include <iosfwd> |
26 | | #include <ios> |
27 | | #include <istream> |
28 | | #include <ostream> |
29 | | |
30 | | |
31 | | namespace Poco { |
32 | | |
33 | | |
34 | | template <typename ch, typename tr> |
35 | | class BasicMemoryStreamBuf: public std::basic_streambuf<ch, tr> |
36 | | /// BasicMemoryStreamBuf is a simple implementation of a |
37 | | /// stream buffer for reading and writing from a memory area. |
38 | | /// |
39 | | /// This streambuf only supports unidirectional streams. |
40 | | /// In other words, the BasicMemoryStreamBuf can be |
41 | | /// used for the implementation of an istream or an |
42 | | /// ostream, but not for an iostream. |
43 | | { |
44 | | protected: |
45 | | using Base = std::basic_streambuf<ch, tr>; |
46 | | using IOS = std::basic_ios<ch, tr>; |
47 | | using char_type = ch; |
48 | | using char_traits = tr; |
49 | | using int_type = typename Base::int_type; |
50 | | using pos_type = typename Base::pos_type; |
51 | | using off_type = typename Base::off_type; |
52 | | |
53 | | public: |
54 | | BasicMemoryStreamBuf(char_type* pBuffer, std::streamsize bufferSize): |
55 | 194k | _pBuffer(pBuffer), |
56 | 194k | _bufferSize(bufferSize) |
57 | 194k | { |
58 | 194k | this->setg(_pBuffer, _pBuffer, _pBuffer + _bufferSize); |
59 | 194k | this->setp(_pBuffer, _pBuffer + _bufferSize); |
60 | 194k | } |
61 | | |
62 | | ~BasicMemoryStreamBuf() override = default; |
63 | | |
64 | | BasicMemoryStreamBuf() = delete; |
65 | | BasicMemoryStreamBuf(const BasicMemoryStreamBuf&) = delete; |
66 | | BasicMemoryStreamBuf& operator=(const BasicMemoryStreamBuf&) = delete; |
67 | | |
68 | | int_type overflow(int_type /*c*/) override |
69 | 0 | { |
70 | 0 | return char_traits::eof(); |
71 | 0 | } |
72 | | |
73 | | int_type underflow() override |
74 | 350k | { |
75 | 350k | return char_traits::eof(); |
76 | 350k | } |
77 | | |
78 | | pos_type seekoff(off_type off, std::ios_base::seekdir way, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override |
79 | 0 | { |
80 | 0 | const pos_type fail = off_type(-1); |
81 | 0 | off_type newoff = off_type(-1); |
82 | |
|
83 | 0 | if ((which & std::ios_base::in) != 0) |
84 | 0 | { |
85 | 0 | if (this->gptr() == nullptr) |
86 | 0 | return fail; |
87 | | |
88 | 0 | if (way == std::ios_base::beg) |
89 | 0 | { |
90 | 0 | newoff = 0; |
91 | 0 | } |
92 | 0 | else if (way == std::ios_base::cur) |
93 | 0 | { |
94 | | // cur is not valid if both in and out are specified (Condition 3) |
95 | 0 | if ((which & std::ios_base::out) != 0) |
96 | 0 | return fail; |
97 | 0 | newoff = this->gptr() - this->eback(); |
98 | 0 | } |
99 | 0 | else if (way == std::ios_base::end) |
100 | 0 | { |
101 | 0 | newoff = this->egptr() - this->eback(); |
102 | 0 | } |
103 | 0 | else |
104 | 0 | { |
105 | 0 | poco_bugcheck(); |
106 | 0 | } |
107 | | |
108 | 0 | if ((newoff + off) < 0 || (this->egptr() - this->eback()) < (newoff + off)) |
109 | 0 | return fail; |
110 | 0 | this->setg(this->eback(), this->eback() + newoff + off, this->egptr()); |
111 | 0 | } |
112 | | |
113 | 0 | if ((which & std::ios_base::out) != 0) |
114 | 0 | { |
115 | 0 | if (this->pptr() == nullptr) |
116 | 0 | return fail; |
117 | | |
118 | 0 | if (way == std::ios_base::beg) |
119 | 0 | { |
120 | 0 | newoff = 0; |
121 | 0 | } |
122 | 0 | else if (way == std::ios_base::cur) |
123 | 0 | { |
124 | | // cur is not valid if both in and out are specified (Condition 3) |
125 | 0 | if ((which & std::ios_base::in) != 0) |
126 | 0 | return fail; |
127 | 0 | newoff = this->pptr() - this->pbase(); |
128 | 0 | } |
129 | 0 | else if (way == std::ios_base::end) |
130 | 0 | { |
131 | 0 | newoff = this->epptr() - this->pbase(); |
132 | 0 | } |
133 | 0 | else |
134 | 0 | { |
135 | 0 | poco_bugcheck(); |
136 | 0 | } |
137 | | |
138 | 0 | if (newoff + off < 0 || (this->epptr() - this->pbase()) < newoff + off) |
139 | 0 | return fail; |
140 | 0 | this->pbump((int)(newoff + off - (this->pptr() - this->pbase()))); |
141 | 0 | } |
142 | | |
143 | 0 | return newoff; |
144 | 0 | } |
145 | | |
146 | | pos_type seekpos(pos_type pos, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override |
147 | 0 | { |
148 | 0 | const off_type off = pos; |
149 | 0 | return seekoff(off, std::ios::beg, which); |
150 | 0 | } |
151 | | |
152 | | int sync() override |
153 | 0 | { |
154 | 0 | return 0; |
155 | 0 | } |
156 | | |
157 | | std::streamsize charsWritten() const |
158 | 0 | { |
159 | 0 | return static_cast<std::streamsize>(this->pptr() - this->pbase()); |
160 | 0 | } |
161 | | |
162 | | void reset() |
163 | | /// Resets the buffer so that current read and write positions |
164 | | /// will be set to the beginning of the buffer. |
165 | | { |
166 | | this->setg(_pBuffer, _pBuffer, _pBuffer + _bufferSize); |
167 | | this->setp(_pBuffer, _pBuffer + _bufferSize); |
168 | | } |
169 | | |
170 | | private: |
171 | | char_type* _pBuffer; |
172 | | std::streamsize _bufferSize; |
173 | | }; |
174 | | |
175 | | |
176 | | // |
177 | | // We provide an instantiation for char |
178 | | // |
179 | | using MemoryStreamBuf = BasicMemoryStreamBuf<char, std::char_traits<char>>; |
180 | | |
181 | | class Foundation_API MemoryIOS: public virtual std::ios |
182 | | /// The base class for MemoryInputStream and MemoryOutputStream. |
183 | | /// |
184 | | /// This class is needed to ensure the correct initialization |
185 | | /// order of the stream buffer and base classes. |
186 | | { |
187 | | public: |
188 | | MemoryIOS(char* pBuffer, std::streamsize bufferSize); |
189 | | /// Creates the basic stream. |
190 | | |
191 | | ~MemoryIOS() override; |
192 | | /// Destroys the stream. |
193 | | |
194 | | MemoryStreamBuf* rdbuf(); |
195 | | /// Returns a pointer to the underlying streambuf. |
196 | | |
197 | | protected: |
198 | | MemoryStreamBuf _buf; |
199 | | }; |
200 | | |
201 | | |
202 | | class Foundation_API MemoryInputStream: public MemoryIOS, public std::istream |
203 | | /// An input stream for reading from a memory area. |
204 | | { |
205 | | public: |
206 | | MemoryInputStream(const char* pBuffer, std::streamsize bufferSize); |
207 | | /// Creates a MemoryInputStream for the given memory area, |
208 | | /// ready for reading. |
209 | | |
210 | | ~MemoryInputStream() override; |
211 | | /// Destroys the MemoryInputStream. |
212 | | }; |
213 | | |
214 | | |
215 | | class Foundation_API MemoryOutputStream: public MemoryIOS, public std::ostream |
216 | | /// An input stream for reading from a memory area. |
217 | | { |
218 | | public: |
219 | | MemoryOutputStream(char* pBuffer, std::streamsize bufferSize); |
220 | | /// Creates a MemoryOutputStream for the given memory area, |
221 | | /// ready for writing. |
222 | | |
223 | | ~MemoryOutputStream() override; |
224 | | /// Destroys the MemoryInputStream. |
225 | | |
226 | | std::streamsize charsWritten() const; |
227 | | /// Returns the number of chars written to the buffer. |
228 | | }; |
229 | | |
230 | | |
231 | | // |
232 | | // inlines |
233 | | // |
234 | | inline MemoryStreamBuf* MemoryIOS::rdbuf() |
235 | 0 | { |
236 | 0 | return &_buf; |
237 | 0 | } |
238 | | |
239 | | |
240 | | inline std::streamsize MemoryOutputStream::charsWritten() const |
241 | 0 | { |
242 | 0 | return _buf.charsWritten(); |
243 | 0 | } |
244 | | |
245 | | |
246 | | } // namespace Poco |
247 | | |
248 | | |
249 | | #endif // Foundation_MemoryStream_INCLUDED |