Coverage Report

Created: 2025-07-01 06:10

/src/qpdf/libqpdf/Pl_QPDFTokenizer.cc
Line
Count
Source (jump to first uncovered line)
1
#include <qpdf/Pl_QPDFTokenizer.hh>
2
3
#include <qpdf/BufferInputSource.hh>
4
#include <qpdf/QTC.hh>
5
#include <stdexcept>
6
7
class Pl_QPDFTokenizer::Members
8
{
9
  public:
10
0
    Members() = default;
11
    Members(Members const&) = delete;
12
0
    ~Members() = default;
13
14
    QPDFObjectHandle::TokenFilter* filter{nullptr};
15
    QPDFTokenizer tokenizer;
16
    Pl_Buffer buf{"tokenizer buffer"};
17
};
18
19
Pl_QPDFTokenizer::Pl_QPDFTokenizer(
20
    char const* identifier, QPDFObjectHandle::TokenFilter* filter, Pipeline* next) :
21
0
    Pipeline(identifier, next),
22
0
    m(std::make_unique<Members>())
23
0
{
24
0
    m->filter = filter;
25
0
    QPDFObjectHandle::TokenFilter::PipelineAccessor::setPipeline(m->filter, next);
26
0
    m->tokenizer.allowEOF();
27
0
    m->tokenizer.includeIgnorable();
28
0
}
29
30
// Must be explicit and not inline -- see QPDF_DLL_CLASS in README-maintainer
31
0
Pl_QPDFTokenizer::~Pl_QPDFTokenizer() = default;
32
33
void
34
Pl_QPDFTokenizer::write(unsigned char const* data, size_t len)
35
0
{
36
0
    m->buf.write(data, len);
37
0
}
38
39
void
40
Pl_QPDFTokenizer::finish()
41
0
{
42
0
    m->buf.finish();
43
0
    auto input = BufferInputSource("tokenizer data", m->buf.getBuffer(), true);
44
0
    std::string empty;
45
0
    while (true) {
46
0
        auto token = m->tokenizer.readToken(input, empty, true);
47
0
        m->filter->handleToken(token);
48
0
        if (token.getType() == QPDFTokenizer::tt_eof) {
49
0
            break;
50
0
        } else if (token.isWord("ID")) {
51
            // Read the space after the ID.
52
0
            char ch = ' ';
53
0
            input.read(&ch, 1);
54
0
            m->filter->handleToken(
55
                // line-break
56
0
                QPDFTokenizer::Token(QPDFTokenizer::tt_space, std::string(1, ch)));
57
0
            QTC::TC("qpdf", "Pl_QPDFTokenizer found ID");
58
0
            m->tokenizer.expectInlineImage(input);
59
0
        }
60
0
    }
61
0
    m->filter->handleEOF();
62
0
    QPDFObjectHandle::TokenFilter::PipelineAccessor::setPipeline(m->filter, nullptr);
63
0
    if (next()) {
64
0
        next()->finish();
65
0
    }
66
0
}