Skip to content

Commit b93a808

Browse files
committed
basicio: use fs::path
Makes it extremely clear where unicode file names would fail to open under Windows. Signed-off-by: Rosen Penev <[email protected]>
1 parent 988628a commit b93a808

File tree

6 files changed

+106
-51
lines changed

6 files changed

+106
-51
lines changed

include/exiv2/basicio.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -941,12 +941,19 @@ class EXIV2API CurlIo : public RemoteIo {
941941
@throw Error In case of failure.
942942
*/
943943
EXIV2API DataBuf readFile(const std::string& path);
944+
#ifdef _WIN32
945+
EXIV2API DataBuf readFile(const std::wstring& path);
946+
#endif
944947
/*!
945948
@brief Write DataBuf \em buf to file \em path.
946949
@return Return the number of bytes written.
947950
@throw Error In case of failure.
948951
*/
952+
#ifdef _WIN32
949953
EXIV2API size_t writeFile(const DataBuf& buf, const std::string& path);
954+
#else
955+
EXIV2API size_t writeFile(const DataBuf& buf, const std::string& path);
956+
#endif
950957
#ifdef EXV_USE_CURL
951958
/*!
952959
@brief The callback function is called by libcurl to write the data

include/exiv2/exif.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,9 @@ class EXIV2API ExifThumb : public ExifThumbC {
303303
application that comes with OS X for one.) - David Harvey.
304304
*/
305305
void setJpegThumbnail(const std::string& path, URational xres, URational yres, uint16_t unit);
306+
#ifdef _WIN32
307+
void setJpegThumbnail(const std::wstring& path, URational xres, URational yres, uint16_t unit);
308+
#endif
306309
#endif
307310
/*!
308311
@brief Set the Exif thumbnail to the JPEG image pointed to by \em buf,

include/exiv2/image.hpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ class EXIV2API ImageFactory {
538538
*/
539539
static BasicIo::UniquePtr createIo(const std::string& path, bool useCurl = true);
540540
#ifdef _WIN32
541-
static BasicIo::UniquePtr createIo(const std::wstring& path);
541+
static BasicIo::UniquePtr createIo(const std::wstring& path, bool useCurl = true);
542542
#endif
543543
/*!
544544
@brief Create an Image subclass of the appropriate type by reading
@@ -555,7 +555,7 @@ class EXIV2API ImageFactory {
555555
*/
556556
static Image::UniquePtr open(const std::string& path, bool useCurl = true);
557557
#ifdef _WIN32
558-
static Image::UniquePtr open(const std::wstring& path);
558+
static Image::UniquePtr open(const std::wstring& path, bool useCurl = true);
559559
#endif
560560
/*!
561561
@brief Create an Image subclass of the appropriate type by reading
@@ -597,6 +597,9 @@ class EXIV2API ImageFactory {
597597
@throw Error If the image type is not supported.
598598
*/
599599
static Image::UniquePtr create(ImageType type, const std::string& path);
600+
#ifdef _WIN32
601+
static Image::UniquePtr create(ImageType type, const std::wstring& path);
602+
#endif
600603
/*!
601604
@brief Create an Image subclass of the requested type by creating a
602605
new image in memory.
@@ -630,6 +633,9 @@ class EXIV2API ImageFactory {
630633
@return %Image type or Image::none if the type is not recognized.
631634
*/
632635
static ImageType getType(const std::string& path);
636+
#ifdef _WIN32
637+
static ImageType getType(const std::wstring& path);
638+
#endif
633639
/*!
634640
@brief Returns the image type of the provided data buffer.
635641
@param data Pointer to a data buffer containing an image. The contents

src/basicio.cpp

Lines changed: 51 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -68,19 +68,13 @@ void BasicIo::seekOrThrow(int64_t offset, Position pos, ErrorCode err) {
6868
class FileIo::Impl {
6969
public:
7070
//! Constructor
71-
explicit Impl(std::string path);
72-
#ifdef _WIN32
73-
explicit Impl(std::wstring path);
74-
#endif
71+
explicit Impl(fs::path path);
7572
~Impl() = default;
7673
// Enumerations
7774
//! Mode of operation
7875
enum OpMode { opRead, opWrite, opSeek };
7976
// DATA
80-
std::string path_; //!< (Standard) path
81-
#ifdef _WIN32
82-
std::wstring wpath_; //!< UCS2 path
83-
#endif
77+
fs::path path_; //!< (Standard) path
8478
std::string openMode_; //!< File open mode
8579
FILE* fp_{}; //!< File stream pointer
8680
OpMode opMode_{opSeek}; //!< File open mode
@@ -114,21 +108,8 @@ class FileIo::Impl {
114108
Impl& operator=(const Impl&) = delete; //!< Assignment
115109
};
116110

117-
FileIo::Impl::Impl(std::string path) : path_(std::move(path)) {
118-
#ifdef _WIN32
119-
wchar_t t[512];
120-
const auto nw = MultiByteToWideChar(CP_UTF8, 0, path_.data(), static_cast<int>(path_.size()), t, 512);
121-
wpath_.assign(t, nw);
122-
#endif
123-
}
124-
#ifdef _WIN32
125-
FileIo::Impl::Impl(std::wstring path) : wpath_(std::move(path)) {
126-
char t[1024];
127-
const auto nc =
128-
WideCharToMultiByte(CP_UTF8, 0, wpath_.data(), static_cast<int>(wpath_.size()), t, 1024, nullptr, nullptr);
129-
path_.assign(t, nc);
111+
FileIo::Impl::Impl(fs::path path) : path_(std::move(path)) {
130112
}
131-
#endif
132113

133114
int FileIo::Impl::switchMode(OpMode opMode) {
134115
if (opMode_ == opMode)
@@ -178,7 +159,7 @@ int FileIo::Impl::switchMode(OpMode opMode) {
178159
openMode_ = "r+b";
179160
opMode_ = opSeek;
180161
#ifdef _WIN32
181-
if (_wfopen_s(&fp_, wpath_.c_str(), L"r+b"))
162+
if (_wfopen_s(&fp_, path_.c_str(), L"r+b"))
182163
return 1;
183164
return _fseeki64(fp_, offset, SEEK_SET);
184165
#else
@@ -190,11 +171,7 @@ int FileIo::Impl::switchMode(OpMode opMode) {
190171
} // FileIo::Impl::switchMode
191172

192173
int FileIo::Impl::stat(StructStat& buf) const {
193-
#ifdef _WIN32
194-
const auto& file = wpath_;
195-
#else
196174
const auto& file = path_;
197-
#endif
198175
try {
199176
buf.st_size = fs::file_size(file);
200177
buf.st_mode = fs::status(file).permissions();
@@ -321,21 +298,12 @@ byte* FileIo::mmap(bool isWriteable) {
321298
void FileIo::setPath(const std::string& path) {
322299
close();
323300
p_->path_ = path;
324-
#ifdef _WIN32
325-
wchar_t t[512];
326-
const auto nw = MultiByteToWideChar(CP_UTF8, 0, p_->path_.data(), static_cast<int>(p_->path_.size()), t, 512);
327-
p_->wpath_.assign(t, nw);
328-
#endif
329301
}
330302

331303
#ifdef _WIN32
332304
void FileIo::setPath(const std::wstring& path) {
333305
close();
334-
p_->wpath_ = path;
335-
char t[1024];
336-
const auto nc = WideCharToMultiByte(CP_UTF8, 0, p_->wpath_.data(), static_cast<int>(p_->wpath_.size()), t, 1024,
337-
nullptr, nullptr);
338-
p_->path_.assign(t, nc);
306+
p_->path_ = path;
339307
}
340308
#endif
341309

@@ -447,7 +415,7 @@ void FileIo::transfer(BasicIo& src) {
447415

448416
if (wasOpen) {
449417
if (open(lastMode) != 0) {
450-
throw Error(ErrorCode::kerFileOpenFailed, path(), lastMode, strError());
418+
throw Error(ErrorCode::kerFileOpenFailed, path(), strError());
451419
}
452420
} else
453421
close();
@@ -522,15 +490,28 @@ int FileIo::open(const std::string& mode) {
522490
p_->openMode_ = mode;
523491
p_->opMode_ = Impl::opSeek;
524492
#ifdef _WIN32
525-
wchar_t wmode[10];
526-
MultiByteToWideChar(CP_UTF8, 0, mode.c_str(), -1, wmode, 10);
527-
if (_wfopen_s(&p_->fp_, p_->wpath_.c_str(), wmode))
528-
return 1;
493+
auto wMode = [&] {
494+
if (mode == "ab")
495+
return L"ab";
496+
if (mode == "rb")
497+
return L"rb";
498+
if (mode == "wb")
499+
return L"wb";
500+
if (mode == "a+b")
501+
return L"a+b";
502+
if (mode == "r+b")
503+
return L"r+b";
504+
if (mode == "w+b")
505+
return L"w+b";
506+
return L"";
507+
}();
508+
509+
if (_wfopen_s(&p_->fp_, p_->path_.c_str(), wMode))
529510
#else
530-
p_->fp_ = ::fopen(path().c_str(), mode.c_str());
511+
p_->fp_ = std::fopen(path().c_str(), mode.c_str());
531512
if (!p_->fp_)
532-
return 1;
533513
#endif
514+
return 1;
534515
return 0;
535516
}
536517

@@ -584,7 +565,9 @@ bool FileIo::eof() const {
584565
}
585566

586567
const std::string& FileIo::path() const noexcept {
587-
return p_->path_;
568+
static thread_local std::string p;
569+
p = p_->path_.string();
570+
return p;
588571
}
589572

590573
void FileIo::populateFakeData() {
@@ -871,7 +854,7 @@ bool MemIo::eof() const {
871854
}
872855

873856
const std::string& MemIo::path() const noexcept {
874-
static std::string _path{"MemIo"};
857+
static const std::string _path{"MemIo"};
875858
return _path;
876859
}
877860

@@ -1678,6 +1661,28 @@ size_t writeFile(const DataBuf& buf, const std::string& path) {
16781661
}
16791662
return file.write(buf.c_data(), buf.size());
16801663
}
1664+
1665+
#ifdef _WIN32
1666+
DataBuf readFile(const std::wstring& path) {
1667+
FileIo file(path);
1668+
if (file.open("rb") != 0) {
1669+
throw Error(ErrorCode::kerFileOpenFailed, "rb", strError());
1670+
}
1671+
DataBuf buf(static_cast<size_t>(fs::file_size(path)));
1672+
if (file.read(buf.data(), buf.size()) != buf.size()) {
1673+
throw Error(ErrorCode::kerCallFailed, strError(), "FileIo::read");
1674+
}
1675+
return buf;
1676+
}
1677+
1678+
size_t writeFile(const DataBuf& buf, const std::wstring& path) {
1679+
FileIo file(path);
1680+
if (file.open("wb") != 0) {
1681+
throw Error(ErrorCode::kerFileOpenFailed, "wb", strError());
1682+
}
1683+
return file.write(buf.c_data(), buf.size());
1684+
}
1685+
#endif
16811686
#endif
16821687

16831688
#ifdef EXV_USE_CURL

src/exif.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,13 @@ void ExifThumb::setJpegThumbnail(const std::string& path, URational xres, URatio
411411
DataBuf thumb = readFile(path); // may throw
412412
setJpegThumbnail(thumb.c_data(), thumb.size(), xres, yres, unit);
413413
}
414+
415+
#ifdef _WIN32
416+
void ExifThumb::setJpegThumbnail(const std::wstring& path, URational xres, URational yres, uint16_t unit) {
417+
DataBuf thumb = readFile(path); // may throw
418+
setJpegThumbnail(thumb.c_data(), thumb.size(), xres, yres, unit);
419+
}
420+
#endif
414421
#endif
415422

416423
void ExifThumb::setJpegThumbnail(const byte* buf, size_t size, URational xres, URational yres, uint16_t unit) {

src/image.cpp

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,17 @@ ImageType ImageFactory::getType([[maybe_unused]] const std::string& path) {
782782
#endif
783783
}
784784

785+
#ifdef _WIN32
786+
ImageType ImageFactory::getType([[maybe_unused]] const std::wstring& path) {
787+
#ifdef EXV_ENABLE_FILESYSTEM
788+
FileIo fileIo(path);
789+
return getType(fileIo);
790+
#else
791+
return ImageType::none;
792+
#endif
793+
}
794+
#endif
795+
785796
ImageType ImageFactory::getType(const byte* data, size_t size) {
786797
MemIo memIo(data, size);
787798
return getType(memIo);
@@ -825,7 +836,7 @@ BasicIo::UniquePtr ImageFactory::createIo(const std::string& path, [[maybe_unuse
825836
} // ImageFactory::createIo
826837

827838
#ifdef _WIN32
828-
BasicIo::UniquePtr ImageFactory::createIo(const std::wstring& path) {
839+
BasicIo::UniquePtr ImageFactory::createIo(const std::wstring& path, bool) {
829840
#ifdef EXV_ENABLE_FILESYSTEM
830841
return std::make_unique<FileIo>(path);
831842
#else
@@ -842,8 +853,8 @@ Image::UniquePtr ImageFactory::open(const std::string& path, bool useCurl) {
842853
}
843854

844855
#ifdef _WIN32
845-
Image::UniquePtr ImageFactory::open(const std::wstring& path) {
846-
auto image = open(ImageFactory::createIo(path)); // may throw
856+
Image::UniquePtr ImageFactory::open(const std::wstring& path, bool useCurl) {
857+
auto image = open(ImageFactory::createIo(path, useCurl)); // may throw
847858
if (!image) {
848859
char t[1024];
849860
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) {
887898
throw Error(ErrorCode::kerUnsupportedImageType, static_cast<int>(type));
888899
return image;
889900
}
901+
902+
#ifdef _WIN32
903+
Image::UniquePtr ImageFactory::create(ImageType type, const std::wstring& path) {
904+
auto fileIo = std::make_unique<FileIo>(path);
905+
// Create or overwrite the file, then close it
906+
if (fileIo->open("w+b") != 0)
907+
throw Error(ErrorCode::kerFileOpenFailed, "w+b", strError());
908+
fileIo->close();
909+
910+
BasicIo::UniquePtr io(std::move(fileIo));
911+
auto image = create(type, std::move(io));
912+
if (!image)
913+
throw Error(ErrorCode::kerUnsupportedImageType, static_cast<int>(type));
914+
return image;
915+
}
916+
#endif
890917
#endif
891918

892919
Image::UniquePtr ImageFactory::create(ImageType type) {

0 commit comments

Comments
 (0)