PoDoFo 1.2.0
Loading...
Searching...
No Matches
StreamDevice.h
1// SPDX-FileCopyrightText: 2006 Dominik Seichter <domseichter@web.de>
2// SPDX-FileCopyrightText: 2020 Francesco Pretto <ceztko@gmail.com>
3// SPDX-License-Identifier: LGPL-2.0-or-later OR MPL-2.0
4
5#ifndef AUX_STREAM_DEVICE_H
6#define AUX_STREAM_DEVICE_H
7
8#include <cstring>
9#include <ostream>
10#include <fstream>
11#include <cstdio>
12#include <vector>
13
14#include "basetypes.h"
15
16#include "InputDevice.h"
17#include "OutputDevice.h"
18
19namespace PoDoFo {
20
27class PODOFO_API StreamDevice : public InputStreamDevice, public OutputStreamDevice
28{
29protected:
30 StreamDevice(DeviceAccess access);
31
32protected:
35 void resetBuffers() override;
36
37 static size_t SeekPosition(size_t curpos, size_t devlen, ssize_t offset, SeekDirection direction);
38};
39
40class PODOFO_API StandardStreamDevice : public StreamDevice
41{
42public:
46 StandardStreamDevice(std::ostream& stream);
47
48 StandardStreamDevice(std::istream& stream);
49
53 StandardStreamDevice(std::iostream& stream);
54
55 ~StandardStreamDevice();
56
57public:
58 size_t GetLength() const override;
59
60 size_t GetPosition() const override;
61
62 bool CanSeek() const override;
63
64 bool Eof() const override;
65
66protected:
67 StandardStreamDevice(DeviceAccess access, std::ios& stream, bool streamOwned);
68 void writeBuffer(const char* buffer, size_t size) override;
69 void flush() override;
70 size_t readBuffer(char* buffer, size_t size, bool& eof) override;
71 bool readChar(char& ch) override;
72 bool peek(char& ch) const override;
73 void seek(ssize_t offset, SeekDirection direction) override;
74 void truncate() override;
75
76 inline std::ios& GetStream() { return *m_Stream; }
77
78private:
79 StandardStreamDevice(DeviceAccess access, std::ios* stream, std::istream* istream, std::ostream* ostream, bool streamOwned);
80
81private:
82 std::ios* m_Stream;
83 std::istream* m_istream;
84 std::ostream* m_ostream;
85 bool m_StreamOwned;
86};
87
88// These are the .NET System.IO file opening modes
89// https://docs.microsoft.com/en-us/dotnet/api/system.io.filemode?view=net-6.0
90enum class FileMode : uint8_t
91{
92 CreateNew = 1,
93 Create,
94 Open,
96 Truncate,
97 Append,
98};
99
100class PODOFO_API FileStreamDevice : public StreamDevice
101{
102public:
104 FileStreamDevice(const std::string_view & filepath);
105
107 FileStreamDevice(const std::string_view & filepath, FileMode mode);
108
110 FileStreamDevice(const std::string_view& filepath, FileMode mode,
111 DeviceAccess access);
112
113 ~FileStreamDevice();
114
115public:
116 const std::string& GetFilepath() const { return m_Filepath; }
117
118 size_t GetLength() const override;
119
120 size_t GetPosition() const override;
121
122 bool CanSeek() const override;
123
124 bool Eof() const override;
125
126protected:
127 void writeBuffer(const char* buffer, size_t size) override;
128 void flush() override;
129 size_t readBuffer(char* buffer, size_t size, bool& eof) override;
130 bool readChar(char& ch) override;
131 bool peek(char& ch) const override;
132 void seek(ssize_t offset, SeekDirection direction) override;
133 void close() override;
134 void truncate() override;
135 void resetBuffers() override;
136
137private:
139 enum class BufferDirection : uint8_t
140 {
141 None = 0,
142 Read,
143 Write
144 };
145
146private:
150 void setDirection(BufferDirection direction);
152 size_t getPendingBytesCount() const;
154 void refill();
156 void flushWrite();
158 void beginWrite();
161 void dropBuffers();
163 void syncFdOffset();
166 bool tryRetainBuffer(size_t pos);
167 void ensureOpen() const;
168 void assertInvariants() const;
169
170private:
171 std::string m_Filepath;
172 std::unique_ptr<char[]> m_Buffer;
173 size_t m_BufferOffset;
174 size_t m_Filled;
175 size_t m_Position;
176 size_t m_FdOffset;
177 BufferDirection m_Direction;
178 bool m_Eof;
179 int m_fd;
180};
181
182template <typename TContainer>
183class ContainerStreamDevice : public StreamDevice
184{
185public:
186 ContainerStreamDevice(TContainer& container,
187 DeviceAccess access, bool ate) :
188 StreamDevice(access),
189 m_container(&container),
190 m_Position(ate ? container.size() : 0)
191 {
192 tryEnableReadWindow();
193 }
194
196 ContainerStreamDevice(const TContainer& container) :
197 ContainerStreamDevice(const_cast<TContainer&>(container), DeviceAccess::Read, false) { }
198
200 ContainerStreamDevice(TContainer& container) :
201 ContainerStreamDevice(container, DeviceAccess::ReadWrite, true) { }
202
203public:
204 size_t GetLength() const override { return m_container->size(); }
205
206 size_t GetPosition() const override { return getPos(); }
207
208 bool CanSeek() const override { return true; }
209
210 bool Eof() const override { return getPos() == m_container->size(); }
211
212protected:
213 void writeBuffer(const char* buffer, size_t size) override
214 {
215 size_t pos = getPos();
216 if (pos + size > m_container->size())
217 {
218 // NOTE: Growing can reallocate, so the window has to be re-armed
219 // over the new storage rather than advanced over the old one
220 m_container->resize(pos + size);
221 std::memcpy(m_container->data() + pos, buffer, size);
222 m_Position = pos + size;
223 tryEnableReadWindow();
224 return;
225 }
226
227 std::memcpy(m_container->data() + pos, buffer, size);
228 setPos(pos + size);
229 }
230
231 size_t readBuffer(char* buffer, size_t size, bool& eof) override
232 {
233 size_t pos = getPos();
234 size_t readCount = std::min(size, m_container->size() - pos);
235 std::memcpy(buffer, m_container->data() + pos, readCount);
236 setPos(pos + readCount);
237 eof = pos + readCount == m_container->size();
238 return readCount;
239 }
240
241 bool readChar(char& ch) override
242 {
243 size_t pos = getPos();
244 if (pos == m_container->size())
245 {
246 ch = '\0';
247 return false;
248 }
249
250 ch = m_container->data()[pos];
251 setPos(pos + 1);
252 return true;
253 }
254
255 bool peek(char& ch) const override
256 {
257 size_t pos = getPos();
258 if (pos == m_container->size())
259 {
260 ch = '\0';
261 return false;
262 }
263
264 ch = m_container->data()[pos];
265 return true;
266 }
267
268 void seek(ssize_t offset, SeekDirection direction) override
269 {
270 // NOTE: resetBuffers() already committed the position to m_Position
271 m_Position = SeekPosition(m_Position, m_container->size(), offset, direction);
272 tryEnableReadWindow();
273 }
274
275 void truncate() override
276 {
277 // NOTE: resetBuffers() already committed the position to m_Position
278 m_container->resize(m_Position);
279 tryEnableReadWindow();
280 }
281
282 void resetBuffers() override
283 {
284 m_Position = getPos();
286 }
287
288private:
290 size_t getPos() const
291 {
292 // NOTE: Test the arm flag: a fully consumed container is armed and
293 // empty and its position still lives in the window
294 return m_tail == nullptr ? m_Position : (size_t)(m_head - m_container->data());
295 }
296
298 void setPos(size_t pos)
299 {
300 m_Position = pos;
301 if (m_tail != nullptr)
302 m_head = m_container->data() + pos;
303 }
304
307 void tryEnableReadWindow()
308 {
309 if ((GetAccess() & DeviceAccess::Read) != DeviceAccess{ })
310 enableReadWindow(m_container->data() + m_Position, m_container->data() + m_container->size());
311 }
312
313private:
314 TContainer* m_container;
315 size_t m_Position;
316};
317
318class PODOFO_API SpanStreamDevice : public StreamDevice
319{
320public:
323 SpanStreamDevice(const char* buffer, size_t size);
324 SpanStreamDevice(const bufferview& buffer);
325 SpanStreamDevice(const std::string_view& view);
326 SpanStreamDevice(const std::string& str);
327 SpanStreamDevice(std::string& str,
328 DeviceAccess access = DeviceAccess::ReadWrite);
329 SpanStreamDevice(const char* str);
330 SpanStreamDevice(char* buffer, size_t size,
331 DeviceAccess access = DeviceAccess::ReadWrite);
332 SpanStreamDevice(const bufferspan& span,
333 DeviceAccess access = DeviceAccess::ReadWrite);
334
335public:
336 size_t GetLength() const override;
337
338 size_t GetPosition() const override;
339
340 bool Eof() const override;
341
342 bool CanSeek() const override;
343
344protected:
345 void writeBuffer(const char* buffer, size_t size) override;
346 size_t readBuffer(char* buffer, size_t size, bool& eof) override;
347 bool readChar(char& ch) override;
348 bool peek(char& ch) const override;
349 void seek(ssize_t offset, SeekDirection direction) override;
350 void truncate() override;
351 void resetBuffers() override;
352
353private:
354 SpanStreamDevice(std::nullptr_t) = delete;
355
356private:
358 size_t getPos() const;
360 void setPos(size_t pos);
362 void tryEnableReadWindow();
363
364private:
365 char* m_buffer;
366 size_t m_Length;
367 size_t m_Position;
368};
369
371class PODOFO_API NullStreamDevice final : public StreamDevice
372{
373public:
375
376public:
377 size_t GetLength() const override;
378
379 size_t GetPosition() const override;
380
381 bool Eof() const override;
382
383protected:
384 void writeBuffer(const char* buffer, size_t size) override;
385 size_t readBuffer(char* buffer, size_t size, bool& eof) override;
386 bool readChar(char& ch) override;
387 bool peek(char& ch) const override;
388 void seek(ssize_t offset, SeekDirection direction) override;
389 void truncate() override;
390
391private:
392 size_t m_Length;
393 size_t m_Position;
394};
395
399
400}
401
402#endif // AUX_STREAM_DEVICE_H
This class represents an input device It optionally supports peeking.
Definition InputDevice.h:19
void enableReadWindow(const char *head, const char *tail)
Enable the inline read window over the supplied memory region.
Definition InputDevice.cpp:48
const char * m_head
Inline read window over memory that already holds the bytes at the current logical position.
Definition InputStream.h:90
void Read(char *buffer, size_t size)
Read data from the device.
Definition InputStream.cpp:20
An StreamDevice device that does nothing.
Definition StreamDevice.h:372
This class provides an output device which operates either on a file or on a buffer in memory.
Definition StreamDevice.h:28
void resetBuffers() override
NOTE: It just forwards to InputStreamDevice, disambiguating the InputStreamDevice/OutputStreamDevice ...
Definition StreamDevice.cpp:113
Convenient type for char array storage and/or buffer with std::string compatibility.
Definition basetypes.h:30
All classes, functions, types and enums of PoDoFo are members of these namespace.
Definition basetypes.h:13
@ None
Do not add a default appearance.
FileMode
Definition StreamDevice.h:91
@ CreateNew
Create a new file (throw if existing) for writing/reading.
@ OpenOrCreate
Open an existing file or create a new one for writing/reading.
@ Append
Open an existing file and seek to the end for writing.
@ Create
Create a new file or truncate existing one for writing/reading.
@ Truncate
Truncate an existing file for writing/reading.
@ Open
Open an existing file for reading and/or writing.