Commit ca80db6fc1fe96f3da234390ac27fdc8a0a1ec58

Authored by m-holger
Committed by GitHub
2 parents 3a055d5b 799080b0

Merge pull request #1496 from m-holger/obis

Refactor is::OffsetBuffer and BufferInputSource
include/qpdf/BufferInputSource.hh
... ... @@ -23,6 +23,8 @@
23 23 #include <qpdf/Buffer.hh>
24 24 #include <qpdf/InputSource.hh>
25 25  
  26 +#include <memory>
  27 +
26 28 class QPDF_DLL_CLASS BufferInputSource: public InputSource
27 29 {
28 30 public:
... ... @@ -52,11 +54,17 @@ class QPDF_DLL_CLASS BufferInputSource: public InputSource
52 54 void unreadCh(char ch) override;
53 55  
54 56 private:
  57 +#ifndef QPDF_FUTURE
55 58 bool own_memory;
56 59 std::string description;
57 60 Buffer* buf;
58 61 qpdf_offset_t cur_offset;
59 62 qpdf_offset_t max_offset;
  63 +#else
  64 + class Members;
  65 +
  66 + std::unique_ptr<Members> m;
  67 +#endif
60 68 };
61 69  
62 70 #endif // QPDF_BUFFERINPUTSOURCE_HH
... ...
include/qpdf/QPDF.hh
... ... @@ -95,7 +95,8 @@ class QPDF
95 95  
96 96 // Parse a PDF file loaded into a memory buffer. This works exactly like processFile except
97 97 // that the PDF file is in memory instead of on disk. The description appears in any warning or
98   - // error message in place of the file name.
  98 + // error message in place of the file name. The buffer is owned by the caller and must remain
  99 + // valid for the lifetime of the QPDF object.
99 100 QPDF_DLL
100 101 void processMemoryFile(
101 102 char const* description, char const* buf, size_t length, char const* password = nullptr);
... ...
include/qpdf/QPDFObjectHandle.hh
... ... @@ -1351,7 +1351,7 @@ class QPDFObjectHandle: public qpdf::BaseHandle
1351 1351 void setParsedOffset(qpdf_offset_t offset);
1352 1352 void parseContentStream_internal(std::string const& description, ParserCallbacks* callbacks);
1353 1353 static void parseContentStream_data(
1354   - std::shared_ptr<Buffer>,
  1354 + std::string_view stream_data,
1355 1355 std::string const& description,
1356 1356 ParserCallbacks* callbacks,
1357 1357 QPDF* context);
... ...
libqpdf/BufferInputSource.cc
1 1 #include <qpdf/BufferInputSource.hh>
  2 +#include <qpdf/InputSource_private.hh>
2 3  
  4 +#include <qpdf/Buffer.hh>
3 5 #include <qpdf/QIntC.hh>
  6 +
4 7 #include <algorithm>
5 8 #include <cstring>
6 9 #include <sstream>
7 10  
  11 +using namespace qpdf;
  12 +
  13 +#ifndef QPDF_FUTURE
  14 +
8 15 BufferInputSource::BufferInputSource(std::string const& description, Buffer* buf, bool own_memory) :
9 16 own_memory(own_memory),
10 17 description(description),
... ... @@ -139,3 +146,166 @@ BufferInputSource::unreadCh(char ch)
139 146 --cur_offset;
140 147 }
141 148 }
  149 +
  150 +#else
  151 +
  152 +class BufferInputSource::Members
  153 +{
  154 + public:
  155 + Members(std::string const& description, Buffer* buf, bool own_memory) :
  156 + buf(own_memory ? buf : nullptr),
  157 + is(description,
  158 + buf && buf->getSize() > 0
  159 + ? std::string_view(reinterpret_cast<const char*>(buf->getBuffer()), buf->getSize())
  160 + : std::string_view())
  161 + {
  162 + }
  163 +
  164 + Members(std::string const& description, std::string const& str) :
  165 + content(str),
  166 + is(description, content)
  167 + {
  168 + }
  169 +
  170 + ~Members() = default;
  171 +
  172 + std::unique_ptr<Buffer> buf{nullptr};
  173 + std::string content;
  174 + is::OffsetBuffer is;
  175 +};
  176 +
  177 +BufferInputSource::BufferInputSource(std::string const& description, Buffer* buf, bool own_memory) :
  178 + m(std::make_unique<Members>(description, buf, own_memory))
  179 +{
  180 +}
  181 +
  182 +BufferInputSource::BufferInputSource(std::string const& description, std::string const& contents) :
  183 + m(std::make_unique<Members>(description, contents))
  184 +{
  185 +}
  186 +BufferInputSource::~BufferInputSource() = default;
  187 +
  188 +qpdf_offset_t
  189 +BufferInputSource::findAndSkipNextEOL()
  190 +{
  191 + auto result = m->is.findAndSkipNextEOL();
  192 + last_offset = m->is.getLastOffset();
  193 + return result;
  194 +}
  195 +std::string const&
  196 +BufferInputSource::getName() const
  197 +{
  198 + return m->is.getName();
  199 +}
  200 +qpdf_offset_t
  201 +BufferInputSource::tell()
  202 +{
  203 + return m->is.tell();
  204 +}
  205 +void
  206 +BufferInputSource::seek(qpdf_offset_t offset, int whence)
  207 +{
  208 + m->is.seek(offset, whence);
  209 +}
  210 +void
  211 +BufferInputSource::rewind()
  212 +{
  213 + m->is.rewind();
  214 +}
  215 +size_t
  216 +BufferInputSource::read(char* buffer, size_t length)
  217 +{
  218 + auto result = m->is.read(buffer, length);
  219 + last_offset = m->is.getLastOffset();
  220 + return result;
  221 +}
  222 +void
  223 +BufferInputSource::unreadCh(char ch)
  224 +{
  225 + m->is.unreadCh(ch);
  226 +}
  227 +
  228 +#endif // QPDF_FUTURE
  229 +
  230 +qpdf_offset_t
  231 +is::OffsetBuffer::findAndSkipNextEOL()
  232 +{
  233 + if (pos < 0) {
  234 + throw std::logic_error("INTERNAL ERROR: is::OffsetBuffer offset < 0");
  235 + }
  236 + auto end_pos = static_cast<qpdf_offset_t>(view_.size());
  237 + if (pos >= end_pos) {
  238 + last_offset = end_pos + global_offset;
  239 + pos = end_pos;
  240 + return end_pos + global_offset;
  241 + }
  242 +
  243 + qpdf_offset_t result = 0;
  244 + auto buffer = view_.begin();
  245 + auto end = view_.end();
  246 + auto p = buffer + static_cast<std::ptrdiff_t>(pos);
  247 +
  248 + while (p < end && !(*p == '\r' || *p == '\n')) {
  249 + ++p;
  250 + }
  251 + if (p < end) {
  252 + result = p - buffer;
  253 + pos = result + 1;
  254 + ++p;
  255 + while (pos < end_pos && (*p == '\r' || *p == '\n')) {
  256 + ++p;
  257 + ++pos;
  258 + }
  259 + } else {
  260 + pos = end_pos;
  261 + result = end_pos;
  262 + }
  263 + return result + global_offset;
  264 +}
  265 +
  266 +void
  267 +is::OffsetBuffer::seek(qpdf_offset_t offset, int whence)
  268 +{
  269 + switch (whence) {
  270 + case SEEK_SET:
  271 + pos = offset - global_offset;
  272 + break;
  273 +
  274 + case SEEK_END:
  275 + QIntC::range_check(static_cast<qpdf_offset_t>(view_.size()), offset);
  276 + pos = static_cast<qpdf_offset_t>(view_.size()) + offset;
  277 + break;
  278 +
  279 + case SEEK_CUR:
  280 + QIntC::range_check(pos, offset);
  281 + pos += offset;
  282 + break;
  283 +
  284 + default:
  285 + throw std::logic_error("INTERNAL ERROR: invalid argument to BufferInputSource::seek");
  286 + break;
  287 + }
  288 +
  289 + if (pos < 0) {
  290 + throw std::runtime_error(description + ": seek before beginning of buffer");
  291 + }
  292 +}
  293 +
  294 +size_t
  295 +is::OffsetBuffer::read(char* buffer, size_t length)
  296 +{
  297 + if (pos < 0) {
  298 + throw std::logic_error("INTERNAL ERROR: is::OffsetBuffer offset < 0");
  299 + }
  300 + auto end_pos = static_cast<qpdf_offset_t>(view_.size());
  301 + if (pos >= end_pos) {
  302 + last_offset = end_pos + global_offset;
  303 + return 0;
  304 + }
  305 +
  306 + last_offset = pos + global_offset;
  307 + size_t len = std::min(QIntC::to_size(end_pos - pos), length);
  308 + memcpy(buffer, view_.data() + pos, len);
  309 + pos += QIntC::to_offset(len);
  310 + return len;
  311 +}
... ...
libqpdf/JSON.cc
... ... @@ -2,7 +2,7 @@
2 2  
3 3 #include <qpdf/JSON_writer.hh>
4 4  
5   -#include <qpdf/BufferInputSource.hh>
  5 +#include <qpdf/InputSource_private.hh>
6 6 #include <qpdf/Pl_Base64.hh>
7 7 #include <qpdf/Pl_Concatenate.hh>
8 8 #include <qpdf/Pl_String.hh>
... ... @@ -1348,7 +1348,7 @@ JSON::parse(InputSource&amp; is, Reactor* reactor)
1348 1348 JSON
1349 1349 JSON::parse(std::string const& s)
1350 1350 {
1351   - BufferInputSource bis("json input", s);
  1351 + is::OffsetBuffer bis("json input", s);
1352 1352 JSONParser jp(bis, nullptr);
1353 1353 return jp.parse();
1354 1354 }
... ...
libqpdf/Pl_QPDFTokenizer.cc
1 1 #include <qpdf/Pl_QPDFTokenizer.hh>
2 2  
3   -#include <qpdf/BufferInputSource.hh>
  3 +#include <qpdf/InputSource_private.hh>
  4 +#include <qpdf/Pipeline_private.hh>
4 5 #include <qpdf/QTC.hh>
  6 +
5 7 #include <stdexcept>
6 8  
  9 +using namespace qpdf;
  10 +
7 11 class Pl_QPDFTokenizer::Members
8 12 {
9 13 public:
... ... @@ -13,7 +17,8 @@ class Pl_QPDFTokenizer::Members
13 17  
14 18 QPDFObjectHandle::TokenFilter* filter{nullptr};
15 19 QPDFTokenizer tokenizer;
16   - Pl_Buffer buf{"tokenizer buffer"};
  20 + std::string buffer;
  21 + pl::String buf{"pl_tokenizer", nullptr, buffer};
17 22 };
18 23  
19 24 Pl_QPDFTokenizer::Pl_QPDFTokenizer(
... ... @@ -39,8 +44,7 @@ Pl_QPDFTokenizer::write(unsigned char const* data, size_t len)
39 44 void
40 45 Pl_QPDFTokenizer::finish()
41 46 {
42   - m->buf.finish();
43   - auto input = BufferInputSource("tokenizer data", m->buf.getBuffer(), true);
  47 + auto input = is::OffsetBuffer("tokenizer data", m->buffer);
44 48 std::string empty;
45 49 while (true) {
46 50 auto token = m->tokenizer.readToken(input, empty, true);
... ...
libqpdf/QPDF.cc
... ... @@ -11,7 +11,6 @@
11 11 #include <sstream>
12 12 #include <vector>
13 13  
14   -#include <qpdf/BufferInputSource.hh>
15 14 #include <qpdf/FileInputSource.hh>
16 15 #include <qpdf/InputSource_private.hh>
17 16 #include <qpdf/OffsetInputSource.hh>
... ... @@ -259,12 +258,8 @@ void
259 258 QPDF::processMemoryFile(
260 259 char const* description, char const* buf, size_t length, char const* password)
261 260 {
262   - processInputSource(
263   - std::shared_ptr<InputSource>(
264   - // line-break
265   - new BufferInputSource(
266   - description, new Buffer(QUtil::unsigned_char_pointer(buf), length), true)),
267   - password);
  261 + auto is = std::make_shared<is::OffsetBuffer>(description, std::string_view{buf, length});
  262 + processInputSource(is, password);
268 263 }
269 264  
270 265 void
... ...
libqpdf/QPDFObjectHandle.cc
... ... @@ -2,7 +2,6 @@
2 2  
3 3 #include <qpdf/QPDFObjectHandle_private.hh>
4 4  
5   -#include <qpdf/InputSource_private.hh>
6 5 #include <qpdf/JSON_writer.hh>
7 6 #include <qpdf/Pipeline_private.hh>
8 7 #include <qpdf/Pl_Buffer.hh>
... ... @@ -1452,10 +1451,7 @@ QPDFObjectHandle
1452 1451 QPDFObjectHandle::parse(
1453 1452 QPDF* context, std::string const& object_str, std::string const& object_description)
1454 1453 {
1455   - // BufferInputSource does not modify the input, but Buffer either requires a string& or copies
1456   - // the string.
1457   - Buffer buf(const_cast<std::string&>(object_str));
1458   - auto input = BufferInputSource("parsed object", &buf);
  1454 + auto input = is::OffsetBuffer("parsed object", object_str);
1459 1455 auto result = QPDFParser::parse(input, object_description, context);
1460 1456 size_t offset = QIntC::to_size(input.tell());
1461 1457 while (offset < object_str.length()) {
... ... @@ -1549,11 +1545,11 @@ void
1549 1545 QPDFObjectHandle::parseContentStream_internal(
1550 1546 std::string const& description, ParserCallbacks* callbacks)
1551 1547 {
1552   - Pl_Buffer buf("concatenated stream data buffer");
  1548 + std::string stream_data;
  1549 + pl::String buf(stream_data);
1553 1550 std::string all_description;
1554 1551 pipeContentStreams(&buf, description, all_description);
1555   - auto stream_data = buf.getBufferSharedPointer();
1556   - callbacks->contentSize(stream_data->getSize());
  1552 + callbacks->contentSize(stream_data.size());
1557 1553 try {
1558 1554 parseContentStream_data(stream_data, all_description, callbacks, getOwningQPDF());
1559 1555 } catch (TerminateParsing&) {
... ... @@ -1564,13 +1560,13 @@ QPDFObjectHandle::parseContentStream_internal(
1564 1560  
1565 1561 void
1566 1562 QPDFObjectHandle::parseContentStream_data(
1567   - std::shared_ptr<Buffer> stream_data,
  1563 + std::string_view stream_data,
1568 1564 std::string const& description,
1569 1565 ParserCallbacks* callbacks,
1570 1566 QPDF* context)
1571 1567 {
1572   - size_t stream_length = stream_data->getSize();
1573   - auto input = BufferInputSource(description, stream_data.get());
  1568 + size_t stream_length = stream_data.size();
  1569 + auto input = is::OffsetBuffer(description, stream_data);
1574 1570 Tokenizer tokenizer;
1575 1571 tokenizer.allowEOF();
1576 1572 auto sp_description = QPDFParser::make_description(description, "content");
... ...
libqpdf/QPDFParser.cc
1 1 #include <qpdf/QPDFParser.hh>
2 2  
3   -#include <qpdf/BufferInputSource.hh>
4 3 #include <qpdf/QPDF.hh>
5 4 #include <qpdf/QPDFObjGen.hh>
6 5 #include <qpdf/QPDFObjectHandle.hh>
... ...
libqpdf/QPDF_Stream.cc
... ... @@ -3,6 +3,7 @@
3 3 #include <qpdf/ContentNormalizer.hh>
4 4 #include <qpdf/JSON_writer.hh>
5 5 #include <qpdf/Pipeline.hh>
  6 +#include <qpdf/Pipeline_private.hh>
6 7 #include <qpdf/Pl_Base64.hh>
7 8 #include <qpdf/Pl_Buffer.hh>
8 9 #include <qpdf/Pl_Count.hh>
... ... @@ -319,10 +320,11 @@ qpdf::Stream::setDictDescription()
319 320 }
320 321 }
321 322  
322   -std::shared_ptr<Buffer>
  323 +std::string
323 324 Stream::getStreamData(qpdf_stream_decode_level_e decode_level)
324 325 {
325   - Pl_Buffer buf("stream data buffer");
  326 + std::string result;
  327 + pl::String buf(result);
326 328 bool filtered;
327 329 pipeStreamData(&buf, &filtered, 0, decode_level, false, false);
328 330 if (!filtered) {
... ... @@ -334,13 +336,14 @@ Stream::getStreamData(qpdf_stream_decode_level_e decode_level)
334 336 "getStreamData called on unfilterable stream");
335 337 }
336 338 QTC::TC("qpdf", "QPDF_Stream getStreamData");
337   - return buf.getBufferSharedPointer();
  339 + return result;
338 340 }
339 341  
340   -std::shared_ptr<Buffer>
  342 +std::string
341 343 Stream::getRawStreamData()
342 344 {
343   - Pl_Buffer buf("stream data buffer");
  345 + std::string result;
  346 + pl::String buf(result);
344 347 if (!pipeStreamData(&buf, nullptr, 0, qpdf_dl_none, false, false)) {
345 348 throw QPDFExc(
346 349 qpdf_e_unsupported,
... ... @@ -350,7 +353,7 @@ Stream::getRawStreamData()
350 353 "error getting raw stream data");
351 354 }
352 355 QTC::TC("qpdf", "QPDF_Stream getRawStreamData");
353   - return buf.getBufferSharedPointer();
  356 + return result;
354 357 }
355 358  
356 359 bool
... ... @@ -683,13 +686,13 @@ QPDFObjectHandle::isRootMetadata() const
683 686 std::shared_ptr<Buffer>
684 687 QPDFObjectHandle::getStreamData(qpdf_stream_decode_level_e level)
685 688 {
686   - return as_stream(error).getStreamData(level);
  689 + return std::make_shared<Buffer>(as_stream(error).getStreamData(level));
687 690 }
688 691  
689 692 std::shared_ptr<Buffer>
690 693 QPDFObjectHandle::getRawStreamData()
691 694 {
692   - return as_stream(error).getRawStreamData();
  695 + return std::make_shared<Buffer>(as_stream(error).getRawStreamData());
693 696 }
694 697  
695 698 bool
... ...
libqpdf/QPDF_objects.cc
... ... @@ -2,19 +2,7 @@
2 2  
3 3 #include <qpdf/QPDF_private.hh>
4 4  
5   -#include <array>
6   -#include <atomic>
7   -#include <cstring>
8   -#include <limits>
9   -#include <map>
10   -#include <regex>
11   -#include <sstream>
12   -#include <vector>
13   -
14   -#include <qpdf/BufferInputSource.hh>
15   -#include <qpdf/FileInputSource.hh>
16 5 #include <qpdf/InputSource_private.hh>
17   -#include <qpdf/OffsetInputSource.hh>
18 6 #include <qpdf/Pipeline.hh>
19 7 #include <qpdf/QPDFExc.hh>
20 8 #include <qpdf/QPDFLogger.hh>
... ... @@ -25,6 +13,13 @@
25 13 #include <qpdf/QUtil.hh>
26 14 #include <qpdf/Util.hh>
27 15  
  16 +#include <array>
  17 +#include <atomic>
  18 +#include <cstring>
  19 +#include <limits>
  20 +#include <map>
  21 +#include <vector>
  22 +
28 23 using namespace qpdf;
29 24 using namespace std::literals;
30 25  
... ... @@ -1676,13 +1671,13 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
1676 1671 // id, offset, size
1677 1672 std::vector<std::tuple<int, qpdf_offset_t, size_t>> offsets;
1678 1673  
1679   - auto bp = obj_stream.getStreamData(qpdf_dl_specialized);
  1674 + auto stream_data = obj_stream.getStreamData(qpdf_dl_specialized);
1680 1675  
1681   - BufferInputSource input("", bp.get());
  1676 + is::OffsetBuffer input("", stream_data);
1682 1677  
1683   - const auto b_size = bp->getSize();
  1678 + const auto b_size = stream_data.size();
1684 1679 const auto end_offset = static_cast<qpdf_offset_t>(b_size);
1685   - auto b_start = bp->getBuffer();
  1680 + auto b_start = stream_data.data();
1686 1681  
1687 1682 if (first >= end_offset) {
1688 1683 throw damagedPDF(
... ... @@ -1763,8 +1758,7 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
1763 1758 auto entry = m->xref_table.find(og);
1764 1759 if (entry != m->xref_table.end() && entry->second.getType() == 2 &&
1765 1760 entry->second.getObjStreamNumber() == obj_stream_number) {
1766   - Buffer obj_buffer{b_start + obj_offset, obj_size};
1767   - is::OffsetBuffer in("", &obj_buffer, obj_offset);
  1761 + is::OffsetBuffer in("", {b_start + obj_offset, obj_size}, obj_offset);
1768 1762 auto oh = readObjectInStream(in, obj_stream_number, obj_id);
1769 1763 updateCache(og, oh.getObj(), end_before_space, end_after_space);
1770 1764 } else {
... ...
libqpdf/qpdf/InputSource_private.hh
1 1 #ifndef QPDF_INPUTSOURCE_PRIVATE_HH
2 2 #define QPDF_INPUTSOURCE_PRIVATE_HH
3 3  
4   -#include <qpdf/BufferInputSource.hh>
  4 +#include <qpdf/Buffer.hh>
5 5 #include <qpdf/InputSource.hh>
6 6  
7 7 #include <limits>
... ... @@ -13,8 +13,12 @@ namespace qpdf::is
13 13 class OffsetBuffer final: public InputSource
14 14 {
15 15 public:
16   - OffsetBuffer(std::string const& description, Buffer* buf, qpdf_offset_t global_offset) :
17   - proxied(description, buf),
  16 + OffsetBuffer(
  17 + std::string const& description,
  18 + std::string_view view,
  19 + qpdf_offset_t global_offset = 0) :
  20 + description(description),
  21 + view_(view),
18 22 global_offset(global_offset)
19 23 {
20 24 if (global_offset < 0) {
... ... @@ -23,58 +27,55 @@ namespace qpdf::is
23 27 last_offset = global_offset;
24 28 }
25 29  
26   - ~OffsetBuffer() final = default;
27   -
28   - qpdf_offset_t
29   - findAndSkipNextEOL() final
  30 + OffsetBuffer(std::string const& description, Buffer* buf, qpdf_offset_t global_offset = 0) :
  31 + OffsetBuffer(
  32 + description,
  33 + {buf && buf->getSize()
  34 + ? std::string_view(
  35 + reinterpret_cast<const char*>(buf->getBuffer()), buf->getSize())
  36 + : std::string_view()},
  37 + global_offset)
30 38 {
31   - return proxied.findAndSkipNextEOL() + global_offset;
32 39 }
33 40  
  41 + ~OffsetBuffer() final = default;
  42 +
  43 + qpdf_offset_t findAndSkipNextEOL() final;
  44 +
34 45 std::string const&
35 46 getName() const final
36 47 {
37   - return proxied.getName();
  48 + return description;
38 49 }
39 50  
40 51 qpdf_offset_t
41 52 tell() final
42 53 {
43   - return proxied.tell() + global_offset;
  54 + return pos + global_offset;
44 55 }
45 56  
46   - void
47   - seek(qpdf_offset_t offset, int whence) final
48   - {
49   - if (whence == SEEK_SET) {
50   - proxied.seek(offset - global_offset, whence);
51   - } else {
52   - proxied.seek(offset, whence);
53   - }
54   - }
  57 + void seek(qpdf_offset_t offset, int whence) final;
55 58  
56 59 void
57 60 rewind() final
58 61 {
59   - seek(0, SEEK_SET);
  62 + pos = 0;
60 63 }
61 64  
62   - size_t
63   - read(char* buffer, size_t length) final
64   - {
65   - size_t result = proxied.read(buffer, length);
66   - setLastOffset(proxied.getLastOffset() + global_offset);
67   - return result;
68   - }
  65 + size_t read(char* buffer, size_t length) final;
69 66  
70 67 void
71 68 unreadCh(char ch) final
72 69 {
73   - proxied.unreadCh(ch);
  70 + if (pos > 0) {
  71 + --pos;
  72 + }
74 73 }
75 74  
76 75 private:
77   - BufferInputSource proxied;
  76 + std::string description;
  77 + qpdf_offset_t pos{0};
  78 + std::string_view view_;
78 79 qpdf_offset_t global_offset;
79 80 };
80 81  
... ...
libqpdf/qpdf/QPDFObjectHandle_private.hh
... ... @@ -254,8 +254,8 @@ namespace qpdf
254 254 qpdf_stream_decode_level_e decode_level,
255 255 bool suppress_warnings,
256 256 bool will_retry);
257   - std::shared_ptr<Buffer> getStreamData(qpdf_stream_decode_level_e level);
258   - std::shared_ptr<Buffer> getRawStreamData();
  257 + std::string getStreamData(qpdf_stream_decode_level_e level);
  258 + std::string getRawStreamData();
259 259 void replaceStreamData(
260 260 std::shared_ptr<Buffer> data,
261 261 QPDFObjectHandle const& filter,
... ...