Skip to content

Commit e6e4dc3

Browse files
committed
fixup wstring functions to use fs::path
Signed-off-by: Rosen Penev <[email protected]>
1 parent 5a1c3b1 commit e6e4dc3

File tree

7 files changed

+118
-27
lines changed

7 files changed

+118
-27
lines changed

include/exiv2/basicio.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,9 @@ class EXIV2API FileIo : public BasicIo {
310310
Nonzero if failure.
311311
*/
312312
int open(const std::string& mode);
313+
#ifdef _WIN32
314+
int open(const std::wstring& mode);
315+
#endif
313316
/*!
314317
@brief Open the file using the default access mode of "rb".
315318
This method can also be used to "reopen" a file which will flush
@@ -941,6 +944,9 @@ class EXIV2API CurlIo : public RemoteIo {
941944
@throw Error In case of failure.
942945
*/
943946
EXIV2API DataBuf readFile(const std::string& path);
947+
#ifdef _WIN32
948+
EXIV2API DataBuf readFile(const std::wstring& path);
949+
#endif
944950
/*!
945951
@brief Write DataBuf \em buf to file \em path.
946952
@return Return the number of bytes written.

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: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,11 @@ class FileIo::Impl {
7474
//! Mode of operation
7575
enum OpMode { opRead, opWrite, opSeek };
7676
// DATA
77-
fs::path path_; //!< (Standard) path
78-
std::string openMode_; //!< File open mode
79-
FILE* fp_{}; //!< File stream pointer
80-
OpMode opMode_{opSeek}; //!< File open mode
77+
fs::path path_; //!< (Standard) path
78+
std::string openMode_; //!< File open mode
79+
std::wstring wOpenMode_; //!< File open mode (wide)
80+
FILE* fp_{}; //!< File stream pointer
81+
OpMode opMode_{opSeek}; //!< File open mode
8182

8283
#ifdef _WIN32
8384
HANDLE hFile_{}; //!< Duplicated fd
@@ -119,6 +120,19 @@ int FileIo::Impl::switchMode(OpMode opMode) {
119120

120121
bool reopen = true;
121122
switch (opMode) {
123+
#ifdef _WIN32
124+
case opRead:
125+
// Flush if current mode allows reading, else reopen (in mode "r+b"
126+
// as in this case we know that we can write to the file)
127+
if (wOpenMode_.front() == L'r' || wOpenMode_.at(1) == L'+')
128+
reopen = false;
129+
break;
130+
case opWrite:
131+
// Flush if current mode allows writing, else reopen
132+
if (wOpenMode_.front() != L'r' || wOpenMode_.at(1) == L'+')
133+
reopen = false;
134+
break;
135+
#else
122136
case opRead:
123137
// Flush if current mode allows reading, else reopen (in mode "r+b"
124138
// as in this case we know that we can write to the file)
@@ -130,6 +144,7 @@ int FileIo::Impl::switchMode(OpMode opMode) {
130144
if (openMode_.front() != 'r' || openMode_.at(1) == '+')
131145
reopen = false;
132146
break;
147+
#endif
133148
case opSeek:
134149
reopen = false;
135150
break;
@@ -340,7 +355,11 @@ size_t FileIo::write(BasicIo& src) {
340355

341356
void FileIo::transfer(BasicIo& src) {
342357
const bool wasOpen = (p_->fp_ != nullptr);
358+
#ifdef _WIN32
359+
const std::wstring lastMode(p_->wOpenMode_);
360+
#else
343361
const std::string lastMode(p_->openMode_);
362+
#endif
344363

345364
if (auto fileIo = dynamic_cast<FileIo*>(&src)) {
346365
// Optimization if src is another instance of FileIo
@@ -415,7 +434,7 @@ void FileIo::transfer(BasicIo& src) {
415434

416435
if (wasOpen) {
417436
if (open(lastMode) != 0) {
418-
throw Error(ErrorCode::kerFileOpenFailed, path(), lastMode, strError());
437+
throw Error(ErrorCode::kerFileOpenFailed, path(), strError());
419438
}
420439
} else
421440
close();
@@ -466,7 +485,11 @@ size_t FileIo::tell() const {
466485

467486
size_t FileIo::size() const {
468487
// Flush and commit only if the file is open for writing
488+
#ifdef _WIN32
489+
if (p_->fp_ && (p_->wOpenMode_.front() != L'r' || p_->wOpenMode_.at(1) == L'+')) {
490+
#else
469491
if (p_->fp_ && (p_->openMode_.front() != 'r' || p_->openMode_.at(1) == '+')) {
492+
#endif
470493
std::fflush(p_->fp_);
471494
#ifdef _MSC_VER
472495
// This is required on msvcrt before stat after writing to a file
@@ -482,26 +505,34 @@ size_t FileIo::size() const {
482505

483506
int FileIo::open() {
484507
// Default open is in read-only binary mode
508+
#ifdef _WIN32
509+
return open(L"rb");
510+
#else
485511
return open("rb");
512+
#endif
486513
}
487514

488515
int FileIo::open(const std::string& mode) {
489516
close();
490517
p_->openMode_ = mode;
491518
p_->opMode_ = Impl::opSeek;
492-
#ifdef _WIN32
493-
wchar_t wmode[10];
494-
MultiByteToWideChar(CP_UTF8, 0, mode.c_str(), -1, wmode, 10);
495-
if (_wfopen_s(&p_->fp_, p_->path_.c_str(), wmode))
496-
return 1;
497-
#else
498519
p_->fp_ = ::fopen(path().c_str(), mode.c_str());
499520
if (!p_->fp_)
500521
return 1;
501-
#endif
502522
return 0;
503523
}
504524

525+
#ifdef _WIN32
526+
int FileIo::open(const std::wstring& mode) {
527+
close();
528+
p_->wOpenMode_ = mode;
529+
p_->opMode_ = Impl::opSeek;
530+
if (_wfopen_s(&p_->fp_, p_->path_.c_str(), mode.c_str()))
531+
return 1;
532+
return 0;
533+
}
534+
#endif
535+
505536
bool FileIo::isopen() const {
506537
return p_->fp_ != nullptr;
507538
}
@@ -1648,6 +1679,17 @@ size_t writeFile(const DataBuf& buf, const std::string& path) {
16481679
}
16491680
return file.write(buf.c_data(), buf.size());
16501681
}
1682+
1683+
#ifdef _WIN32
1684+
DataBuf readFile(const std::wstring& path) {
1685+
FileIo file(path);
1686+
if (file.open(L"rb") != 0)
1687+
throw Error(ErrorCode::kerFileOpenFailed, "wb", strError());
1688+
DataBuf buf(static_cast<size_t>(fs::file_size(path)));
1689+
file.read(buf.data(), buf.size());
1690+
return buf;
1691+
}
1692+
#endif
16511693
#endif
16521694

16531695
#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(L"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) {

unitTests/test_ImageFactory.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -100,45 +100,45 @@ TEST(TheImageFactory, cannotCreateInstancesForSomeTypesInFiles) {
100100
TEST(TheImageFactory, loadInstancesDifferentImageTypes) {
101101
fs::path testData(TESTDATA_PATH);
102102

103-
std::string imagePath = (testData / "DSC_3079.jpg").string();
103+
fs::path imagePath = testData / "DSC_3079.jpg";
104104
EXPECT_EQ(ImageType::jpeg, ImageFactory::getType(imagePath));
105105
EXPECT_NO_THROW(ImageFactory::open(imagePath, false));
106106

107-
imagePath = (testData / "exiv2-bug1108.exv").string();
107+
imagePath = testData / "exiv2-bug1108.exv";
108108
EXPECT_EQ(ImageType::exv, ImageFactory::getType(imagePath));
109109
EXPECT_NO_THROW(ImageFactory::open(imagePath, false));
110110

111-
imagePath = (testData / "exiv2-canon-powershot-s40.crw").string();
111+
imagePath = testData / "exiv2-canon-powershot-s40.crw";
112112
EXPECT_EQ(ImageType::crw, ImageFactory::getType(imagePath));
113113
EXPECT_NO_THROW(ImageFactory::open(imagePath, false));
114114

115-
imagePath = (testData / "exiv2-bug1044.tif").string();
115+
imagePath = testData / "exiv2-bug1044.tif";
116116
EXPECT_EQ(ImageType::tiff, ImageFactory::getType(imagePath));
117117
EXPECT_NO_THROW(ImageFactory::open(imagePath, false));
118118

119119
#ifdef EXV_HAVE_LIBZ
120-
imagePath = (testData / "exiv2-bug1074.png").string();
120+
imagePath = testData / "exiv2-bug1074.png";
121121
EXPECT_EQ(ImageType::png, ImageFactory::getType(imagePath));
122122
EXPECT_NO_THROW(ImageFactory::open(imagePath, false));
123123
#endif
124124

125-
imagePath = (testData / "BlueSquare.xmp").string();
125+
imagePath = testData / "BlueSquare.xmp";
126126
EXPECT_EQ(ImageType::xmp, ImageFactory::getType(imagePath));
127127
EXPECT_NO_THROW(ImageFactory::open(imagePath, false));
128128

129-
imagePath = (testData / "exiv2-photoshop.psd").string();
129+
imagePath = testData / "exiv2-photoshop.psd";
130130
EXPECT_EQ(ImageType::psd, ImageFactory::getType(imagePath));
131131
EXPECT_NO_THROW(ImageFactory::open(imagePath, false));
132132

133-
imagePath = (testData / "cve_2017_1000126_stack-oob-read.webp").string();
133+
imagePath = testData / "cve_2017_1000126_stack-oob-read.webp";
134134
EXPECT_EQ(ImageType::webp, ImageFactory::getType(imagePath));
135135
EXPECT_NO_THROW(ImageFactory::open(imagePath, false));
136136

137-
imagePath = (testData / "imagemagick.pgf").string();
137+
imagePath = testData / "imagemagick.pgf";
138138
EXPECT_EQ(ImageType::pgf, ImageFactory::getType(imagePath));
139139
EXPECT_NO_THROW(ImageFactory::open(imagePath, false));
140140

141-
imagePath = (testData / "Reagan.jp2").string();
141+
imagePath = testData / "Reagan.jp2";
142142
EXPECT_EQ(ImageType::jp2, ImageFactory::getType(imagePath));
143143
EXPECT_NO_THROW(ImageFactory::open(imagePath, false));
144144
}

0 commit comments

Comments
 (0)