/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 | } |