From 15eaed5c52c85dd97ce5bc829817c5535c527207 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Sat, 21 Jul 2012 05:37:14 -0400 Subject: [PATCH] Refactor: pull *InputSource out of QPDF InputSource, FileInputSource, and BufferInputSource are now top-level classes instead of privately nested inside QPDF. --- include/qpdf/BufferInputSource.hh | 28 +++ include/qpdf/FileInputSource.hh | 32 +++ include/qpdf/InputSource.hh | 35 ++++ include/qpdf/QPDF.hh | 75 +------ libqpdf/BufferInputSource.cc | 141 ++++++++++++++ libqpdf/FileInputSource.cc | 141 ++++++++++++++ libqpdf/InputSource.cc | 41 ++++ libqpdf/QPDF.cc | 314 +----------------------------- libqpdf/build.mk | 3 + 9 files changed, 424 insertions(+), 386 deletions(-) create mode 100644 include/qpdf/BufferInputSource.hh create mode 100644 include/qpdf/FileInputSource.hh create mode 100644 include/qpdf/InputSource.hh create mode 100644 libqpdf/BufferInputSource.cc create mode 100644 libqpdf/FileInputSource.cc create mode 100644 libqpdf/InputSource.cc diff --git a/include/qpdf/BufferInputSource.hh b/include/qpdf/BufferInputSource.hh new file mode 100644 index 00000000..63c14def --- /dev/null +++ b/include/qpdf/BufferInputSource.hh @@ -0,0 +1,28 @@ +#ifndef __QPDF_BUFFERINPUTSOURCE_HH__ +#define __QPDF_BUFFERINPUTSOURCE_HH__ + +#include +#include + +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__ diff --git a/include/qpdf/FileInputSource.hh b/include/qpdf/FileInputSource.hh new file mode 100644 index 00000000..6129326d --- /dev/null +++ b/include/qpdf/FileInputSource.hh @@ -0,0 +1,32 @@ +#ifndef __QPDF_FILEINPUTSOURCE_HH__ +#define __QPDF_FILEINPUTSOURCE_HH__ + +#include + +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__ diff --git a/include/qpdf/InputSource.hh b/include/qpdf/InputSource.hh new file mode 100644 index 00000000..782d8888 --- /dev/null +++ b/include/qpdf/InputSource.hh @@ -0,0 +1,35 @@ +#ifndef __QPDF_INPUTSOURCE_HH__ +#define __QPDF_INPUTSOURCE_HH__ + +#include +#include +#include + +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__ diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index 3b72e981..e6ff75b4 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -21,6 +21,7 @@ #include #include #include +#include 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: diff --git a/libqpdf/BufferInputSource.cc b/libqpdf/BufferInputSource.cc new file mode 100644 index 00000000..6909dce2 --- /dev/null +++ b/libqpdf/BufferInputSource.cc @@ -0,0 +1,141 @@ +#include +#include +#include + +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; + } +} diff --git a/libqpdf/FileInputSource.cc b/libqpdf/FileInputSource.cc new file mode 100644 index 00000000..b1f7b5d2 --- /dev/null +++ b/libqpdf/FileInputSource.cc @@ -0,0 +1,141 @@ +#include +#include +#include +#include + +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)); +} diff --git a/libqpdf/InputSource.cc b/libqpdf/InputSource.cc new file mode 100644 index 00000000..79c889bf --- /dev/null +++ b/libqpdf/InputSource.cc @@ -0,0 +1,41 @@ +#include +#include +#include + +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 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); +} diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 1a8a689d..43757735 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include @@ -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 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), diff --git a/libqpdf/build.mk b/libqpdf/build.mk index 422878f2..cc379b63 100644 --- a/libqpdf/build.mk +++ b/libqpdf/build.mk @@ -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 \