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