diff --git a/ChangeLog b/ChangeLog index 5ca2d81b..ca9b94fb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-06-21 Jay Berkenbilt + + * libqpdf/QPDF.cc: new processFile method that takes an open FILE* + instead of a filename. + 2012-06-20 Jay Berkenbilt * Add new array mutation routines to QPDFObjectHandle. diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index ee9dba87..26f9cdc9 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -52,6 +52,14 @@ class QPDF QPDF_DLL void processFile(char const* filename, char const* password = 0); + // Parse a PDF from a stdio FILE*. The FILE must be open in + // binary mode and must be seekable. It may be open read only. + // This works exactly like processFile except that the PDF file is + // read from an already opened FILE*. The caller is responsible + // for closing the file. + QPDF_DLL + void processFile(FILE* file, char const* password = 0); + // Parse a PDF file loaded into a memory buffer. This works // exactly like processFile except that the PDF file is in memory // instead of on disk. The description appears in any warning or @@ -400,6 +408,7 @@ class QPDF public: FileInputSource(); void setFilename(char const* filename); + void setFile(FILE* filep); virtual ~FileInputSource(); virtual std::string const& getName() const; virtual off_t tell(); @@ -414,6 +423,7 @@ class QPDF void destroy(); + bool close_file; std::string filename; FILE* file; }; diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 7ed00c98..1c47d893 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -80,6 +80,7 @@ QPDF::InputSource::readLine() } QPDF::FileInputSource::FileInputSource() : + close_file(false), file(0) { } @@ -89,10 +90,21 @@ 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(FILE* f) +{ + destroy(); + this->filename = "stdio FILE"; + this->close_file = false; + this->file = f; + this->seek(0, SEEK_SET); +} + QPDF::FileInputSource::~FileInputSource() { destroy(); @@ -101,7 +113,7 @@ QPDF::FileInputSource::~FileInputSource() void QPDF::FileInputSource::destroy() { - if (this->file) + if (this->file && this->close_file) { fclose(this->file); this->file = 0; @@ -316,6 +328,15 @@ QPDF::processFile(char const* filename, char const* password) parse(password); } +void +QPDF::processFile(FILE* filep, char const* password) +{ + FileInputSource* fi = new FileInputSource(); + this->file = fi; + fi->setFile(filep); + parse(password); +} + void QPDF::processMemoryFile(char const* description, char const* buf, size_t length, diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index 51a5f6aa..8cfe81e4 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -200,3 +200,6 @@ qpdf-c set_info_key to null 0 qpdf-c set-info-key use existing info 0 qpdf-c add info to trailer 0 qpdf-c called qpdf_init_write_memory 0 +exercise processFile(name) 0 +exercise processFile(FILE*) 0 +exercise processMemoryFile 0 diff --git a/qpdf/test_driver.cc b/qpdf/test_driver.cc index ca2fc698..2dc41b41 100644 --- a/qpdf/test_driver.cc +++ b/qpdf/test_driver.cc @@ -60,17 +60,29 @@ void runtest(int n, char const* filename) { QPDF pdf; PointerHolder file_buf; + FILE* filep = 0; if (n == 0) { pdf.setAttemptRecovery(false); } if (n % 2 == 0) { - pdf.processFile(filename); + if (n % 4 == 0) + { + QTC::TC("qpdf", "exercise processFile(name)"); + pdf.processFile(filename); + } + else + { + QTC::TC("qpdf", "exercise processFile(FILE*)"); + filep = QUtil::fopen_wrapper(std::string("open ") + filename, + fopen(filename, "rb")); + pdf.processFile(filep); + } } else { - // Exercise processMemoryFile + QTC::TC("qpdf", "exercise processMemoryFile"); FILE* f = QUtil::fopen_wrapper(std::string("open ") + filename, fopen(filename, "rb")); fseek(f, 0, SEEK_END); @@ -623,6 +635,10 @@ void runtest(int n, char const* filename) QUtil::int_to_string(n)); } + if (filep) + { + fclose(filep); + } std::cout << "test " << n << " done" << std::endl; }