diff --git a/ChangeLog b/ChangeLog index d5ceeea2..c81f88e0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2021-02-07 Jay Berkenbilt + + * Add new functions QUtil::pipe_file and QUtil::file_provider for + sending the contents of a file through a pipeline as binary data. + 2021-02-04 Jay Berkenbilt * Add new option --pasword-file=file for reading the decryption diff --git a/include/qpdf/QUtil.hh b/include/qpdf/QUtil.hh index 30a73441..fe18c9b7 100644 --- a/include/qpdf/QUtil.hh +++ b/include/qpdf/QUtil.hh @@ -34,6 +34,7 @@ #include class RandomDataProvider; +class Pipeline; namespace QUtil { @@ -119,6 +120,18 @@ namespace QUtil QPDF_DLL void rename_file(char const* oldname, char const* newname); + // Write the contents of filename as a binary file to the + // pipeline. + QPDF_DLL + void + pipe_file(char const* filename, Pipeline* p); + + // Return a function that will send the contents of the given file + // through the given pipeline as binary data. + QPDF_DLL + std::function + file_provider(std::string const& filename); + QPDF_DLL char* copy_string(std::string const&); diff --git a/libqpdf/QUtil.cc b/libqpdf/QUtil.cc index 5442b5ff..dc847679 100644 --- a/libqpdf/QUtil.cc +++ b/libqpdf/QUtil.cc @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -612,6 +613,35 @@ QUtil::rename_file(char const* oldname, char const* newname) #endif } +void +QUtil::pipe_file(char const* filename, Pipeline* p) +{ + // Exercised in test suite by testing file_provider. + FILE* f = safe_fopen(filename, "rb"); + FileCloser fc(f); + size_t len = 0; + int constexpr size = 8192; + unsigned char buf[size]; + while ((len = fread(buf, 1, size, f)) > 0) + { + p->write(buf, len); + } + p->finish(); + if (ferror(f)) + { + throw std::runtime_error( + std::string("failure reading file ") + filename); + } +} + +std::function +QUtil::file_provider(std::string const& filename) +{ + return [filename](Pipeline* p) { + pipe_file(filename.c_str(), p); + }; +} + char* QUtil::copy_string(std::string const& str) { @@ -1018,6 +1048,7 @@ QUtil::read_file_into_memory( PointerHolder& file_buf, size_t& size) { FILE* f = safe_fopen(filename, "rb"); + FileCloser fc(f); fseek(f, 0, SEEK_END); size = QIntC::to_size(QUtil::tell(f)); fseek(f, 0, SEEK_SET); @@ -1048,7 +1079,6 @@ QUtil::read_file_into_memory( uint_to_string(size)); } } - fclose(f); } static bool read_char_from_FILE(char& ch, FILE* f) diff --git a/libtests/qutil.cc b/libtests/qutil.cc index abfefce0..bc12a6ea 100644 --- a/libtests/qutil.cc +++ b/libtests/qutil.cc @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -483,6 +484,12 @@ void read_from_file_test() assert(memcmp(p, "This file is used for qutil testing.", 36) == 0); assert(p[59] == static_cast(13)); assert(memcmp(p + 24641, "very long.", 10) == 0); + Pl_Buffer b2("buffer"); + // QUtil::file_provider also exercises QUtil::pipe_file + QUtil::file_provider("other-file")(&b2); + auto buf2 = b2.getBuffer(); + assert(buf2->getSize() == size); + assert(memcmp(buf2->getBuffer(), p, size) == 0); } void assert_hex_encode(std::string const& input, std::string const& expected) diff --git a/manual/qpdf-manual.xml b/manual/qpdf-manual.xml index 09ba7408..39f3d969 100644 --- a/manual/qpdf-manual.xml +++ b/manual/qpdf-manual.xml @@ -4964,6 +4964,13 @@ print "\n"; read/write implementation of name and number trees. + + + Add new functions QUtil::pipe_file and + QUtil::file_provider for sending the + contents of a file through a pipeline as binary data. + +