diff --git a/ChangeLog b/ChangeLog index 33542286..546c5658 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2021-12-29 Jay Berkenbilt + + * Add method QUtil::file_can_be_opened + 2021-12-21 Jay Berkenbilt * 10.5.0: release diff --git a/include/qpdf/QUtil.hh b/include/qpdf/QUtil.hh index dd42fe1c..5a064d5c 100644 --- a/include/qpdf/QUtil.hh +++ b/include/qpdf/QUtil.hh @@ -111,6 +111,10 @@ namespace QUtil QPDF_DLL FILE* fopen_wrapper(std::string const&, FILE*); + // Attempt to open the file read only and then close again + QPDF_DLL + bool file_can_be_opened(char const* filename); + // Wrap around off_t versions of fseek and ftell if available QPDF_DLL int seek(FILE* stream, qpdf_offset_t offset, int whence); diff --git a/libqpdf/QUtil.cc b/libqpdf/QUtil.cc index f45468a0..daa663a3 100644 --- a/libqpdf/QUtil.cc +++ b/libqpdf/QUtil.cc @@ -515,6 +515,21 @@ QUtil::fopen_wrapper(std::string const& description, FILE* f) return f; } +bool +QUtil::file_can_be_opened(char const* filename) +{ + try + { + fclose(safe_fopen(filename, "rb")); + return true; + } + catch (std::runtime_error&) + { + // can't open the file + } + return false; +} + int QUtil::seek(FILE* stream, qpdf_offset_t offset, int whence) { diff --git a/libtests/qutil.cc b/libtests/qutil.cc index f52ec2dc..46eb840c 100644 --- a/libtests/qutil.cc +++ b/libtests/qutil.cc @@ -203,6 +203,9 @@ void fopen_wrapper_test() std::cout << "exception: " << s.what() << std::endl; assert(s.getErrno() != 0); } + + assert(QUtil::file_can_be_opened("qutil.out")); + assert(! QUtil::file_can_be_opened("/does/not/exist")); } void getenv_test() diff --git a/qpdf/qpdf.cc b/qpdf/qpdf.cc index 77b7bdf1..aa1827d9 100644 --- a/qpdf/qpdf.cc +++ b/qpdf/qpdf.cc @@ -740,21 +740,6 @@ static void parse_object_id(std::string const& objspec, } } -static bool file_exists(char const* filename) -{ - try - { - fclose(QUtil::safe_fopen(filename, "rb")); - return true; - } - catch (std::runtime_error&) - { - // can't open the file - } - return false; -} - - // This is not a general-purpose argument parser. It is tightly // crafted to work with qpdf. qpdf's command-line syntax is very // complex because of its long history, and it doesn't really follow @@ -2976,7 +2961,7 @@ ArgParser::handleArgFileArguments() argfile = 1 + argv[i]; if (strcmp(argfile, "-") != 0) { - if (! file_exists(argfile)) + if (! QUtil::file_can_be_opened(argfile)) { // The file's not there; treating as regular option argfile = nullptr; @@ -3276,7 +3261,7 @@ ArgParser::parsePagesOptions() char const* file = argv[cur_arg++]; char const* password = 0; char const* range = argv[cur_arg++]; - if (! file_exists(file)) + if (! QUtil::file_can_be_opened(file)) { check_unclosed(file, 0); } @@ -3315,7 +3300,7 @@ ArgParser::parsePagesOptions() // "." means the input file. QTC::TC("qpdf", "qpdf pages range omitted with ."); } - else if (file_exists(range)) + else if (QUtil::file_can_be_opened(range)) { QTC::TC("qpdf", "qpdf pages range omitted in middle"); // Yup, it's a file.