Commit 4fa7b1eb606ecd749409a907ea7a47b39d48cb7b
1 parent
cd2bd667
Add remove_file and rename_file to QUtil
Showing
5 changed files
with
119 additions
and
5 deletions
ChangeLog
| 1 | +2019-08-31 Jay Berkenbilt <ejb@ql.org> | ||
| 2 | + | ||
| 3 | + * Add methods rename_file and remove_file to QUtil. | ||
| 4 | + | ||
| 1 | 2019-08-24 Jay Berkenbilt <ejb@ql.org> | 5 | 2019-08-24 Jay Berkenbilt <ejb@ql.org> |
| 2 | 6 | ||
| 3 | * Add QPDF::userPasswordMatched() and QPDF::ownerPasswordMatched() | 7 | * Add QPDF::userPasswordMatched() and QPDF::ownerPasswordMatched() |
include/qpdf/QUtil.hh
| @@ -111,6 +111,13 @@ namespace QUtil | @@ -111,6 +111,13 @@ namespace QUtil | ||
| 111 | bool same_file(char const* name1, char const* name2); | 111 | bool same_file(char const* name1, char const* name2); |
| 112 | 112 | ||
| 113 | QPDF_DLL | 113 | QPDF_DLL |
| 114 | + void remove_file(char const* path); | ||
| 115 | + | ||
| 116 | + // rename_file will overwrite newname if it exists | ||
| 117 | + QPDF_DLL | ||
| 118 | + void rename_file(char const* oldname, char const* newname); | ||
| 119 | + | ||
| 120 | + QPDF_DLL | ||
| 114 | char* copy_string(std::string const&); | 121 | char* copy_string(std::string const&); |
| 115 | 122 | ||
| 116 | // Returns lower-case hex-encoded version of the string, treating | 123 | // Returns lower-case hex-encoded version of the string, treating |
libqpdf/QUtil.cc
| @@ -394,15 +394,14 @@ QUtil::os_wrapper(std::string const& description, int status) | @@ -394,15 +394,14 @@ QUtil::os_wrapper(std::string const& description, int status) | ||
| 394 | return status; | 394 | return status; |
| 395 | } | 395 | } |
| 396 | 396 | ||
| 397 | -FILE* | ||
| 398 | -QUtil::safe_fopen(char const* filename, char const* mode) | ||
| 399 | -{ | ||
| 400 | - FILE* f = 0; | ||
| 401 | #ifdef _WIN32 | 397 | #ifdef _WIN32 |
| 398 | +static PointerHolder<wchar_t> | ||
| 399 | +win_convert_filename(char const* filename) | ||
| 400 | +{ | ||
| 402 | // Convert the utf-8 encoded filename argument to wchar_t*. First, | 401 | // Convert the utf-8 encoded filename argument to wchar_t*. First, |
| 403 | // convert to utf16, then to wchar_t*. Note that u16 will start | 402 | // convert to utf16, then to wchar_t*. Note that u16 will start |
| 404 | // with the UTF16 marker, which we skip. | 403 | // with the UTF16 marker, which we skip. |
| 405 | - std::string u16 = utf8_to_utf16(filename); | 404 | + std::string u16 = QUtil::utf8_to_utf16(filename); |
| 406 | size_t len = u16.length(); | 405 | size_t len = u16.length(); |
| 407 | size_t wlen = (len / 2) - 1; | 406 | size_t wlen = (len / 2) - 1; |
| 408 | PointerHolder<wchar_t> wfilenamep(true, new wchar_t[wlen + 1]); | 407 | PointerHolder<wchar_t> wfilenamep(true, new wchar_t[wlen + 1]); |
| @@ -415,6 +414,17 @@ QUtil::safe_fopen(char const* filename, char const* mode) | @@ -415,6 +414,17 @@ QUtil::safe_fopen(char const* filename, char const* mode) | ||
| 415 | (static_cast<unsigned char>(u16.at(i)) << 8) + | 414 | (static_cast<unsigned char>(u16.at(i)) << 8) + |
| 416 | static_cast<unsigned char>(u16.at(i+1))); | 415 | static_cast<unsigned char>(u16.at(i+1))); |
| 417 | } | 416 | } |
| 417 | + return wfilenamep; | ||
| 418 | +} | ||
| 419 | +#endif | ||
| 420 | + | ||
| 421 | +FILE* | ||
| 422 | +QUtil::safe_fopen(char const* filename, char const* mode) | ||
| 423 | +{ | ||
| 424 | + FILE* f = 0; | ||
| 425 | +#ifdef _WIN32 | ||
| 426 | + PointerHolder<wchar_t> wfilenamep = win_convert_filename(filename); | ||
| 427 | + wchar_t* wfilename = wfilenamep.getPointer(); | ||
| 418 | PointerHolder<wchar_t> wmodep(true, new wchar_t[strlen(mode) + 1]); | 428 | PointerHolder<wchar_t> wmodep(true, new wchar_t[strlen(mode) + 1]); |
| 419 | wchar_t* wmode = wmodep.getPointer(); | 429 | wchar_t* wmode = wmodep.getPointer(); |
| 420 | wmode[strlen(mode)] = 0; | 430 | wmode[strlen(mode)] = 0; |
| @@ -537,6 +547,40 @@ QUtil::same_file(char const* name1, char const* name2) | @@ -537,6 +547,40 @@ QUtil::same_file(char const* name1, char const* name2) | ||
| 537 | return false; | 547 | return false; |
| 538 | } | 548 | } |
| 539 | 549 | ||
| 550 | + | ||
| 551 | +void | ||
| 552 | +QUtil::remove_file(char const* path) | ||
| 553 | +{ | ||
| 554 | +#ifdef _WIN32 | ||
| 555 | + PointerHolder<wchar_t> wpath = win_convert_filename(path); | ||
| 556 | + os_wrapper(std::string("remove ") + path, _wunlink(wpath.getPointer())); | ||
| 557 | +#else | ||
| 558 | + os_wrapper(std::string("remove ") + path, unlink(path)); | ||
| 559 | +#endif | ||
| 560 | +} | ||
| 561 | + | ||
| 562 | +void | ||
| 563 | +QUtil::rename_file(char const* oldname, char const* newname) | ||
| 564 | +{ | ||
| 565 | +#ifdef _WIN32 | ||
| 566 | + try | ||
| 567 | + { | ||
| 568 | + remove_file(newname); | ||
| 569 | + } | ||
| 570 | + catch (QPDFSystemError&) | ||
| 571 | + { | ||
| 572 | + // ignore | ||
| 573 | + } | ||
| 574 | + PointerHolder<wchar_t> wold = win_convert_filename(oldname); | ||
| 575 | + PointerHolder<wchar_t> wnew = win_convert_filename(newname); | ||
| 576 | + os_wrapper(std::string("rename ") + oldname + " " + newname, | ||
| 577 | + _wrename(wold.getPointer(), wnew.getPointer())); | ||
| 578 | +#else | ||
| 579 | + os_wrapper(std::string("rename ") + oldname + " " + newname, | ||
| 580 | + rename(oldname, newname)); | ||
| 581 | +#endif | ||
| 582 | +} | ||
| 583 | + | ||
| 540 | char* | 584 | char* |
| 541 | QUtil::copy_string(std::string const& str) | 585 | QUtil::copy_string(std::string const& str) |
| 542 | { | 586 | { |
libtests/qtest/qutil/qutil.out
| @@ -99,3 +99,9 @@ read 24652 bytes | @@ -99,3 +99,9 @@ read 24652 bytes | ||
| 99 | ---- hex encode/decode | 99 | ---- hex encode/decode |
| 100 | begin hex encode/decode | 100 | begin hex encode/decode |
| 101 | end hex encode/decode | 101 | end hex encode/decode |
| 102 | +---- rename/delete | ||
| 103 | +create file | ||
| 104 | +rename file | ||
| 105 | +create file | ||
| 106 | +rename over existing | ||
| 107 | +delete file |
libtests/qutil.cc
| @@ -457,6 +457,57 @@ void hex_encode_decode_test() | @@ -457,6 +457,57 @@ void hex_encode_decode_test() | ||
| 457 | std::cout << "end hex encode/decode\n"; | 457 | std::cout << "end hex encode/decode\n"; |
| 458 | } | 458 | } |
| 459 | 459 | ||
| 460 | +static void assert_no_file(char const* filename) | ||
| 461 | +{ | ||
| 462 | + try | ||
| 463 | + { | ||
| 464 | + fclose(QUtil::safe_fopen(filename, "r")); | ||
| 465 | + assert(false); | ||
| 466 | + } | ||
| 467 | + catch (QPDFSystemError&) | ||
| 468 | + { | ||
| 469 | + } | ||
| 470 | +} | ||
| 471 | + | ||
| 472 | +void rename_delete_test() | ||
| 473 | +{ | ||
| 474 | + PointerHolder<char> buf; | ||
| 475 | + size_t size = 0; | ||
| 476 | + | ||
| 477 | + try | ||
| 478 | + { | ||
| 479 | + QUtil::remove_file("old\xcf\x80"); | ||
| 480 | + } | ||
| 481 | + catch (QPDFSystemError&) | ||
| 482 | + { | ||
| 483 | + } | ||
| 484 | + assert_no_file("old\xcf\x80"); | ||
| 485 | + std::cout << "create file" << std::endl;; | ||
| 486 | + FILE* f1 = QUtil::safe_fopen("old\xcf\x80", "w"); | ||
| 487 | + fprintf(f1, "one"); | ||
| 488 | + fclose(f1); | ||
| 489 | + QUtil::read_file_into_memory("old\xcf\x80", buf, size); | ||
| 490 | + assert(memcmp(buf.getPointer(), "one", 3) == 0); | ||
| 491 | + std::cout << "rename file" << std::endl;; | ||
| 492 | + QUtil::rename_file("old\xcf\x80", "old\xcf\x80.~tmp"); | ||
| 493 | + QUtil::read_file_into_memory("old\xcf\x80.~tmp", buf, size); | ||
| 494 | + assert(memcmp(buf.getPointer(), "one", 3) == 0); | ||
| 495 | + assert_no_file("old\xcf\x80"); | ||
| 496 | + std::cout << "create file" << std::endl;; | ||
| 497 | + f1 = QUtil::safe_fopen("old\xcf\x80", "w"); | ||
| 498 | + fprintf(f1, "two"); | ||
| 499 | + fclose(f1); | ||
| 500 | + std::cout << "rename over existing" << std::endl;; | ||
| 501 | + QUtil::rename_file("old\xcf\x80", "old\xcf\x80.~tmp"); | ||
| 502 | + QUtil::read_file_into_memory("old\xcf\x80.~tmp", buf, size); | ||
| 503 | + assert(memcmp(buf.getPointer(), "two", 3) == 0); | ||
| 504 | + assert_no_file("old\xcf\x80"); | ||
| 505 | + std::cout << "delete file" << std::endl;; | ||
| 506 | + QUtil::remove_file("old\xcf\x80.~tmp"); | ||
| 507 | + assert_no_file("old\xcf\x80"); | ||
| 508 | + assert_no_file("old\xcf\x80.~tmp"); | ||
| 509 | +} | ||
| 510 | + | ||
| 460 | int main(int argc, char* argv[]) | 511 | int main(int argc, char* argv[]) |
| 461 | { | 512 | { |
| 462 | try | 513 | try |
| @@ -485,6 +536,8 @@ int main(int argc, char* argv[]) | @@ -485,6 +536,8 @@ int main(int argc, char* argv[]) | ||
| 485 | read_from_file_test(); | 536 | read_from_file_test(); |
| 486 | std::cout << "---- hex encode/decode" << std::endl; | 537 | std::cout << "---- hex encode/decode" << std::endl; |
| 487 | hex_encode_decode_test(); | 538 | hex_encode_decode_test(); |
| 539 | + std::cout << "---- rename/delete" << std::endl; | ||
| 540 | + rename_delete_test(); | ||
| 488 | } | 541 | } |
| 489 | catch (std::exception& e) | 542 | catch (std::exception& e) |
| 490 | { | 543 | { |