Coverage Report

Created: 2026-06-16 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qpdf/libqpdf/Pl_TIFFPredictor.cc
Line
Count
Source
1
#include <qpdf/Pl_TIFFPredictor.hh>
2
3
#include <qpdf/BitStream.hh>
4
#include <qpdf/BitWriter.hh>
5
#include <qpdf/QTC.hh>
6
#include <qpdf/Util.hh>
7
#include <qpdf/global_private.hh>
8
9
#include <climits>
10
#include <stdexcept>
11
12
using namespace qpdf;
13
14
namespace
15
{
16
    unsigned long long const& memory_limit = global::Limits::tiff_max_memory();
17
} // namespace
18
19
Pl_TIFFPredictor::Pl_TIFFPredictor(
20
    char const* identifier,
21
    Pipeline* next,
22
    action_e action,
23
    uint32_t columns,
24
    uint32_t samples_per_pixel,
25
    uint32_t bits_per_sample) :
26
9.66k
    Pipeline(identifier, next),
27
9.66k
    action(action),
28
9.66k
    columns(columns),
29
9.66k
    samples_per_pixel(samples_per_pixel),
30
9.66k
    bits_per_sample(bits_per_sample)
31
9.66k
{
32
9.66k
    util::assertion(next, "Attempt to create Pl_TIFFPredictor with nullptr as next");
33
9.66k
    util::no_ci_rt_error_if(
34
9.66k
        samples_per_pixel < 1, "TIFFPredictor created with invalid samples_per_pixel");
35
9.66k
    util::no_ci_rt_error_if(
36
9.66k
        bits_per_sample < 1 || bits_per_sample > (8 * (sizeof(unsigned long long))),
37
9.66k
        "TIFFPredictor created with invalid bits_per_sample");
38
9.66k
    auto bits_per_pixel = 1ULL * bits_per_sample * samples_per_pixel;
39
9.66k
    util::no_ci_rt_error_if(
40
9.66k
        !util::fits<uint32_t>(bits_per_pixel + 7),
41
9.66k
        "TIFFPredictor created with bits_per_sample and samples_per_pixel values that cause "
42
9.66k
        "overflow");
43
9.66k
    auto bpr = (columns * bits_per_pixel + 7) / 8;
44
9.66k
    util::no_ci_rt_error_if(
45
9.66k
        bpr == 0 || !util::fits<uint32_t>(bpr), "TIFFPredictor created with invalid columns value");
46
9.66k
    util::no_ci_rt_error_if(
47
9.66k
        memory_limit > 0 && bpr > (memory_limit / 2ULL), "TIFFPredictor memory limit exceeded");
48
9.66k
    bytes_per_row = static_cast<uint32_t>(bpr);
49
9.66k
}
50
51
void
52
Pl_TIFFPredictor::setMemoryLimit(unsigned long long limit)
53
0
{
54
0
    global::Limits::tiff_max_memory(limit);
55
0
}
56
57
void
58
Pl_TIFFPredictor::write(unsigned char const* data, size_t len)
59
9.43M
{
60
9.43M
    auto end = data + len;
61
9.43M
    auto row_end = data + (bytes_per_row - cur_row.size());
62
14.3M
    while (row_end <= end) {
63
        // finish off current row
64
4.95M
        cur_row.insert(cur_row.end(), data, row_end);
65
4.95M
        data = row_end;
66
4.95M
        row_end += bytes_per_row;
67
68
4.95M
        processRow();
69
70
        // Prepare for next row
71
4.95M
        cur_row.clear();
72
4.95M
    }
73
74
9.43M
    cur_row.insert(cur_row.end(), data, end);
75
9.43M
}
76
77
void
78
Pl_TIFFPredictor::processRow()
79
4.95M
{
80
4.95M
    QTC::TC("libtests", "Pl_TIFFPredictor processRow", (action == a_decode ? 0 : 1));
81
4.95M
    previous.assign(samples_per_pixel, 0);
82
4.95M
    if (bits_per_sample != 8) {
83
61.5k
        BitWriter bw(next());
84
61.5k
        BitStream in(cur_row.data(), cur_row.size());
85
15.9M
        for (uint32_t col = 0; col < this->columns; ++col) {
86
16.8M
            for (auto& prev: previous) {
87
16.8M
                long long sample = in.getBitsSigned(this->bits_per_sample);
88
16.8M
                long long new_sample = sample;
89
16.8M
                if (action == a_encode) {
90
0
                    new_sample -= prev;
91
0
                    prev = sample;
92
16.8M
                } else {
93
16.8M
                    new_sample += prev;
94
16.8M
                    prev = new_sample;
95
16.8M
                }
96
16.8M
                bw.writeBitsSigned(new_sample, this->bits_per_sample);
97
16.8M
            }
98
15.9M
        }
99
61.5k
        bw.flush();
100
4.89M
    } else {
101
4.89M
        out.clear();
102
4.89M
        auto next_it = cur_row.begin();
103
4.89M
        auto cr_end = cur_row.end();
104
4.89M
        auto pr_end = previous.end();
105
106
39.2M
        while (next_it != cr_end) {
107
88.0M
            for (auto prev = previous.begin(); prev != pr_end && next_it != cr_end;
108
53.6M
                 ++prev, ++next_it) {
109
53.6M
                long long sample = *next_it;
110
53.6M
                long long new_sample = sample;
111
53.6M
                if (action == a_encode) {
112
0
                    new_sample -= *prev;
113
0
                    *prev = sample;
114
53.6M
                } else {
115
53.6M
                    new_sample += *prev;
116
53.6M
                    *prev = new_sample;
117
53.6M
                }
118
53.6M
                out.push_back(static_cast<unsigned char>(255U & new_sample));
119
53.6M
            }
120
34.3M
        }
121
4.89M
        next()->write(out.data(), out.size());
122
4.89M
    }
123
4.95M
}
124
125
void
126
Pl_TIFFPredictor::finish()
127
8.75k
{
128
8.75k
    if (!cur_row.empty()) {
129
        // write partial row
130
5.42k
        cur_row.insert(cur_row.end(), bytes_per_row - cur_row.size(), 0);
131
5.42k
        processRow();
132
5.42k
    }
133
8.75k
    cur_row.clear();
134
8.75k
    next()->finish();
135
8.75k
}