Coverage Report

Created: 2025-07-01 06:10

/src/qpdf/libqpdf/Pl_Base64.cc
Line
Count
Source (jump to first uncovered line)
1
#include <qpdf/Pl_Base64.hh>
2
3
#include <qpdf/QIntC.hh>
4
#include <qpdf/QUtil.hh>
5
#include <qpdf/Util.hh>
6
7
#include <cstring>
8
#include <stdexcept>
9
10
using namespace qpdf;
11
12
static char
13
to_c(unsigned int ch)
14
0
{
15
0
    return static_cast<char>(ch);
16
0
}
17
18
static unsigned char
19
to_uc(int ch)
20
0
{
21
0
    return static_cast<unsigned char>(ch);
22
0
}
23
24
static int
25
to_i(int i)
26
0
{
27
0
    return static_cast<int>(i);
28
0
}
29
30
Pl_Base64::Pl_Base64(char const* identifier, Pipeline* next, action_e action) :
31
0
    Pipeline(identifier, next),
32
0
    action(action)
33
0
{
34
0
    if (!next) {
35
0
        throw std::logic_error("Attempt to create Pl_Base64 with nullptr as next");
36
0
    }
37
0
}
38
39
void
40
Pl_Base64::write(unsigned char const* data, size_t len)
41
0
{
42
0
    if (finished) {
43
0
        throw std::logic_error("Pl_Base64 used after finished");
44
0
    }
45
0
    if (action == a_decode) {
46
0
        decode(data, len);
47
0
    } else {
48
0
        encode(data, len);
49
0
    }
50
0
}
51
52
void
53
Pl_Base64::decode(unsigned char const* data, size_t len)
54
0
{
55
0
    unsigned char const* p = data;
56
0
    while (len > 0) {
57
0
        if (!util::is_space(to_c(*p))) {
58
0
            buf[pos++] = *p;
59
0
            if (pos == 4) {
60
0
                flush();
61
0
            }
62
0
        }
63
0
        ++p;
64
0
        --len;
65
0
    }
66
0
}
67
68
void
69
Pl_Base64::encode(unsigned char const* data, size_t len)
70
0
{
71
0
    unsigned char const* p = data;
72
0
    while (len > 0) {
73
0
        buf[pos++] = *p;
74
0
        if (pos == 3) {
75
0
            flush();
76
0
        }
77
0
        ++p;
78
0
        --len;
79
0
    }
80
0
}
81
82
void
83
Pl_Base64::flush()
84
0
{
85
0
    if (action == a_decode) {
86
0
        flush_decode();
87
0
    } else {
88
0
        flush_encode();
89
0
    }
90
0
    reset();
91
0
}
92
93
void
94
Pl_Base64::flush_decode()
95
0
{
96
0
    if (end_of_data) {
97
0
        throw std::runtime_error(getIdentifier() + ": base64 decode: data follows pad characters");
98
0
    }
99
0
    int pad = 0;
100
0
    int shift = 18;
101
0
    int outval = 0;
102
0
    for (size_t i = 0; i < 4; ++i) {
103
0
        int v = 0;
104
0
        char ch = to_c(buf[i]);
105
0
        if ((ch >= 'A') && (ch <= 'Z')) {
106
0
            v = ch - 'A';
107
0
        } else if ((ch >= 'a') && (ch <= 'z')) {
108
0
            v = ch - 'a' + 26;
109
0
        } else if ((ch >= '0') && (ch <= '9')) {
110
0
            v = ch - '0' + 52;
111
0
        } else if ((ch == '+') || (ch == '-')) {
112
0
            v = 62;
113
0
        } else if ((ch == '/') || (ch == '_')) {
114
0
            v = 63;
115
0
        } else if ((ch == '=') && ((i == 3) || ((i == 2) && (buf[3] == '=')))) {
116
0
            ++pad;
117
0
            end_of_data = true;
118
0
            v = 0;
119
0
        } else {
120
0
            throw std::runtime_error(getIdentifier() + ": base64 decode: invalid input");
121
0
        }
122
0
        outval |= v << shift;
123
0
        shift -= 6;
124
0
    }
125
0
    unsigned char out[3] = {
126
0
        to_uc(outval >> 16),
127
0
        to_uc(0xff & (outval >> 8)),
128
0
        to_uc(0xff & outval),
129
0
    };
130
131
0
    next()->write(out, QIntC::to_size(3 - pad));
132
0
}
133
134
void
135
Pl_Base64::flush_encode()
136
0
{
137
0
    int outval = ((buf[0] << 16) | (buf[1] << 8) | (buf[2]));
138
0
    unsigned char out[4] = {
139
0
        to_uc(outval >> 18),
140
0
        to_uc(0x3f & (outval >> 12)),
141
0
        to_uc(0x3f & (outval >> 6)),
142
0
        to_uc(0x3f & outval),
143
0
    };
144
0
    for (size_t i = 0; i < 4; ++i) {
145
0
        int ch = to_i(out[i]);
146
0
        if (ch < 26) {
147
0
            ch += 'A';
148
0
        } else if (ch < 52) {
149
0
            ch -= 26;
150
0
            ch += 'a';
151
0
        } else if (ch < 62) {
152
0
            ch -= 52;
153
0
            ch += '0';
154
0
        } else if (ch == 62) {
155
0
            ch = '+';
156
0
        } else if (ch == 63) {
157
0
            ch = '/';
158
0
        }
159
0
        out[i] = to_uc(ch);
160
0
    }
161
0
    for (size_t i = 0; i < 3 - pos; ++i) {
162
0
        out[3 - i] = '=';
163
0
    }
164
0
    next()->write(out, 4);
165
0
}
166
167
void
168
Pl_Base64::finish()
169
0
{
170
0
    if (pos > 0) {
171
0
        if (finished) {
172
0
            throw std::logic_error("Pl_Base64 used after finished");
173
0
        }
174
0
        if (action == a_decode) {
175
0
            for (size_t i = pos; i < 4; ++i) {
176
0
                buf[i] = '=';
177
0
            }
178
0
        }
179
0
        flush();
180
0
    }
181
0
    finished = true;
182
0
    next()->finish();
183
0
}
184
185
void
186
Pl_Base64::reset()
187
0
{
188
0
    pos = 0;
189
0
    memset(buf, 0, 4);
190
0
}