Coverage Report

Created: 2025-11-11 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qpdf/libqpdf/MD5.cc
Line
Count
Source
1
#include <qpdf/MD5.hh>
2
3
#include <qpdf/Pl_MD5.hh>
4
5
#include <qpdf/QIntC.hh>
6
#include <qpdf/QPDFCryptoProvider.hh>
7
#include <qpdf/QUtil.hh>
8
9
#include <cstring>
10
11
MD5::MD5()
12
26.3k
{
13
26.3k
    init();
14
26.3k
}
15
16
void
17
MD5::init()
18
34.7k
{
19
34.7k
    crypto = QPDFCryptoProvider::getImpl();
20
34.7k
    crypto->MD5_init();
21
34.7k
}
22
23
void
24
MD5::finalize()
25
0
{
26
0
    crypto->MD5_finalize();
27
0
}
28
29
void
30
MD5::reset()
31
8.43k
{
32
8.43k
    init();
33
8.43k
}
34
35
void
36
MD5::encodeString(char const* str)
37
8.01k
{
38
8.01k
    size_t len = strlen(str);
39
8.01k
    crypto->MD5_init();
40
8.01k
    encodeDataIncrementally(str, len);
41
8.01k
    crypto->MD5_finalize();
42
8.01k
}
43
44
void
45
MD5::appendString(char const* input_string)
46
0
{
47
0
    encodeDataIncrementally(input_string, strlen(input_string));
48
0
}
49
50
void
51
MD5::encodeFile(char const* filename, qpdf_offset_t up_to_offset)
52
0
{
53
0
    char buffer[1024];
54
55
0
    FILE* file = QUtil::safe_fopen(filename, "rb");
56
0
    size_t len;
57
0
    size_t so_far = 0;
58
0
    size_t to_try = 1024;
59
0
    size_t up_to_size = 0;
60
0
    if (up_to_offset >= 0) {
61
0
        up_to_size = QIntC::to_size(up_to_offset);
62
0
    }
63
0
    do {
64
0
        if ((up_to_offset >= 0) && ((so_far + to_try) > up_to_size)) {
65
0
            to_try = up_to_size - so_far;
66
0
        }
67
0
        len = fread(buffer, 1, to_try, file);
68
0
        if (len > 0) {
69
0
            encodeDataIncrementally(buffer, len);
70
0
            so_far += len;
71
0
            if ((up_to_offset >= 0) && (so_far >= up_to_size)) {
72
0
                break;
73
0
            }
74
0
        }
75
0
    } while (len > 0);
76
0
    if (ferror(file)) {
77
        // Assume, perhaps incorrectly, that errno was set by the underlying call to read....
78
0
        (void)fclose(file);
79
0
        QUtil::throw_system_error(std::string("MD5: read error on ") + filename);
80
0
    }
81
0
    (void)fclose(file);
82
83
0
    crypto->MD5_finalize();
84
0
}
85
86
void
87
MD5::digest(Digest result)
88
25.9k
{
89
25.9k
    crypto->MD5_finalize();
90
25.9k
    crypto->MD5_digest(result);
91
25.9k
}
92
93
std::string
94
MD5::digest()
95
116
{
96
116
    Digest digest_val;
97
116
    digest(digest_val);
98
116
    return {reinterpret_cast<char*>(digest_val), 16};
99
116
}
100
101
std::string
102
MD5::digest(std::string_view data)
103
163
{
104
163
    MD5 m;
105
163
    m.encodeDataIncrementally(data.data(), data.size());
106
163
    Digest digest_val;
107
163
    m.digest(digest_val);
108
163
    return {reinterpret_cast<char*>(digest_val), 16};
109
163
}
110
111
void
112
MD5::print()
113
0
{
114
0
    Digest digest_val;
115
0
    digest(digest_val);
116
117
0
    unsigned int i;
118
0
    for (i = 0; i < 16; ++i) {
119
0
        printf("%02x", digest_val[i]);
120
0
    }
121
0
    printf("\n");
122
0
}
123
124
std::string
125
MD5::unparse()
126
8.01k
{
127
8.01k
    crypto->MD5_finalize();
128
8.01k
    Digest digest_val;
129
8.01k
    digest(digest_val);
130
8.01k
    return QUtil::hex_encode(std::string(reinterpret_cast<char*>(digest_val), 16));
131
8.01k
}
132
133
std::string
134
MD5::getDataChecksum(char const* buf, size_t len)
135
0
{
136
0
    MD5 m;
137
0
    m.encodeDataIncrementally(buf, len);
138
0
    return m.unparse();
139
0
}
140
141
std::string
142
MD5::getFileChecksum(char const* filename, qpdf_offset_t up_to_offset)
143
0
{
144
0
    MD5 m;
145
0
    m.encodeFile(filename, up_to_offset);
146
0
    return m.unparse();
147
0
}
148
149
bool
150
MD5::checkDataChecksum(char const* const checksum, char const* buf, size_t len)
151
0
{
152
0
    std::string actual_checksum = getDataChecksum(buf, len);
153
0
    return (checksum == actual_checksum);
154
0
}
155
156
bool
157
MD5::checkFileChecksum(char const* const checksum, char const* filename, qpdf_offset_t up_to_offset)
158
0
{
159
0
    bool result = false;
160
0
    try {
161
0
        std::string actual_checksum = getFileChecksum(filename, up_to_offset);
162
0
        result = (checksum == actual_checksum);
163
0
    } catch (std::runtime_error const&) {
164
        // Ignore -- return false
165
0
    }
166
0
    return result;
167
0
}
168
169
void
170
Pl_MD5::write(unsigned char const* buf, size_t len)
171
2.52M
{
172
2.52M
    if (enabled) {
173
2.52M
        if (!in_progress) {
174
8.43k
            md5.reset();
175
8.43k
            in_progress = true;
176
8.43k
        }
177
178
        // Write in chunks in case len is too big to fit in an int. Assume int is at least 32 bits.
179
2.52M
        static size_t const max_bytes = 1 << 30;
180
2.52M
        size_t bytes_left = len;
181
2.52M
        unsigned char const* data = buf;
182
5.05M
        while (bytes_left > 0) {
183
2.52M
            size_t bytes = (bytes_left >= max_bytes ? max_bytes : bytes_left);
184
2.52M
            md5.encodeDataIncrementally(reinterpret_cast<char const*>(data), bytes);
185
2.52M
            bytes_left -= bytes;
186
2.52M
            data += bytes;
187
2.52M
        }
188
2.52M
    }
189
190
2.52M
    if (next()) {
191
2.52M
        next()->write(buf, len);
192
2.52M
    }
193
2.52M
}