2012-07-21 09:37:14 +00:00
|
|
|
#include <qpdf/FileInputSource.hh>
|
2022-02-04 21:31:31 +00:00
|
|
|
|
2012-07-21 09:37:14 +00:00
|
|
|
#include <qpdf/QPDFExc.hh>
|
2022-04-02 21:14:10 +00:00
|
|
|
#include <qpdf/QUtil.hh>
|
2013-11-29 15:20:50 +00:00
|
|
|
#include <algorithm>
|
2023-05-20 11:22:32 +00:00
|
|
|
#include <cstring>
|
2012-07-21 09:37:14 +00:00
|
|
|
|
2019-06-22 01:32:47 +00:00
|
|
|
FileInputSource::FileInputSource() :
|
2022-08-25 11:42:14 +00:00
|
|
|
close_file(false),
|
|
|
|
file(nullptr)
|
2019-06-22 01:32:47 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-05-04 16:02:39 +00:00
|
|
|
FileInputSource::FileInputSource(char const* filename) :
|
2022-08-25 11:42:14 +00:00
|
|
|
close_file(true),
|
|
|
|
filename(filename),
|
|
|
|
file(QUtil::safe_fopen(filename, "rb"))
|
2022-05-04 16:02:39 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
FileInputSource::FileInputSource(
|
|
|
|
char const* description, FILE* filep, bool close_file) :
|
2022-08-25 11:42:14 +00:00
|
|
|
close_file(close_file),
|
|
|
|
filename(description),
|
|
|
|
file(filep)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
FileInputSource::~FileInputSource()
|
2022-05-04 16:02:39 +00:00
|
|
|
{
|
2022-08-25 11:42:14 +00:00
|
|
|
// Must be explicit and not inline -- see QPDF_DLL_CLASS in
|
|
|
|
// README-maintainer
|
|
|
|
if (this->file && this->close_file) {
|
|
|
|
fclose(this->file);
|
|
|
|
}
|
2022-05-04 16:02:39 +00:00
|
|
|
}
|
|
|
|
|
2012-07-21 09:37:14 +00:00
|
|
|
void
|
|
|
|
FileInputSource::setFilename(char const* filename)
|
|
|
|
{
|
2022-08-25 11:42:14 +00:00
|
|
|
this->close_file = true;
|
|
|
|
this->filename = filename;
|
|
|
|
this->file = QUtil::safe_fopen(filename, "rb");
|
2012-07-21 09:37:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2022-04-02 21:14:10 +00:00
|
|
|
FileInputSource::setFile(char const* description, FILE* filep, bool close_file)
|
2012-07-21 09:37:14 +00:00
|
|
|
{
|
2022-08-25 11:42:14 +00:00
|
|
|
this->filename = description;
|
|
|
|
this->file = filep;
|
2012-07-21 09:37:14 +00:00
|
|
|
this->seek(0, SEEK_SET);
|
|
|
|
}
|
|
|
|
|
|
|
|
qpdf_offset_t
|
|
|
|
FileInputSource::findAndSkipNextEOL()
|
|
|
|
{
|
|
|
|
qpdf_offset_t result = 0;
|
|
|
|
bool done = false;
|
|
|
|
char buf[10240];
|
2022-04-02 21:14:10 +00:00
|
|
|
while (!done) {
|
2022-08-25 11:42:14 +00:00
|
|
|
qpdf_offset_t cur_offset = QUtil::tell(this->file);
|
2012-07-21 09:37:14 +00:00
|
|
|
size_t len = this->read(buf, sizeof(buf));
|
2022-04-02 21:14:10 +00:00
|
|
|
if (len == 0) {
|
2012-07-21 09:37:14 +00:00
|
|
|
done = true;
|
|
|
|
result = this->tell();
|
2022-04-02 21:14:10 +00:00
|
|
|
} else {
|
2013-02-24 02:46:21 +00:00
|
|
|
char* p1 = static_cast<char*>(memchr(buf, '\r', len));
|
|
|
|
char* p2 = static_cast<char*>(memchr(buf, '\n', len));
|
2012-07-21 09:37:14 +00:00
|
|
|
char* p = (p1 && p2) ? std::min(p1, p2) : p1 ? p1 : p2;
|
2022-04-02 21:14:10 +00:00
|
|
|
if (p) {
|
2012-07-21 09:37:14 +00:00
|
|
|
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;
|
2022-04-02 21:14:10 +00:00
|
|
|
while (!done) {
|
|
|
|
if (this->read(&ch, 1) == 0) {
|
2012-07-21 09:37:14 +00:00
|
|
|
done = true;
|
2022-04-02 21:14:10 +00:00
|
|
|
} else if (!((ch == '\r') || (ch == '\n'))) {
|
2020-10-27 14:51:41 +00:00
|
|
|
this->unreadCh(ch);
|
2012-07-21 09:37:14 +00:00
|
|
|
done = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string const&
|
|
|
|
FileInputSource::getName() const
|
|
|
|
{
|
2022-08-25 11:42:14 +00:00
|
|
|
return this->filename;
|
2012-07-21 09:37:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
qpdf_offset_t
|
|
|
|
FileInputSource::tell()
|
|
|
|
{
|
2022-08-25 11:42:14 +00:00
|
|
|
return QUtil::tell(this->file);
|
2012-07-21 09:37:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
FileInputSource::seek(qpdf_offset_t offset, int whence)
|
|
|
|
{
|
2022-08-25 13:05:36 +00:00
|
|
|
if (QUtil::seek(this->file, offset, whence) == -1) {
|
|
|
|
QUtil::throw_system_error(
|
|
|
|
std::string("seek to ") + this->filename + ", offset " +
|
2022-09-21 16:49:21 +00:00
|
|
|
std::to_string(offset) + " (" + std::to_string(whence) + ")");
|
2022-08-25 13:05:36 +00:00
|
|
|
}
|
2012-07-21 09:37:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
FileInputSource::rewind()
|
|
|
|
{
|
2022-08-25 11:42:14 +00:00
|
|
|
::rewind(this->file);
|
2012-07-21 09:37:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t
|
|
|
|
FileInputSource::read(char* buffer, size_t length)
|
|
|
|
{
|
2022-08-25 14:08:03 +00:00
|
|
|
this->last_offset = QUtil::tell(this->file);
|
2022-08-25 11:42:14 +00:00
|
|
|
size_t len = fread(buffer, 1, length, this->file);
|
2022-04-02 21:14:10 +00:00
|
|
|
if (len == 0) {
|
2022-08-25 11:42:14 +00:00
|
|
|
if (ferror(this->file)) {
|
2022-04-02 21:14:10 +00:00
|
|
|
throw QPDFExc(
|
|
|
|
qpdf_e_system,
|
2022-08-25 11:42:14 +00:00
|
|
|
this->filename,
|
2022-04-02 21:14:10 +00:00
|
|
|
"",
|
|
|
|
this->last_offset,
|
2022-09-21 16:49:21 +00:00
|
|
|
(std::string("read ") + std::to_string(length) + " bytes"));
|
2022-04-02 21:14:10 +00:00
|
|
|
} else if (length > 0) {
|
2018-01-28 23:28:45 +00:00
|
|
|
this->seek(0, SEEK_END);
|
|
|
|
this->last_offset = this->tell();
|
|
|
|
}
|
2012-07-21 09:37:14 +00:00
|
|
|
}
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
FileInputSource::unreadCh(char ch)
|
|
|
|
{
|
2022-08-25 13:05:36 +00:00
|
|
|
if (ungetc(static_cast<unsigned char>(ch), this->file) == -1) {
|
|
|
|
QUtil::throw_system_error(this->filename + ": unread character");
|
|
|
|
}
|
2012-07-21 09:37:14 +00:00
|
|
|
}
|