From 988628aafdf7cd6f6f4663a61a673154edd61e8b Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Sat, 26 Apr 2025 11:57:30 -0700 Subject: [PATCH 1/3] unitTests: test unicode file opening As of the last commit, unicode file opening is working on Windows for the library but not the app. Signed-off-by: Rosen Penev --- ...0\240\320\265\320\263\320\260\320\275.jp2" | Bin 0 -> 40609 bytes .../test_regression_allfiles.py | 1 + unitTests/test_ImageFactory.cpp | 24 ++++++++++-------- 3 files changed, 15 insertions(+), 10 deletions(-) create mode 100644 "test/data/\320\240\320\265\320\263\320\260\320\275.jp2" diff --git "a/test/data/\320\240\320\265\320\263\320\260\320\275.jp2" "b/test/data/\320\240\320\265\320\263\320\260\320\275.jp2" new file mode 100644 index 0000000000000000000000000000000000000000..fb011b5217b7e4c764c6c6dd3cb72712485167af GIT binary patch literal 40609 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 literal 0 HcmV?d00001 diff --git a/tests/regression_tests/test_regression_allfiles.py b/tests/regression_tests/test_regression_allfiles.py index d35a66c85b..fc49920845 100644 --- a/tests/regression_tests/test_regression_allfiles.py +++ b/tests/regression_tests/test_regression_allfiles.py @@ -58,6 +58,7 @@ def get_valid_files(data_dir): "imagemagick.pgf", "iptc-psAPP13s-wIPTC-psAPP13s-noIPTC.jpg", "Reagan.jp2", + "Реган.jp2", "issue_ghsa_8949_hhfh_j7rj_poc.exv", "exiv2-bug495.jpg", "issue_1920_poc.tiff", diff --git a/unitTests/test_ImageFactory.cpp b/unitTests/test_ImageFactory.cpp index b77d33e68b..1c43c0b451 100644 --- a/unitTests/test_ImageFactory.cpp +++ b/unitTests/test_ImageFactory.cpp @@ -100,45 +100,49 @@ TEST(TheImageFactory, cannotCreateInstancesForSomeTypesInFiles) { TEST(TheImageFactory, loadInstancesDifferentImageTypes) { fs::path testData(TESTDATA_PATH); - std::string imagePath = (testData / "DSC_3079.jpg").string(); + fs::path imagePath = testData / "DSC_3079.jpg"; EXPECT_EQ(ImageType::jpeg, ImageFactory::getType(imagePath)); EXPECT_NO_THROW(ImageFactory::open(imagePath, false)); - imagePath = (testData / "exiv2-bug1108.exv").string(); + imagePath = testData / "exiv2-bug1108.exv"; EXPECT_EQ(ImageType::exv, ImageFactory::getType(imagePath)); EXPECT_NO_THROW(ImageFactory::open(imagePath, false)); - imagePath = (testData / "exiv2-canon-powershot-s40.crw").string(); + imagePath = testData / "exiv2-canon-powershot-s40.crw"; EXPECT_EQ(ImageType::crw, ImageFactory::getType(imagePath)); EXPECT_NO_THROW(ImageFactory::open(imagePath, false)); - imagePath = (testData / "exiv2-bug1044.tif").string(); + imagePath = testData / "exiv2-bug1044.tif"; EXPECT_EQ(ImageType::tiff, ImageFactory::getType(imagePath)); EXPECT_NO_THROW(ImageFactory::open(imagePath, false)); #ifdef EXV_HAVE_LIBZ - imagePath = (testData / "exiv2-bug1074.png").string(); + imagePath = testData / "exiv2-bug1074.png"; EXPECT_EQ(ImageType::png, ImageFactory::getType(imagePath)); EXPECT_NO_THROW(ImageFactory::open(imagePath, false)); #endif - imagePath = (testData / "BlueSquare.xmp").string(); + imagePath = testData / "BlueSquare.xmp"; EXPECT_EQ(ImageType::xmp, ImageFactory::getType(imagePath)); EXPECT_NO_THROW(ImageFactory::open(imagePath, false)); - imagePath = (testData / "exiv2-photoshop.psd").string(); + imagePath = testData / "exiv2-photoshop.psd"; EXPECT_EQ(ImageType::psd, ImageFactory::getType(imagePath)); EXPECT_NO_THROW(ImageFactory::open(imagePath, false)); - imagePath = (testData / "cve_2017_1000126_stack-oob-read.webp").string(); + imagePath = testData / "cve_2017_1000126_stack-oob-read.webp"; EXPECT_EQ(ImageType::webp, ImageFactory::getType(imagePath)); EXPECT_NO_THROW(ImageFactory::open(imagePath, false)); - imagePath = (testData / "imagemagick.pgf").string(); + imagePath = testData / "imagemagick.pgf"; EXPECT_EQ(ImageType::pgf, ImageFactory::getType(imagePath)); EXPECT_NO_THROW(ImageFactory::open(imagePath, false)); - imagePath = (testData / "Reagan.jp2").string(); + imagePath = testData / "Reagan.jp2"; + EXPECT_EQ(ImageType::jp2, ImageFactory::getType(imagePath)); + EXPECT_NO_THROW(ImageFactory::open(imagePath, false)); + + imagePath = testData / "Реган.jp2"; EXPECT_EQ(ImageType::jp2, ImageFactory::getType(imagePath)); EXPECT_NO_THROW(ImageFactory::open(imagePath, false)); } From b93a8088988cb38321a25217ef3965a03d7b0a30 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Sat, 26 Apr 2025 11:57:30 -0700 Subject: [PATCH 2/3] basicio: use fs::path Makes it extremely clear where unicode file names would fail to open under Windows. Signed-off-by: Rosen Penev --- include/exiv2/basicio.hpp | 7 +++ include/exiv2/exif.hpp | 3 ++ include/exiv2/image.hpp | 10 +++- src/basicio.cpp | 97 ++++++++++++++++++++------------------- src/exif.cpp | 7 +++ src/image.cpp | 33 +++++++++++-- 6 files changed, 106 insertions(+), 51 deletions(-) diff --git a/include/exiv2/basicio.hpp b/include/exiv2/basicio.hpp index a96a166528..65d1d29e9e 100644 --- a/include/exiv2/basicio.hpp +++ b/include/exiv2/basicio.hpp @@ -941,12 +941,19 @@ class EXIV2API CurlIo : public RemoteIo { @throw Error In case of failure. */ EXIV2API DataBuf readFile(const std::string& path); +#ifdef _WIN32 +EXIV2API DataBuf readFile(const std::wstring& path); +#endif /*! @brief Write DataBuf \em buf to file \em path. @return Return the number of bytes written. @throw Error In case of failure. */ +#ifdef _WIN32 EXIV2API size_t writeFile(const DataBuf& buf, const std::string& path); +#else +EXIV2API size_t writeFile(const DataBuf& buf, const std::string& path); +#endif #ifdef EXV_USE_CURL /*! @brief The callback function is called by libcurl to write the data diff --git a/include/exiv2/exif.hpp b/include/exiv2/exif.hpp index 480c3f2185..8ce7c3cea2 100644 --- a/include/exiv2/exif.hpp +++ b/include/exiv2/exif.hpp @@ -303,6 +303,9 @@ class EXIV2API ExifThumb : public ExifThumbC { application that comes with OS X for one.) - David Harvey. */ void setJpegThumbnail(const std::string& path, URational xres, URational yres, uint16_t unit); +#ifdef _WIN32 + void setJpegThumbnail(const std::wstring& path, URational xres, URational yres, uint16_t unit); +#endif #endif /*! @brief Set the Exif thumbnail to the JPEG image pointed to by \em buf, diff --git a/include/exiv2/image.hpp b/include/exiv2/image.hpp index 00bfe40c6c..5fef008833 100644 --- a/include/exiv2/image.hpp +++ b/include/exiv2/image.hpp @@ -538,7 +538,7 @@ class EXIV2API ImageFactory { */ static BasicIo::UniquePtr createIo(const std::string& path, bool useCurl = true); #ifdef _WIN32 - static BasicIo::UniquePtr createIo(const std::wstring& path); + static BasicIo::UniquePtr createIo(const std::wstring& path, bool useCurl = true); #endif /*! @brief Create an Image subclass of the appropriate type by reading @@ -555,7 +555,7 @@ class EXIV2API ImageFactory { */ static Image::UniquePtr open(const std::string& path, bool useCurl = true); #ifdef _WIN32 - static Image::UniquePtr open(const std::wstring& path); + static Image::UniquePtr open(const std::wstring& path, bool useCurl = true); #endif /*! @brief Create an Image subclass of the appropriate type by reading @@ -597,6 +597,9 @@ class EXIV2API ImageFactory { @throw Error If the image type is not supported. */ static Image::UniquePtr create(ImageType type, const std::string& path); +#ifdef _WIN32 + static Image::UniquePtr create(ImageType type, const std::wstring& path); +#endif /*! @brief Create an Image subclass of the requested type by creating a new image in memory. @@ -630,6 +633,9 @@ class EXIV2API ImageFactory { @return %Image type or Image::none if the type is not recognized. */ static ImageType getType(const std::string& path); +#ifdef _WIN32 + static ImageType getType(const std::wstring& path); +#endif /*! @brief Returns the image type of the provided data buffer. @param data Pointer to a data buffer containing an image. The contents diff --git a/src/basicio.cpp b/src/basicio.cpp index e44c0372b8..b82ec282bd 100644 --- a/src/basicio.cpp +++ b/src/basicio.cpp @@ -68,19 +68,13 @@ void BasicIo::seekOrThrow(int64_t offset, Position pos, ErrorCode err) { class FileIo::Impl { public: //! Constructor - explicit Impl(std::string path); -#ifdef _WIN32 - explicit Impl(std::wstring path); -#endif + explicit Impl(fs::path path); ~Impl() = default; // Enumerations //! Mode of operation enum OpMode { opRead, opWrite, opSeek }; // DATA - std::string path_; //!< (Standard) path -#ifdef _WIN32 - std::wstring wpath_; //!< UCS2 path -#endif + fs::path path_; //!< (Standard) path std::string openMode_; //!< File open mode FILE* fp_{}; //!< File stream pointer OpMode opMode_{opSeek}; //!< File open mode @@ -114,21 +108,8 @@ class FileIo::Impl { Impl& operator=(const Impl&) = delete; //!< Assignment }; -FileIo::Impl::Impl(std::string path) : path_(std::move(path)) { -#ifdef _WIN32 - wchar_t t[512]; - const auto nw = MultiByteToWideChar(CP_UTF8, 0, path_.data(), static_cast(path_.size()), t, 512); - wpath_.assign(t, nw); -#endif -} -#ifdef _WIN32 -FileIo::Impl::Impl(std::wstring path) : wpath_(std::move(path)) { - char t[1024]; - const auto nc = - WideCharToMultiByte(CP_UTF8, 0, wpath_.data(), static_cast(wpath_.size()), t, 1024, nullptr, nullptr); - path_.assign(t, nc); +FileIo::Impl::Impl(fs::path path) : path_(std::move(path)) { } -#endif int FileIo::Impl::switchMode(OpMode opMode) { if (opMode_ == opMode) @@ -178,7 +159,7 @@ int FileIo::Impl::switchMode(OpMode opMode) { openMode_ = "r+b"; opMode_ = opSeek; #ifdef _WIN32 - if (_wfopen_s(&fp_, wpath_.c_str(), L"r+b")) + if (_wfopen_s(&fp_, path_.c_str(), L"r+b")) return 1; return _fseeki64(fp_, offset, SEEK_SET); #else @@ -190,11 +171,7 @@ int FileIo::Impl::switchMode(OpMode opMode) { } // FileIo::Impl::switchMode int FileIo::Impl::stat(StructStat& buf) const { -#ifdef _WIN32 - const auto& file = wpath_; -#else const auto& file = path_; -#endif try { buf.st_size = fs::file_size(file); buf.st_mode = fs::status(file).permissions(); @@ -321,21 +298,12 @@ byte* FileIo::mmap(bool isWriteable) { void FileIo::setPath(const std::string& path) { close(); p_->path_ = path; -#ifdef _WIN32 - wchar_t t[512]; - const auto nw = MultiByteToWideChar(CP_UTF8, 0, p_->path_.data(), static_cast(p_->path_.size()), t, 512); - p_->wpath_.assign(t, nw); -#endif } #ifdef _WIN32 void FileIo::setPath(const std::wstring& path) { close(); - p_->wpath_ = path; - char t[1024]; - const auto nc = WideCharToMultiByte(CP_UTF8, 0, p_->wpath_.data(), static_cast(p_->wpath_.size()), t, 1024, - nullptr, nullptr); - p_->path_.assign(t, nc); + p_->path_ = path; } #endif @@ -447,7 +415,7 @@ void FileIo::transfer(BasicIo& src) { if (wasOpen) { if (open(lastMode) != 0) { - throw Error(ErrorCode::kerFileOpenFailed, path(), lastMode, strError()); + throw Error(ErrorCode::kerFileOpenFailed, path(), strError()); } } else close(); @@ -522,15 +490,28 @@ int FileIo::open(const std::string& mode) { p_->openMode_ = mode; p_->opMode_ = Impl::opSeek; #ifdef _WIN32 - wchar_t wmode[10]; - MultiByteToWideChar(CP_UTF8, 0, mode.c_str(), -1, wmode, 10); - if (_wfopen_s(&p_->fp_, p_->wpath_.c_str(), wmode)) - return 1; + auto wMode = [&] { + if (mode == "ab") + return L"ab"; + if (mode == "rb") + return L"rb"; + if (mode == "wb") + return L"wb"; + if (mode == "a+b") + return L"a+b"; + if (mode == "r+b") + return L"r+b"; + if (mode == "w+b") + return L"w+b"; + return L""; + }(); + + if (_wfopen_s(&p_->fp_, p_->path_.c_str(), wMode)) #else - p_->fp_ = ::fopen(path().c_str(), mode.c_str()); + p_->fp_ = std::fopen(path().c_str(), mode.c_str()); if (!p_->fp_) - return 1; #endif + return 1; return 0; } @@ -584,7 +565,9 @@ bool FileIo::eof() const { } const std::string& FileIo::path() const noexcept { - return p_->path_; + static thread_local std::string p; + p = p_->path_.string(); + return p; } void FileIo::populateFakeData() { @@ -871,7 +854,7 @@ bool MemIo::eof() const { } const std::string& MemIo::path() const noexcept { - static std::string _path{"MemIo"}; + static const std::string _path{"MemIo"}; return _path; } @@ -1678,6 +1661,28 @@ size_t writeFile(const DataBuf& buf, const std::string& path) { } return file.write(buf.c_data(), buf.size()); } + +#ifdef _WIN32 +DataBuf readFile(const std::wstring& path) { + FileIo file(path); + if (file.open("rb") != 0) { + throw Error(ErrorCode::kerFileOpenFailed, "rb", strError()); + } + DataBuf buf(static_cast(fs::file_size(path))); + if (file.read(buf.data(), buf.size()) != buf.size()) { + throw Error(ErrorCode::kerCallFailed, strError(), "FileIo::read"); + } + return buf; +} + +size_t writeFile(const DataBuf& buf, const std::wstring& path) { + FileIo file(path); + if (file.open("wb") != 0) { + throw Error(ErrorCode::kerFileOpenFailed, "wb", strError()); + } + return file.write(buf.c_data(), buf.size()); +} +#endif #endif #ifdef EXV_USE_CURL diff --git a/src/exif.cpp b/src/exif.cpp index ad489238a2..96b2dd63fb 100644 --- a/src/exif.cpp +++ b/src/exif.cpp @@ -411,6 +411,13 @@ void ExifThumb::setJpegThumbnail(const std::string& path, URational xres, URatio DataBuf thumb = readFile(path); // may throw setJpegThumbnail(thumb.c_data(), thumb.size(), xres, yres, unit); } + +#ifdef _WIN32 +void ExifThumb::setJpegThumbnail(const std::wstring& path, URational xres, URational yres, uint16_t unit) { + DataBuf thumb = readFile(path); // may throw + setJpegThumbnail(thumb.c_data(), thumb.size(), xres, yres, unit); +} +#endif #endif void ExifThumb::setJpegThumbnail(const byte* buf, size_t size, URational xres, URational yres, uint16_t unit) { diff --git a/src/image.cpp b/src/image.cpp index eaa78c8fd4..038d61ff0d 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -782,6 +782,17 @@ ImageType ImageFactory::getType([[maybe_unused]] const std::string& path) { #endif } +#ifdef _WIN32 +ImageType ImageFactory::getType([[maybe_unused]] const std::wstring& path) { +#ifdef EXV_ENABLE_FILESYSTEM + FileIo fileIo(path); + return getType(fileIo); +#else + return ImageType::none; +#endif +} +#endif + ImageType ImageFactory::getType(const byte* data, size_t size) { MemIo memIo(data, size); return getType(memIo); @@ -825,7 +836,7 @@ BasicIo::UniquePtr ImageFactory::createIo(const std::string& path, [[maybe_unuse } // ImageFactory::createIo #ifdef _WIN32 -BasicIo::UniquePtr ImageFactory::createIo(const std::wstring& path) { +BasicIo::UniquePtr ImageFactory::createIo(const std::wstring& path, bool) { #ifdef EXV_ENABLE_FILESYSTEM return std::make_unique(path); #else @@ -842,8 +853,8 @@ Image::UniquePtr ImageFactory::open(const std::string& path, bool useCurl) { } #ifdef _WIN32 -Image::UniquePtr ImageFactory::open(const std::wstring& path) { - auto image = open(ImageFactory::createIo(path)); // may throw +Image::UniquePtr ImageFactory::open(const std::wstring& path, bool useCurl) { + auto image = open(ImageFactory::createIo(path, useCurl)); // may throw if (!image) { char t[1024]; WideCharToMultiByte(CP_UTF8, 0, path.c_str(), -1, t, 1024, nullptr, nullptr); @@ -887,6 +898,22 @@ Image::UniquePtr ImageFactory::create(ImageType type, const std::string& path) { throw Error(ErrorCode::kerUnsupportedImageType, static_cast(type)); return image; } + +#ifdef _WIN32 +Image::UniquePtr ImageFactory::create(ImageType type, const std::wstring& path) { + auto fileIo = std::make_unique(path); + // Create or overwrite the file, then close it + if (fileIo->open("w+b") != 0) + throw Error(ErrorCode::kerFileOpenFailed, "w+b", strError()); + fileIo->close(); + + BasicIo::UniquePtr io(std::move(fileIo)); + auto image = create(type, std::move(io)); + if (!image) + throw Error(ErrorCode::kerUnsupportedImageType, static_cast(type)); + return image; +} +#endif #endif Image::UniquePtr ImageFactory::create(ImageType type) { From 2d78b8e47ecc5fbe44d752f727dd89d6ce05df03 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Mon, 20 Oct 2025 13:59:35 -0700 Subject: [PATCH 3/3] hrmm --- unitTests/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unitTests/meson.build b/unitTests/meson.build index b1b5b0d49d..f5534c3a2e 100644 --- a/unitTests/meson.build +++ b/unitTests/meson.build @@ -48,7 +48,7 @@ if host_machine.system() == 'windows' and get_option('default_library') != 'stat test_sources += int_lib endif -t_args = ['-UEXIV2API', '-DEXIV2API=', '-DTESTDATA_PATH="@0@"'.format(meson.current_source_dir() / '..' / 'test' / 'data')] +t_args = ['-UEXIV2API', '-DEXIV2API=', '-DTESTDATA_PATH="@0@/"'.format(meson.current_source_dir() / '..' / 'test' / 'data')] unit_tests = executable( 'unit_tests',