Coverage Report

Created: 2025-11-24 06:47

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
0
{
13
0
    init();
14
0
}
15
16
void
17
MD5::init()
18
0
{
19
0
    crypto = QPDFCryptoProvider::getImpl();
20
0
    crypto->MD5_init();
21
0
}
22
23
void
24
MD5::finalize()
25
0
{
26
0
    crypto->MD5_finalize();
27
0
}
28
29
void
30
MD5::reset()
31
0
{
32
0
    init();
33
0
}
34
35
void
36
MD5::encodeString(char const* str)
37
0
{
38
0
    size_t len = strlen(str);
39
0
    crypto->MD5_init();
40
0
    encodeDataIncrementally(str, len);
41
0
    crypto->MD5_finalize();
42
0
}
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
0
{
89
0
    crypto->MD5_finalize();
90
0
    crypto->MD5_digest(result);
91
0
}
92
93
std::string
94
MD5::digest()
95
0
{
96
0
    Digest digest_val;
97
0
    digest(digest_val);
98
0
    return {reinterpret_cast<char*>(digest_val), 16};
99
0
}
100
101
std::string
102
MD5::digest(std::string_view data)
103
0
{
104
0
    MD5 m;
105
0
    m.encodeDataIncrementally(data.data(), data.size());
106
0
    Digest digest_val;
107
0
    m.digest(digest_val);
108
0
    return {reinterpret_cast<char*>(digest_val), 16};
109
0
}
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
0
{
127
0
    crypto->MD5_finalize();
128
0
    Digest digest_val;
129
0
    digest(digest_val);
130
0
    return QUtil::hex_encode(std::string(reinterpret_cast<char*>(digest_val), 16));
131
0
}
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
0
{
172
0
    if (enabled) {
173
0
        if (!in_progress) {
174
0
            md5.reset();
175
0
            in_progress = true;
176
0
        }
177
178
        // Write in chunks in case len is too big to fit in an int. Assume int is at least 32 bits.
179
0
        static size_t const max_bytes = 1 << 30;
180
0
        size_t bytes_left = len;
181
0
        unsigned char const* data = buf;
182
0
        while (bytes_left > 0) {
183
0
            size_t bytes = (bytes_left >= max_bytes ? max_bytes : bytes_left);
184
0
            md5.encodeDataIncrementally(reinterpret_cast<char const*>(data), bytes);
185
0
            bytes_left -= bytes;
186
0
            data += bytes;
187
0
        }
188
0
    }
189
190
0
    if (next()) {
191
0
        next()->write(buf, len);
192
0
    }
193
0
}