Coverage Report

Created: 2024-09-08 06:05

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