diff --git a/include/exiv2/basicio.hpp b/include/exiv2/basicio.hpp index 71155136d9..485d0b913a 100644 --- a/include/exiv2/basicio.hpp +++ b/include/exiv2/basicio.hpp @@ -292,6 +292,9 @@ class EXIV2API FileIo : public BasicIo { @param path The full path of a file */ explicit FileIo(const std::string& path); +#ifdef _WIN32 + explicit FileIo(const std::wstring& path); +#endif //! Destructor. Flushes and closes an open file. ~FileIo() override; @@ -433,6 +436,9 @@ class EXIV2API FileIo : public BasicIo { @brief close the file source and set a new path. */ virtual void setPath(const std::string& path); +#ifdef _WIN32 + virtual void setPath(const std::wstring& path); +#endif //@} //! @name Accessors diff --git a/include/exiv2/image.hpp b/include/exiv2/image.hpp index 339ea37e46..273a42d153 100644 --- a/include/exiv2/image.hpp +++ b/include/exiv2/image.hpp @@ -522,7 +522,9 @@ class EXIV2API ImageFactory { read the remote file. */ static BasicIo::UniquePtr createIo(const std::string& path, bool useCurl = true); - +#ifdef _WIN32 + static BasicIo::UniquePtr createIo(const std::wstring& path); +#endif /*! @brief Create an Image subclass of the appropriate type by reading the specified file. %Image type is derived from the file @@ -537,7 +539,9 @@ class EXIV2API ImageFactory { unknown image type. */ static Image::UniquePtr open(const std::string& path, bool useCurl = true); - +#ifdef _WIN32 + static Image::UniquePtr open(const std::wstring& path); +#endif /*! @brief Create an Image subclass of the appropriate type by reading the provided memory. %Image type is derived from the memory diff --git a/src/basicio.cpp b/src/basicio.cpp index 5bbea74579..6599af2787 100644 --- a/src/basicio.cpp +++ b/src/basicio.cpp @@ -69,12 +69,18 @@ class FileIo::Impl { public: //! Constructor explicit Impl(std::string path); +#ifdef _WIN32 + explicit Impl(std::wstring path); +#endif ~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 std::string openMode_; //!< File open mode FILE* fp_{}; //!< File stream pointer OpMode opMode_{opSeek}; //!< File open mode @@ -110,7 +116,19 @@ class FileIo::Impl { }; 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); } +#endif int FileIo::Impl::switchMode(OpMode opMode) { if (opMode_ == opMode) @@ -159,7 +177,11 @@ int FileIo::Impl::switchMode(OpMode opMode) { std::fclose(fp_); openMode_ = "r+b"; opMode_ = opSeek; +#ifdef _WIN32 + fp_ = _wfopen(wpath_.c_str(), L"r+b"); +#else fp_ = std::fopen(path_.c_str(), openMode_.c_str()); +#endif if (!fp_) return 1; #ifdef _WIN32 @@ -170,6 +192,15 @@ int FileIo::Impl::switchMode(OpMode opMode) { } // FileIo::Impl::switchMode int FileIo::Impl::stat(StructStat& buf) const { +#ifdef _WIN32 + struct _stat64 st; + auto ret = _wstat64(wpath_.c_str(), &st); + if (ret == 0) { + buf.st_size = st.st_size; + buf.st_mode = st.st_mode; + } + return ret; +#else try { buf.st_size = fs::file_size(path_); buf.st_mode = fs::status(path_).permissions(); @@ -177,10 +208,15 @@ int FileIo::Impl::stat(StructStat& buf) const { } catch (const fs::filesystem_error&) { return -1; } +#endif } // FileIo::Impl::stat FileIo::FileIo(const std::string& path) : p_(std::make_unique(path)) { } +#ifdef _WIN32 +FileIo::FileIo(const std::wstring& path) : p_(std::make_unique(path)) { +} +#endif FileIo::~FileIo() { close(); @@ -296,7 +332,22 @@ 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); } +#endif size_t FileIo::write(const byte* data, size_t wcount) { if (p_->switchMode(Impl::opWrite) != 0) @@ -480,7 +531,13 @@ int FileIo::open(const std::string& mode) { close(); p_->openMode_ = mode; p_->opMode_ = Impl::opSeek; +#ifdef _WIN32 + wchar_t wmode[10]; + MultiByteToWideChar(CP_UTF8, 0, mode.c_str(), -1, wmode, 10); + p_->fp_ = _wfopen(p_->wpath_.c_str(), wmode); +#else p_->fp_ = ::fopen(path().c_str(), mode.c_str()); +#endif if (!p_->fp_) return 1; return 0; diff --git a/src/image.cpp b/src/image.cpp index dd8774cef0..7224d14389 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -55,6 +55,10 @@ #include #endif +#ifdef _WIN32 +#include +#endif + // ***************************************************************************** namespace { using namespace Exiv2; @@ -830,6 +834,16 @@ BasicIo::UniquePtr ImageFactory::createIo(const std::string& path, [[maybe_unuse #endif } // ImageFactory::createIo +#ifdef _WIN32 +BasicIo::UniquePtr ImageFactory::createIo(const std::wstring& path) { +#ifdef EXV_ENABLE_FILESYSTEM + return std::make_unique(path); +#else + return nullptr; +#endif +} +#endif + Image::UniquePtr ImageFactory::open(const std::string& path, bool useCurl) { auto image = open(ImageFactory::createIo(path, useCurl)); // may throw if (!image) @@ -837,6 +851,18 @@ Image::UniquePtr ImageFactory::open(const std::string& path, bool useCurl) { return image; } +#ifdef _WIN32 +Image::UniquePtr ImageFactory::open(const std::wstring& path) { + auto image = open(ImageFactory::createIo(path)); // may throw + if (!image) { + char t[1024]; + WideCharToMultiByte(CP_UTF8, 0, path.c_str(), -1, t, 1024, nullptr, nullptr); + throw Error(ErrorCode::kerFileContainsUnknownImageType, t); + } + return image; +} +#endif + Image::UniquePtr ImageFactory::open(const byte* data, size_t size) { auto image = open(std::make_unique(data, size)); // may throw if (!image)