aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2019-08-31 17:00:53 +0200
committerJay Berkenbilt <ejb@ql.org>2019-08-31 21:51:04 +0200
commit4fa7b1eb606ecd749409a907ea7a47b39d48cb7b (patch)
treeb3d6eaa0e8b62e7edc0e39cfa0d56320f8daa4b7
parentcd2bd66781b13c7afef8c0111008860e6cb94ad7 (diff)
downloadqpdf-4fa7b1eb606ecd749409a907ea7a47b39d48cb7b.tar.zst
Add remove_file and rename_file to QUtil
-rw-r--r--ChangeLog4
-rw-r--r--include/qpdf/QUtil.hh7
-rw-r--r--libqpdf/QUtil.cc54
-rw-r--r--libtests/qtest/qutil/qutil.out6
-rw-r--r--libtests/qutil.cc53
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 <ejb@ql.org>
+
+ * Add methods rename_file and remove_file to QUtil.
+
2019-08-24 Jay Berkenbilt <ejb@ql.org>
* 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
@@ -111,6 +111,13 @@ namespace QUtil
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&);
// Returns lower-case hex-encoded version of the string, treating
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<wchar_t>
+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<wchar_t> wfilenamep(true, new wchar_t[wlen + 1]);
@@ -415,6 +414,17 @@ QUtil::safe_fopen(char const* filename, char const* mode)
(static_cast<unsigned char>(u16.at(i)) << 8) +
static_cast<unsigned char>(u16.at(i+1)));
}
+ return wfilenamep;
+}
+#endif
+
+FILE*
+QUtil::safe_fopen(char const* filename, char const* mode)
+{
+ FILE* f = 0;
+#ifdef _WIN32
+ PointerHolder<wchar_t> wfilenamep = win_convert_filename(filename);
+ wchar_t* wfilename = wfilenamep.getPointer();
PointerHolder<wchar_t> 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<wchar_t> 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<wchar_t> wold = win_convert_filename(oldname);
+ PointerHolder<wchar_t> 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<char> 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)
{