Coverage Report

Created: 2025-06-22 06:30

/src/qpdf/libqpdf/FileInputSource.cc
Line
Count
Source (jump to first uncovered line)
1
#include <qpdf/FileInputSource.hh>
2
3
#include <qpdf/QPDFExc.hh>
4
#include <qpdf/QUtil.hh>
5
#include <algorithm>
6
#include <cstring>
7
8
FileInputSource::FileInputSource(char const* filename) :
9
0
    close_file(true),
10
0
    filename(filename),
11
0
    file(QUtil::safe_fopen(filename, "rb"))
12
0
{
13
0
}
14
15
FileInputSource::FileInputSource(char const* description, FILE* filep, bool close_file) :
16
0
    close_file(close_file),
17
0
    filename(description),
18
0
    file(filep)
19
0
{
20
0
}
21
22
FileInputSource::~FileInputSource()
23
0
{
24
    // Must be explicit and not inline -- see QPDF_DLL_CLASS in README-maintainer
25
0
    if (this->file && this->close_file) {
26
0
        fclose(this->file);
27
0
    }
28
0
}
29
30
void
31
FileInputSource::setFilename(char const* filename)
32
0
{
33
0
    this->close_file = true;
34
0
    this->filename = filename;
35
0
    this->file = QUtil::safe_fopen(filename, "rb");
36
0
}
37
38
void
39
FileInputSource::setFile(char const* description, FILE* filep, bool close_file)
40
0
{
41
0
    this->filename = description;
42
0
    this->file = filep;
43
0
    this->seek(0, SEEK_SET);
44
0
}
45
46
qpdf_offset_t
47
FileInputSource::findAndSkipNextEOL()
48
0
{
49
0
    qpdf_offset_t result = 0;
50
0
    bool done = false;
51
0
    char buf[10240];
52
0
    while (!done) {
53
0
        qpdf_offset_t cur_offset = QUtil::tell(this->file);
54
0
        size_t len = this->read(buf, sizeof(buf));
55
0
        if (len == 0) {
56
0
            done = true;
57
0
            result = this->tell();
58
0
        } else {
59
0
            char* p1 = static_cast<char*>(memchr(buf, '\r', len));
60
0
            char* p2 = static_cast<char*>(memchr(buf, '\n', len));
61
0
            char* p = (p1 && p2) ? std::min(p1, p2) : p1 ? p1 : p2;
62
0
            if (p) {
63
0
                result = cur_offset + (p - buf);
64
                // We found \r or \n.  Keep reading until we get past \r and \n characters.
65
0
                this->seek(result + 1, SEEK_SET);
66
0
                char ch;
67
0
                while (!done) {
68
0
                    if (this->read(&ch, 1) == 0) {
69
0
                        done = true;
70
0
                    } else if (!((ch == '\r') || (ch == '\n'))) {
71
0
                        this->unreadCh(ch);
72
0
                        done = true;
73
0
                    }
74
0
                }
75
0
            }
76
0
        }
77
0
    }
78
0
    return result;
79
0
}
80
81
std::string const&
82
FileInputSource::getName() const
83
0
{
84
0
    return this->filename;
85
0
}
86
87
qpdf_offset_t
88
FileInputSource::tell()
89
0
{
90
0
    return QUtil::tell(this->file);
91
0
}
92
93
void
94
FileInputSource::seek(qpdf_offset_t offset, int whence)
95
0
{
96
0
    if (QUtil::seek(this->file, offset, whence) == -1) {
97
0
        QUtil::throw_system_error(
98
0
            std::string("seek to ") + this->filename + ", offset " + std::to_string(offset) + " (" +
99
0
            std::to_string(whence) + ")");
100
0
    }
101
0
}
102
103
void
104
FileInputSource::rewind()
105
0
{
106
0
    ::rewind(this->file);
107
0
}
108
109
size_t
110
FileInputSource::read(char* buffer, size_t length)
111
0
{
112
0
    this->last_offset = QUtil::tell(this->file);
113
0
    size_t len = fread(buffer, 1, length, this->file);
114
0
    if (len == 0) {
115
0
        if (ferror(this->file)) {
116
0
            throw QPDFExc(
117
0
                qpdf_e_system,
118
0
                this->filename,
119
0
                "",
120
0
                this->last_offset,
121
0
                (std::string("read ") + std::to_string(length) + " bytes"));
122
0
        } else if (length > 0) {
123
0
            this->seek(0, SEEK_END);
124
0
            this->last_offset = this->tell();
125
0
        }
126
0
    }
127
0
    return len;
128
0
}
129
130
void
131
FileInputSource::unreadCh(char ch)
132
0
{
133
0
    if (ungetc(static_cast<unsigned char>(ch), this->file) == -1) {
134
0
        QUtil::throw_system_error(this->filename + ": unread character");
135
0
    }
136
0
}