Coverage Report

Created: 2024-09-08 06:06

/src/qpdf/libqpdf/Pl_TIFFPredictor.cc
Line
Count
Source (jump to first uncovered line)
1
#include <qpdf/Pl_TIFFPredictor.hh>
2
3
#include <qpdf/BitStream.hh>
4
#include <qpdf/BitWriter.hh>
5
#include <qpdf/QTC.hh>
6
7
#include <climits>
8
#include <stdexcept>
9
10
namespace
11
{
12
    unsigned long long memory_limit{0};
13
} // namespace
14
15
Pl_TIFFPredictor::Pl_TIFFPredictor(
16
    char const* identifier,
17
    Pipeline* next,
18
    action_e action,
19
    unsigned int columns,
20
    unsigned int samples_per_pixel,
21
    unsigned int bits_per_sample) :
22
    Pipeline(identifier, next),
23
    action(action),
24
    columns(columns),
25
    samples_per_pixel(samples_per_pixel),
26
    bits_per_sample(bits_per_sample),
27
    p_next(getNext())
28
1.08k
{
29
1.08k
    if (samples_per_pixel < 1) {
30
0
        throw std::runtime_error("TIFFPredictor created with invalid samples_per_pixel");
31
0
    }
32
1.08k
    if ((bits_per_sample < 1) || (bits_per_sample > (8 * (sizeof(unsigned long long))))) {
33
0
        throw std::runtime_error("TIFFPredictor created with invalid bits_per_sample");
34
0
    }
35
1.08k
    unsigned long long bpr = ((columns * bits_per_sample * samples_per_pixel) + 7) / 8;
36
1.08k
    if ((bpr == 0) || (bpr > (UINT_MAX - 1))) {
37
0
        throw std::runtime_error("TIFFPredictor created with invalid columns value");
38
0
    }
39
1.08k
    if (memory_limit > 0 && bpr > (memory_limit / 2U)) {
40
30
        throw std::runtime_error("TIFFPredictor memory limit exceeded");
41
30
    }
42
1.05k
    this->bytes_per_row = bpr & UINT_MAX;
43
1.05k
}
44
45
void
46
Pl_TIFFPredictor::setMemoryLimit(unsigned long long limit)
47
80.5k
{
48
80.5k
    memory_limit = limit;
49
80.5k
}
50
51
void
52
Pl_TIFFPredictor::write(unsigned char const* data, size_t len)
53
3.66k
{
54
3.66k
    auto end = data + len;
55
3.66k
    auto row_end = data + (bytes_per_row - cur_row.size());
56
1.10M
    while (row_end <= end) {
57
        // finish off current row
58
1.10M
        cur_row.insert(cur_row.end(), data, row_end);
59
1.10M
        data = row_end;
60
1.10M
        row_end += bytes_per_row;
61
62
1.10M
        processRow();
63
64
        // Prepare for next row
65
1.10M
        cur_row.clear();
66
1.10M
    }
67
68
3.66k
    cur_row.insert(cur_row.end(), data, end);
69
3.66k
}
70
71
void
72
Pl_TIFFPredictor::processRow()
73
1.10M
{
74
1.10M
    QTC::TC("libtests", "Pl_TIFFPredictor processRow", (action == a_decode ? 0 : 1));
75
1.10M
    previous.assign(samples_per_pixel, 0);
76
1.10M
    if (bits_per_sample != 8) {
77
322k
        BitWriter bw(p_next);
78
322k
        BitStream in(cur_row.data(), cur_row.size());
79
5.47M
        for (unsigned int col = 0; col < this->columns; ++col) {
80
10.3M
            for (auto& prev: previous) {
81
10.3M
                long long sample = in.getBitsSigned(this->bits_per_sample);
82
10.3M
                long long new_sample = sample;
83
10.3M
                if (action == a_encode) {
84
0
                    new_sample -= prev;
85
0
                    prev = sample;
86
10.3M
                } else {
87
10.3M
                    new_sample += prev;
88
10.3M
                    prev = new_sample;
89
10.3M
                }
90
10.3M
                bw.writeBitsSigned(new_sample, this->bits_per_sample);
91
10.3M
            }
92
5.15M
        }
93
322k
        bw.flush();
94
779k
    } else {
95
779k
        out.clear();
96
779k
        auto next = cur_row.begin();
97
779k
        auto cr_end = cur_row.end();
98
779k
        auto pr_end = previous.end();
99
100
10.0M
        while (next != cr_end) {
101
18.5M
            for (auto prev = previous.begin(); prev != pr_end && next != cr_end; ++prev, ++next) {
102
9.26M
                long long sample = *next;
103
9.26M
                long long new_sample = sample;
104
9.26M
                if (action == a_encode) {
105
0
                    new_sample -= *prev;
106
0
                    *prev = sample;
107
9.26M
                } else {
108
9.26M
                    new_sample += *prev;
109
9.26M
                    *prev = new_sample;
110
9.26M
                }
111
9.26M
                out.push_back(static_cast<unsigned char>(255U & new_sample));
112
9.26M
            }
113
9.26M
        }
114
779k
        p_next->write(out.data(), out.size());
115
779k
    }
116
1.10M
}
117
118
void
119
Pl_TIFFPredictor::finish()
120
1.05k
{
121
1.05k
    if (!cur_row.empty()) {
122
        // write partial row
123
720
        cur_row.insert(cur_row.end(), bytes_per_row - cur_row.size(), 0);
124
720
        processRow();
125
720
    }
126
1.05k
    cur_row.clear();
127
1.05k
    p_next->finish();
128
1.05k
}