From 4fa7b1eb606ecd749409a907ea7a47b39d48cb7b Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Sat, 31 Aug 2019 11:00:53 -0400 Subject: [PATCH] Add remove_file and rename_file to QUtil --- ChangeLog | 4 +++ include/qpdf/QUtil.hh | 7 +++++ libqpdf/QUtil.cc | 54 ++++++++++++++++++++++++++++++---- libtests/qtest/qutil/qutil.out | 6 ++++ libtests/qutil.cc | 53 +++++++++++++++++++++++++++++++++ 5 files changed, 119 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0c5ccf07..0efdebec 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2019-08-31 Jay Berkenbilt + + * Add methods rename_file and remove_file to QUtil. + 2019-08-24 Jay Berkenbilt * Add QPDF::userPasswordMatched() and QPDF::ownerPasswordMatched() diff --git a/include/qpdf/QUtil.hh b/include/qpdf/QUtil.hh index a0442f69..9994fcc6 100644 --- a/include/qpdf/QUtil.hh +++ b/include/qpdf/QUtil.hh @@ -110,6 +110,13 @@ namespace QUtil QPDF_DLL bool same_file(char const* name1, char const* name2); + QPDF_DLL + void remove_file(char const* path); + + // rename_file will overwrite newname if it exists + QPDF_DLL + void rename_file(char const* oldname, char const* newname); + QPDF_DLL char* copy_string(std::string const&); diff --git a/libqpdf/QUtil.cc b/libqpdf/QUtil.cc index a3bf1744..db52bdb3 100644 --- a/libqpdf/QUtil.cc +++ b/libqpdf/QUtil.cc @@ -394,15 +394,14 @@ QUtil::os_wrapper(std::string const& description, int status) return status; } -FILE* -QUtil::safe_fopen(char const* filename, char const* mode) -{ - FILE* f = 0; #ifdef _WIN32 +static PointerHolder +win_convert_filename(char const* filename) +{ // Convert the utf-8 encoded filename argument to wchar_t*. First, // convert to utf16, then to wchar_t*. Note that u16 will start // with the UTF16 marker, which we skip. - std::string u16 = utf8_to_utf16(filename); + std::string u16 = QUtil::utf8_to_utf16(filename); size_t len = u16.length(); size_t wlen = (len / 2) - 1; PointerHolder wfilenamep(true, new wchar_t[wlen + 1]); @@ -415,6 +414,17 @@ QUtil::safe_fopen(char const* filename, char const* mode) (static_cast(u16.at(i)) << 8) + static_cast(u16.at(i+1))); } + return wfilenamep; +} +#endif + +FILE* +QUtil::safe_fopen(char const* filename, char const* mode) +{ + FILE* f = 0; +#ifdef _WIN32 + PointerHolder wfilenamep = win_convert_filename(filename); + wchar_t* wfilename = wfilenamep.getPointer(); PointerHolder wmodep(true, new wchar_t[strlen(mode) + 1]); wchar_t* wmode = wmodep.getPointer(); wmode[strlen(mode)] = 0; @@ -537,6 +547,40 @@ QUtil::same_file(char const* name1, char const* name2) return false; } + +void +QUtil::remove_file(char const* path) +{ +#ifdef _WIN32 + PointerHolder wpath = win_convert_filename(path); + os_wrapper(std::string("remove ") + path, _wunlink(wpath.getPointer())); +#else + os_wrapper(std::string("remove ") + path, unlink(path)); +#endif +} + +void +QUtil::rename_file(char const* oldname, char const* newname) +{ +#ifdef _WIN32 + try + { + remove_file(newname); + } + catch (QPDFSystemError&) + { + // ignore + } + PointerHolder wold = win_convert_filename(oldname); + PointerHolder wnew = win_convert_filename(newname); + os_wrapper(std::string("rename ") + oldname + " " + newname, + _wrename(wold.getPointer(), wnew.getPointer())); +#else + os_wrapper(std::string("rename ") + oldname + " " + newname, + rename(oldname, newname)); +#endif +} + char* QUtil::copy_string(std::string const& str) { diff --git a/libtests/qtest/qutil/qutil.out b/libtests/qtest/qutil/qutil.out index 763654bb..5fe841ac 100644 --- a/libtests/qtest/qutil/qutil.out +++ b/libtests/qtest/qutil/qutil.out @@ -99,3 +99,9 @@ read 24652 bytes ---- hex encode/decode begin hex encode/decode end hex encode/decode +---- rename/delete +create file +rename file +create file +rename over existing +delete file diff --git a/libtests/qutil.cc b/libtests/qutil.cc index ed605a1d..3c87cd31 100644 --- a/libtests/qutil.cc +++ b/libtests/qutil.cc @@ -457,6 +457,57 @@ void hex_encode_decode_test() std::cout << "end hex encode/decode\n"; } +static void assert_no_file(char const* filename) +{ + try + { + fclose(QUtil::safe_fopen(filename, "r")); + assert(false); + } + catch (QPDFSystemError&) + { + } +} + +void rename_delete_test() +{ + PointerHolder buf; + size_t size = 0; + + try + { + QUtil::remove_file("old\xcf\x80"); + } + catch (QPDFSystemError&) + { + } + assert_no_file("old\xcf\x80"); + std::cout << "create file" << std::endl;; + FILE* f1 = QUtil::safe_fopen("old\xcf\x80", "w"); + fprintf(f1, "one"); + fclose(f1); + QUtil::read_file_into_memory("old\xcf\x80", buf, size); + assert(memcmp(buf.getPointer(), "one", 3) == 0); + std::cout << "rename file" << std::endl;; + QUtil::rename_file("old\xcf\x80", "old\xcf\x80.~tmp"); + QUtil::read_file_into_memory("old\xcf\x80.~tmp", buf, size); + assert(memcmp(buf.getPointer(), "one", 3) == 0); + assert_no_file("old\xcf\x80"); + std::cout << "create file" << std::endl;; + f1 = QUtil::safe_fopen("old\xcf\x80", "w"); + fprintf(f1, "two"); + fclose(f1); + std::cout << "rename over existing" << std::endl;; + QUtil::rename_file("old\xcf\x80", "old\xcf\x80.~tmp"); + QUtil::read_file_into_memory("old\xcf\x80.~tmp", buf, size); + assert(memcmp(buf.getPointer(), "two", 3) == 0); + assert_no_file("old\xcf\x80"); + std::cout << "delete file" << std::endl;; + QUtil::remove_file("old\xcf\x80.~tmp"); + assert_no_file("old\xcf\x80"); + assert_no_file("old\xcf\x80.~tmp"); +} + int main(int argc, char* argv[]) { try @@ -485,6 +536,8 @@ int main(int argc, char* argv[]) read_from_file_test(); std::cout << "---- hex encode/decode" << std::endl; hex_encode_decode_test(); + std::cout << "---- rename/delete" << std::endl; + rename_delete_test(); } catch (std::exception& e) {