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