Refactor: pull *InputSource out of QPDF

InputSource, FileInputSource, and BufferInputSource are now top-level
classes instead of privately nested inside QPDF.
This commit is contained in:
Jay Berkenbilt 2012-07-21 05:37:14 -04:00
parent 8657c6f004
commit 15eaed5c52
9 changed files with 424 additions and 386 deletions

View File

@ -0,0 +1,28 @@
#ifndef __QPDF_BUFFERINPUTSOURCE_HH__
#define __QPDF_BUFFERINPUTSOURCE_HH__
#include <qpdf/InputSource.hh>
#include <qpdf/Buffer.hh>
class BufferInputSource: public InputSource
{
public:
BufferInputSource(std::string const& description, Buffer* buf,
bool own_memory = false);
virtual ~BufferInputSource();
virtual qpdf_offset_t findAndSkipNextEOL();
virtual std::string const& getName() const;
virtual qpdf_offset_t tell();
virtual void seek(qpdf_offset_t offset, int whence);
virtual void rewind();
virtual size_t read(char* buffer, size_t length);
virtual void unreadCh(char ch);
private:
bool own_memory;
std::string description;
Buffer* buf;
qpdf_offset_t cur_offset;
};
#endif // __QPDF_BUFFERINPUTSOURCE_HH__

View File

@ -0,0 +1,32 @@
#ifndef __QPDF_FILEINPUTSOURCE_HH__
#define __QPDF_FILEINPUTSOURCE_HH__
#include <qpdf/InputSource.hh>
class FileInputSource: public InputSource
{
public:
FileInputSource();
void setFilename(char const* filename);
void setFile(char const* description, FILE* filep, bool close_file);
virtual ~FileInputSource();
virtual qpdf_offset_t findAndSkipNextEOL();
virtual std::string const& getName() const;
virtual qpdf_offset_t tell();
virtual void seek(qpdf_offset_t offset, int whence);
virtual void rewind();
virtual size_t read(char* buffer, size_t length);
virtual void unreadCh(char ch);
private:
FileInputSource(FileInputSource const&);
FileInputSource& operator=(FileInputSource const&);
void destroy();
bool close_file;
std::string filename;
FILE* file;
};
#endif // __QPDF_FILEINPUTSOURCE_HH__

View File

@ -0,0 +1,35 @@
#ifndef __QPDF_INPUTSOURCE_HH__
#define __QPDF_INPUTSOURCE_HH__
#include <qpdf/Types.h>
#include <stdio.h>
#include <string>
class InputSource
{
public:
InputSource() :
last_offset(0)
{
}
virtual ~InputSource()
{
}
void setLastOffset(qpdf_offset_t);
qpdf_offset_t getLastOffset() const;
std::string readLine(size_t max_line_length);
virtual qpdf_offset_t findAndSkipNextEOL() = 0;
virtual std::string const& getName() const = 0;
virtual qpdf_offset_t tell() = 0;
virtual void seek(qpdf_offset_t offset, int whence) = 0;
virtual void rewind() = 0;
virtual size_t read(char* buffer, size_t length) = 0;
virtual void unreadCh(char ch) = 0;
protected:
qpdf_offset_t last_offset;
};
#endif // __QPDF_INPUTSOURCE_HH__

View File

@ -21,6 +21,7 @@
#include <qpdf/QPDFObjectHandle.hh>
#include <qpdf/QPDFTokenizer.hh>
#include <qpdf/Buffer.hh>
#include <qpdf/InputSource.hh>
class QPDF_Stream;
class BitStream;
@ -474,80 +475,6 @@ class QPDF
private:
static std::string qpdf_version;
class InputSource
{
public:
InputSource() :
last_offset(0)
{
}
virtual ~InputSource()
{
}
void setLastOffset(qpdf_offset_t);
qpdf_offset_t getLastOffset() const;
std::string readLine(size_t max_line_length);
virtual qpdf_offset_t findAndSkipNextEOL() = 0;
virtual std::string const& getName() const = 0;
virtual qpdf_offset_t tell() = 0;
virtual void seek(qpdf_offset_t offset, int whence) = 0;
virtual void rewind() = 0;
virtual size_t read(char* buffer, size_t length) = 0;
virtual void unreadCh(char ch) = 0;
protected:
qpdf_offset_t last_offset;
};
class FileInputSource: public InputSource
{
public:
FileInputSource();
void setFilename(char const* filename);
void setFile(char const* description, FILE* filep, bool close_file);
virtual ~FileInputSource();
virtual qpdf_offset_t findAndSkipNextEOL();
virtual std::string const& getName() const;
virtual qpdf_offset_t tell();
virtual void seek(qpdf_offset_t offset, int whence);
virtual void rewind();
virtual size_t read(char* buffer, size_t length);
virtual void unreadCh(char ch);
private:
FileInputSource(FileInputSource const&);
FileInputSource& operator=(FileInputSource const&);
void destroy();
bool close_file;
std::string filename;
FILE* file;
};
class BufferInputSource: public InputSource
{
public:
BufferInputSource(std::string const& description, Buffer* buf,
bool own_memory = false);
virtual ~BufferInputSource();
virtual qpdf_offset_t findAndSkipNextEOL();
virtual std::string const& getName() const;
virtual qpdf_offset_t tell();
virtual void seek(qpdf_offset_t offset, int whence);
virtual void rewind();
virtual size_t read(char* buffer, size_t length);
virtual void unreadCh(char ch);
private:
bool own_memory;
std::string description;
Buffer* buf;
qpdf_offset_t cur_offset;
};
class ObjGen
{
public:

View File

@ -0,0 +1,141 @@
#include <qpdf/BufferInputSource.hh>
#include <string.h>
#include <stdexcept>
BufferInputSource::BufferInputSource(std::string const& description,
Buffer* buf, bool own_memory) :
own_memory(own_memory),
description(description),
buf(buf),
cur_offset(0)
{
}
BufferInputSource::~BufferInputSource()
{
if (own_memory)
{
delete this->buf;
}
}
qpdf_offset_t
BufferInputSource::findAndSkipNextEOL()
{
if (this->cur_offset < 0)
{
throw std::logic_error("INTERNAL ERROR: BufferInputSource offset < 0");
}
qpdf_offset_t end_pos = (qpdf_offset_t) this->buf->getSize();
if (this->cur_offset >= end_pos)
{
this->last_offset = end_pos;
this->cur_offset = end_pos;
return end_pos;
}
qpdf_offset_t result = 0;
size_t len = (size_t)(end_pos - this->cur_offset);
unsigned char const* buffer = this->buf->getBuffer();
void* start = (void*)(buffer + this->cur_offset);
unsigned char* p1 = (unsigned char*)memchr(start, '\r', len);
unsigned char* p2 = (unsigned char*)memchr(start, '\n', len);
unsigned char* p = (p1 && p2) ? std::min(p1, p2) : p1 ? p1 : p2;
if (p)
{
result = p - buffer;
this->cur_offset = result + 1;
++p;
while ((this->cur_offset < end_pos) &&
((*p == '\r') || (*p == '\n')))
{
++p;
++this->cur_offset;
}
}
else
{
this->cur_offset = end_pos;
result = end_pos;
}
return result;
}
std::string const&
BufferInputSource::getName() const
{
return this->description;
}
qpdf_offset_t
BufferInputSource::tell()
{
return this->cur_offset;
}
void
BufferInputSource::seek(qpdf_offset_t offset, int whence)
{
switch (whence)
{
case SEEK_SET:
this->cur_offset = offset;
break;
case SEEK_END:
this->cur_offset = (qpdf_offset_t)this->buf->getSize() + offset;
break;
case SEEK_CUR:
this->cur_offset += offset;
break;
default:
throw std::logic_error(
"INTERNAL ERROR: invalid argument to BufferInputSource::seek");
break;
}
if (this->cur_offset < 0)
{
throw std::runtime_error(
this->description + ": seek before beginning of buffer");
}
}
void
BufferInputSource::rewind()
{
this->cur_offset = 0;
}
size_t
BufferInputSource::read(char* buffer, size_t length)
{
if (this->cur_offset < 0)
{
throw std::logic_error("INTERNAL ERROR: BufferInputSource offset < 0");
}
qpdf_offset_t end_pos = (qpdf_offset_t) this->buf->getSize();
if (this->cur_offset >= end_pos)
{
this->last_offset = end_pos;
return 0;
}
this->last_offset = this->cur_offset;
size_t len = std::min((size_t)(end_pos - this->cur_offset), length);
memcpy(buffer, buf->getBuffer() + this->cur_offset, len);
this->cur_offset += len;
return len;
}
void
BufferInputSource::unreadCh(char ch)
{
if (this->cur_offset > 0)
{
--this->cur_offset;
}
}

141
libqpdf/FileInputSource.cc Normal file
View File

@ -0,0 +1,141 @@
#include <qpdf/FileInputSource.hh>
#include <string.h>
#include <qpdf/QUtil.hh>
#include <qpdf/QPDFExc.hh>
FileInputSource::FileInputSource() :
close_file(false),
file(0)
{
}
void
FileInputSource::setFilename(char const* filename)
{
destroy();
this->filename = filename;
this->close_file = true;
this->file = QUtil::fopen_wrapper(std::string("open ") + this->filename,
fopen(this->filename.c_str(), "rb"));
}
void
FileInputSource::setFile(
char const* description, FILE* filep, bool close_file)
{
destroy();
this->filename = description;
this->close_file = close_file;
this->file = filep;
this->seek(0, SEEK_SET);
}
FileInputSource::~FileInputSource()
{
destroy();
}
void
FileInputSource::destroy()
{
if (this->file && this->close_file)
{
fclose(this->file);
this->file = 0;
}
}
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 = (char*)memchr((void*)buf, '\r', len);
char* p2 = (char*)memchr((void*)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)
{
QUtil::os_wrapper(std::string("seek to ") + this->filename + ", offset " +
QUtil::int_to_string(offset) + " (" +
QUtil::int_to_string(whence) + ")",
QUtil::seek(this->file, offset, 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) && ferror(this->file))
{
throw QPDFExc(qpdf_e_system,
this->filename, "",
this->last_offset,
std::string("read ") +
QUtil::int_to_string(length) + " bytes");
}
return len;
}
void
FileInputSource::unreadCh(char ch)
{
QUtil::os_wrapper(this->filename + ": unread character",
ungetc((unsigned char)ch, this->file));
}

41
libqpdf/InputSource.cc Normal file
View File

@ -0,0 +1,41 @@
#include <qpdf/InputSource.hh>
#include <string.h>
#include <qpdf/PointerHolder.hh>
void
InputSource::setLastOffset(qpdf_offset_t offset)
{
this->last_offset = offset;
}
qpdf_offset_t
InputSource::getLastOffset() const
{
return this->last_offset;
}
std::string
InputSource::readLine(size_t max_line_length)
{
// Return at most max_line_length characters from the next line.
// Lines are terminated by one or more \r or \n characters.
// Consume the trailing newline characters but don't return them.
// After this is called, the file will be positioned after a line
// terminator or at the end of the file, and last_offset will
// point to position the file had when this method was called.
qpdf_offset_t offset = this->tell();
char* buf = new char[max_line_length + 1];
PointerHolder<char> bp(true, buf);
memset(buf, '\0', max_line_length + 1);
this->read(buf, max_line_length);
this->seek(offset, SEEK_SET);
qpdf_offset_t eol = this->findAndSkipNextEOL();
this->last_offset = offset;
size_t line_length = eol - offset;
if (line_length < max_line_length)
{
buf[line_length] = '\0';
}
return std::string(buf);
}

View File

@ -11,6 +11,8 @@
#include <qpdf/PCRE.hh>
#include <qpdf/Pipeline.hh>
#include <qpdf/Pl_Discard.hh>
#include <qpdf/FileInputSource.hh>
#include <qpdf/BufferInputSource.hh>
#include <qpdf/QPDFExc.hh>
#include <qpdf/QPDF_Null.hh>
@ -36,318 +38,6 @@ static char const* EMPTY_PDF =
"110\n"
"%%EOF\n";
void
QPDF::InputSource::setLastOffset(qpdf_offset_t offset)
{
this->last_offset = offset;
}
qpdf_offset_t
QPDF::InputSource::getLastOffset() const
{
return this->last_offset;
}
std::string
QPDF::InputSource::readLine(size_t max_line_length)
{
// Return at most max_line_length characters from the next line.
// Lines are terminated by one or more \r or \n characters.
// Consume the trailing newline characters but don't return them.
// After this is called, the file will be positioned after a line
// terminator or at the end of the file, and last_offset will
// point to position the file had when this method was called.
qpdf_offset_t offset = this->tell();
char* buf = new char[max_line_length + 1];
PointerHolder<char> bp(true, buf);
memset(buf, '\0', max_line_length + 1);
this->read(buf, max_line_length);
this->seek(offset, SEEK_SET);
qpdf_offset_t eol = this->findAndSkipNextEOL();
this->last_offset = offset;
size_t line_length = eol - offset;
if (line_length < max_line_length)
{
buf[line_length] = '\0';
}
return std::string(buf);
}
QPDF::FileInputSource::FileInputSource() :
close_file(false),
file(0)
{
}
void
QPDF::FileInputSource::setFilename(char const* filename)
{
destroy();
this->filename = filename;
this->close_file = true;
this->file = QUtil::fopen_wrapper(std::string("open ") + this->filename,
fopen(this->filename.c_str(), "rb"));
}
void
QPDF::FileInputSource::setFile(
char const* description, FILE* filep, bool close_file)
{
destroy();
this->filename = description;
this->close_file = close_file;
this->file = filep;
this->seek(0, SEEK_SET);
}
QPDF::FileInputSource::~FileInputSource()
{
destroy();
}
void
QPDF::FileInputSource::destroy()
{
if (this->file && this->close_file)
{
fclose(this->file);
this->file = 0;
}
}
qpdf_offset_t
QPDF::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 = (char*)memchr((void*)buf, '\r', len);
char* p2 = (char*)memchr((void*)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&
QPDF::FileInputSource::getName() const
{
return this->filename;
}
qpdf_offset_t
QPDF::FileInputSource::tell()
{
return QUtil::tell(this->file);
}
void
QPDF::FileInputSource::seek(qpdf_offset_t offset, int whence)
{
QUtil::os_wrapper(std::string("seek to ") + this->filename + ", offset " +
QUtil::int_to_string(offset) + " (" +
QUtil::int_to_string(whence) + ")",
QUtil::seek(this->file, offset, whence));
}
void
QPDF::FileInputSource::rewind()
{
::rewind(this->file);
}
size_t
QPDF::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) && ferror(this->file))
{
throw QPDFExc(qpdf_e_system,
this->filename, "",
this->last_offset,
std::string("read ") +
QUtil::int_to_string(length) + " bytes");
}
return len;
}
void
QPDF::FileInputSource::unreadCh(char ch)
{
QUtil::os_wrapper(this->filename + ": unread character",
ungetc((unsigned char)ch, this->file));
}
QPDF::BufferInputSource::BufferInputSource(std::string const& description,
Buffer* buf, bool own_memory) :
own_memory(own_memory),
description(description),
buf(buf),
cur_offset(0)
{
}
QPDF::BufferInputSource::~BufferInputSource()
{
if (own_memory)
{
delete this->buf;
}
}
qpdf_offset_t
QPDF::BufferInputSource::findAndSkipNextEOL()
{
if (this->cur_offset < 0)
{
throw std::logic_error("INTERNAL ERROR: BufferInputSource offset < 0");
}
qpdf_offset_t end_pos = (qpdf_offset_t) this->buf->getSize();
if (this->cur_offset >= end_pos)
{
this->last_offset = end_pos;
this->cur_offset = end_pos;
return end_pos;
}
qpdf_offset_t result = 0;
size_t len = (size_t)(end_pos - this->cur_offset);
unsigned char const* buffer = this->buf->getBuffer();
void* start = (void*)(buffer + this->cur_offset);
unsigned char* p1 = (unsigned char*)memchr(start, '\r', len);
unsigned char* p2 = (unsigned char*)memchr(start, '\n', len);
unsigned char* p = (p1 && p2) ? std::min(p1, p2) : p1 ? p1 : p2;
if (p)
{
result = p - buffer;
this->cur_offset = result + 1;
++p;
while ((this->cur_offset < end_pos) &&
((*p == '\r') || (*p == '\n')))
{
++p;
++this->cur_offset;
}
}
else
{
this->cur_offset = end_pos;
result = end_pos;
}
return result;
}
std::string const&
QPDF::BufferInputSource::getName() const
{
return this->description;
}
qpdf_offset_t
QPDF::BufferInputSource::tell()
{
return this->cur_offset;
}
void
QPDF::BufferInputSource::seek(qpdf_offset_t offset, int whence)
{
switch (whence)
{
case SEEK_SET:
this->cur_offset = offset;
break;
case SEEK_END:
this->cur_offset = (qpdf_offset_t)this->buf->getSize() + offset;
break;
case SEEK_CUR:
this->cur_offset += offset;
break;
default:
throw std::logic_error(
"INTERNAL ERROR: invalid argument to BufferInputSource::seek");
break;
}
if (this->cur_offset < 0)
{
throw std::runtime_error(
this->description + ": seek before beginning of buffer");
}
}
void
QPDF::BufferInputSource::rewind()
{
this->cur_offset = 0;
}
size_t
QPDF::BufferInputSource::read(char* buffer, size_t length)
{
if (this->cur_offset < 0)
{
throw std::logic_error("INTERNAL ERROR: BufferInputSource offset < 0");
}
qpdf_offset_t end_pos = (qpdf_offset_t) this->buf->getSize();
if (this->cur_offset >= end_pos)
{
this->last_offset = end_pos;
return 0;
}
this->last_offset = this->cur_offset;
size_t len = std::min((size_t)(end_pos - this->cur_offset), length);
memcpy(buffer, buf->getBuffer() + this->cur_offset, len);
this->cur_offset += len;
return len;
}
void
QPDF::BufferInputSource::unreadCh(char ch)
{
if (this->cur_offset > 0)
{
--this->cur_offset;
}
}
QPDF::ObjGen::ObjGen(int o = 0, int g = 0) :
obj(o),

View File

@ -8,6 +8,9 @@ SRCS_libqpdf = \
libqpdf/BitStream.cc \
libqpdf/BitWriter.cc \
libqpdf/Buffer.cc \
libqpdf/BufferInputSource.cc \
libqpdf/FileInputSource.cc \
libqpdf/InputSource.cc \
libqpdf/MD5.cc \
libqpdf/PCRE.cc \
libqpdf/Pipeline.cc \