|
35 | 35 | #include <ctype.h> |
36 | 36 | #endif // _WIN32 |
37 | 37 |
|
| 38 | +#include <filesystem> |
| 39 | + |
38 | 40 | #include "FreeImage.h" |
39 | 41 | #include "Utilities.h" |
40 | 42 | #include "FreeImageIO.h" |
@@ -769,41 +771,107 @@ FreeImage_SaveToHandle(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, FreeImageIO *io, fi |
769 | 771 | } |
770 | 772 |
|
771 | 773 |
|
772 | | -FIBOOL DLL_CALLCONV |
773 | | -FreeImage_Save(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, const char *filename, int flags) { |
774 | | - FreeImageIO io; |
775 | | - SetDefaultIO(&io); |
| 774 | +namespace { |
776 | 775 |
|
777 | | - FIBOOL success{FALSE}; |
778 | | - if (auto *handle = fopen(filename, "w+b")) { |
779 | | - success = FreeImage_SaveToHandle(fif, dib, &io, (fi_handle)handle, flags); |
780 | 776 |
|
781 | | - fclose(handle); |
782 | | - } else { |
783 | | - FreeImage_OutputMessageProc((int)fif, "FreeImage_Save: failed to open file %s", filename); |
| 777 | + std::filesystem::path MakeRandomSuffix() |
| 778 | + { |
| 779 | + std::stringstream strs{}; |
| 780 | + strs << ".fitmp" << std::hex << static_cast<uint32_t>(std::rand()); |
| 781 | + return strs.str(); |
784 | 782 | } |
785 | 783 |
|
786 | | - return success; |
787 | | -} |
| 784 | + |
| 785 | + std::filesystem::path MakeTmpName(const std::filesystem::path& target) |
| 786 | + { |
| 787 | + std::filesystem::path res{}; |
| 788 | + |
| 789 | + int attempts = 16; |
| 790 | + do { |
| 791 | + res = target.stem(); |
| 792 | + res += MakeRandomSuffix(); |
| 793 | + res += target.extension(); |
| 794 | + |
| 795 | + if (std::filesystem::status(res).type() != std::filesystem::file_type::not_found) { |
| 796 | + continue; |
| 797 | + } |
| 798 | + |
| 799 | + } while (--attempts); |
| 800 | + |
| 801 | + return res; |
| 802 | + } |
| 803 | + |
| 804 | + |
| 805 | + bool MoveOrCopy(const std::filesystem::path& oldp, const std::filesystem::path& newp) noexcept |
| 806 | + { |
| 807 | + std::error_code err{}; |
| 808 | + std::filesystem::rename(oldp, newp, err); |
| 809 | + if (!err) { |
| 810 | + return true; |
| 811 | + } |
| 812 | + const auto copied = std::filesystem::copy_file(oldp, newp, std::filesystem::copy_options::overwrite_existing, err); |
| 813 | + if (copied) { |
| 814 | + std::filesystem::remove(oldp, err); |
| 815 | + } |
| 816 | + return copied; |
| 817 | + } |
| 818 | + |
| 819 | + |
| 820 | + FIBOOL SaveImpl(FREE_IMAGE_FORMAT fif, FIBITMAP* dib, const std::filesystem::path& filename, int flags) |
| 821 | + try |
| 822 | + { |
| 823 | + FreeImageIO io; |
| 824 | + SetDefaultIO(&io); |
| 825 | + |
| 826 | + FIBOOL success{ FALSE }; |
| 827 | + |
| 828 | + const auto tmpname = MakeTmpName(filename); |
| 829 | + if (auto* handle = FreeImage_FOpen(tmpname, "w+b")) { |
| 830 | + success = FreeImage_SaveToHandle(fif, dib, &io, (fi_handle)handle, flags); |
| 831 | + fclose(handle); |
| 832 | + |
| 833 | + if (success) { |
| 834 | + success = MoveOrCopy(tmpname, filename); |
| 835 | + if (!success) { |
| 836 | + FreeImage_OutputMessageProc((int)fif, "FreeImage_Save: failed to rename output file %s", filename.u8string().c_str()); |
| 837 | + } |
| 838 | + } |
| 839 | + else { |
| 840 | + std::error_code err{}; |
| 841 | + std::filesystem::remove(tmpname, err); |
| 842 | + } |
| 843 | + } |
| 844 | + else { |
| 845 | + FreeImage_OutputMessageProc((int)fif, "FreeImage_Save: failed to open file %s", filename.u8string().c_str()); |
| 846 | + } |
| 847 | + |
| 848 | + return success; |
| 849 | + } |
| 850 | + catch (...) { |
| 851 | + return FALSE; |
| 852 | + } |
| 853 | + |
| 854 | +} // namespace |
| 855 | + |
788 | 856 |
|
789 | 857 | FIBOOL DLL_CALLCONV |
790 | | -FreeImage_SaveU(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, const wchar_t *filename, int flags) { |
791 | | - FreeImageIO io; |
792 | | - SetDefaultIO(&io); |
| 858 | +FreeImage_Save(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, const char *filename, int flags) { |
| 859 | + if (!dib || !filename) { |
| 860 | + return FALSE; |
| 861 | + } |
| 862 | + return SaveImpl(fif, dib, filename, flags); |
| 863 | +} |
793 | 864 |
|
794 | | - FIBOOL success{FALSE}; |
795 | | -#ifdef _WIN32 |
796 | | - if (auto *handle = _wfopen(filename, L"w+b")) { |
797 | | - success = FreeImage_SaveToHandle(fif, dib, &io, (fi_handle)handle, flags); |
798 | 865 |
|
799 | | - fclose(handle); |
800 | | - } else { |
801 | | - FreeImage_OutputMessageProc((int)fif, "FreeImage_SaveU: failed to open output file"); |
| 866 | +FIBOOL DLL_CALLCONV |
| 867 | +FreeImage_SaveU(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, const wchar_t *filename, int flags) { |
| 868 | + if (!dib || !filename) { |
| 869 | + return FALSE; |
802 | 870 | } |
803 | | -#endif |
804 | | - return success; |
| 871 | + return SaveImpl(fif, dib, filename, flags); |
805 | 872 | } |
806 | 873 |
|
| 874 | + |
807 | 875 | // ===================================================================== |
808 | 876 | // Plugin construction + enable/disable functions |
809 | 877 | // ===================================================================== |
|
0 commit comments