From 0b1623d07db963ecf3789aba7163321812cba88e Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Thu, 18 Feb 2021 07:55:39 -0500 Subject: [PATCH] Add QUtil::path_basename --- ChangeLog | 2 ++ include/qpdf/QUtil.hh | 16 ++++++++++++---- libqpdf/QUtil.cc | 31 +++++++++++++++++++++++++++++++ libtests/qtest/qutil/qutil.out | 7 +++++++ libtests/qutil.cc | 25 +++++++++++++++++++++++++ manual/qpdf-manual.xml | 6 ++++++ 6 files changed, 83 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2a3f1780..4a758b54 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2021-02-18 Jay Berkenbilt + * Add QUtil::path_basename to get last element of a path. + * Add examples/pdf-attach-file.cc to illustrate new file attachment method and also new parse that takes indirect objects. diff --git a/include/qpdf/QUtil.hh b/include/qpdf/QUtil.hh index 769c5fd7..dd42fe1c 100644 --- a/include/qpdf/QUtil.hh +++ b/include/qpdf/QUtil.hh @@ -130,14 +130,22 @@ namespace QUtil // Write the contents of filename as a binary file to the // pipeline. QPDF_DLL - void - pipe_file(char const* filename, Pipeline* p); + 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); + std::function file_provider(std::string const& filename); + + // Return the last path element. On Windows, either / or \ are + // path separators. Otherwise, only / is a path separator. Strip + // any trailing path separators. Then, if any path separators + // remain, return everything after the last path separator. + // Otherwise, return the whole string. As a special case, if a + // string consists entirely of path separators, the first + // character is returned. + QPDF_DLL + std::string path_basename(std::string const& filename); QPDF_DLL char* copy_string(std::string const&); diff --git a/libqpdf/QUtil.cc b/libqpdf/QUtil.cc index a3fa94f4..17b163f5 100644 --- a/libqpdf/QUtil.cc +++ b/libqpdf/QUtil.cc @@ -663,6 +663,37 @@ QUtil::file_provider(std::string const& filename) }; } +std::string +QUtil::path_basename(std::string const& filename) +{ +#ifdef _WIN32 + char const* pathsep = "/\\"; +#else + char const* pathsep = "/"; +#endif + std::string last = filename; + auto len = last.length(); + while (len > 1) + { + auto pos = last.find_last_of(pathsep); + if (pos == len - 1) + { + last.pop_back(); + --len; + } + else if (pos == std::string::npos) + { + break; + } + else + { + last = last.substr(pos + 1); + break; + } + } + return last; +} + char* QUtil::copy_string(std::string const& str) { diff --git a/libtests/qtest/qutil/qutil.out b/libtests/qtest/qutil/qutil.out index 7dded2e3..90f1fd16 100644 --- a/libtests/qtest/qutil/qutil.out +++ b/libtests/qtest/qutil/qutil.out @@ -97,6 +97,13 @@ file1: -qutil.out-, file2: -other-file-; same: 0: PASS file1: -qutil.out-, file2: --; same: 0: PASS file1: -qutil.out-, file2: -(null)-; same: 0: PASS file1: --, file2: -qutil.out-; same: 0: PASS +---- path +//// -> / +a/b/cdef -> cdef +a/b/cdef/ -> cdef +/ -> / + -> +quack -> quack ---- read from file This file is used for qutil testing. It has mixed newlines. diff --git a/libtests/qutil.cc b/libtests/qutil.cc index abe05f35..7b1a8788 100644 --- a/libtests/qutil.cc +++ b/libtests/qutil.cc @@ -439,6 +439,29 @@ void same_file_test() assert_same_file("", "qutil.out", false); } +void path_test() +{ + auto check = [](bool print, std::string const& a, std::string const& b) { + auto result = QUtil::path_basename(a); + if (print) + { + std::cout << a << " -> " << result << std::endl; + } + assert(result == b); + }; + +#ifdef _WIN32 + check(false, "asdf\\qwer", "qwer"); + check(false, "asdf\\qwer/\\", "qwer"); +#endif + check(true, "////", "/"); + check(true, "a/b/cdef", "cdef"); + check(true, "a/b/cdef/", "cdef"); + check(true, "/", "/"); + check(true, "", ""); + check(true, "quack", "quack"); +} + void read_from_file_test() { std::list lines = QUtil::read_lines_from_file("other-file"); @@ -636,6 +659,8 @@ int main(int argc, char* argv[]) get_whoami_test(); std::cout << "---- file" << std::endl; same_file_test(); + std::cout << "---- path" << std::endl; + path_test(); std::cout << "---- read from file" << std::endl; read_from_file_test(); std::cout << "---- hex encode/decode" << std::endl; diff --git a/manual/qpdf-manual.xml b/manual/qpdf-manual.xml index 4a294cb3..2c1c235a 100644 --- a/manual/qpdf-manual.xml +++ b/manual/qpdf-manual.xml @@ -5283,6 +5283,12 @@ print "\n"; matrices. + + + Add QUtil::path_basename to return the + last element of a path. + +