Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions include/exiv2/basicio.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions include/exiv2/exif.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
10 changes: 8 additions & 2 deletions include/exiv2/image.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
97 changes: 51 additions & 46 deletions src/basicio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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<int>(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<int>(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)
Expand Down Expand Up @@ -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
Expand All @@ -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();
Expand Down Expand Up @@ -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<int>(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<int>(p_->wpath_.size()), t, 1024,
nullptr, nullptr);
p_->path_.assign(t, nc);
p_->path_ = path;
}
#endif

Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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<size_t>(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
Expand Down
7 changes: 7 additions & 0 deletions src/exif.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
33 changes: 30 additions & 3 deletions src/image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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<FileIo>(path);
#else
Expand All @@ -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);
Expand Down Expand Up @@ -887,6 +898,22 @@ Image::UniquePtr ImageFactory::create(ImageType type, const std::string& path) {
throw Error(ErrorCode::kerUnsupportedImageType, static_cast<int>(type));
return image;
}

#ifdef _WIN32
Image::UniquePtr ImageFactory::create(ImageType type, const std::wstring& path) {
auto fileIo = std::make_unique<FileIo>(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<int>(type));
return image;
}
#endif
#endif

Image::UniquePtr ImageFactory::create(ImageType type) {
Expand Down
Binary file added test/data/Реган.jp2
Binary file not shown.
1 change: 1 addition & 0 deletions tests/regression_tests/test_regression_allfiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion unitTests/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
Loading
Loading