Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: use fs::path for app #3125

Closed
wants to merge 1 commit into from
Closed
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
198 changes: 98 additions & 100 deletions app/actions.cpp

Large diffs are not rendered by default.

50 changes: 29 additions & 21 deletions app/actions.hpp
Original file line number Diff line number Diff line change
@@ -16,6 +16,14 @@

#include <unordered_map>

#if __has_include(<filesystem>)
#include <filesystem>
namespace fs = std::filesystem;
#else
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#endif

// *****************************************************************************
// class declarations

@@ -70,7 +78,7 @@ class Task {
/// @brief Application interface to perform a task.
/// @param path Path of the file to process.
/// @return 0 if successful.
virtual int run(const std::string& path) = 0;
virtual int run(const fs::path& path) = 0;

bool setBinary(bool b) {
bool bResult = binary_;
@@ -133,7 +141,7 @@ class TaskFactory {
//! %Print the Exif (or other metadata) of a file to stdout
class Print : public Task {
public:
int run(const std::string& path) override;
int run(const fs::path& path) override;
[[nodiscard]] Task::UniquePtr clone() const override;

//! Print the Jpeg comment
@@ -171,25 +179,25 @@ class Print : public Task {
EasyAccessFct easyAccessFctFallback = nullptr) const;

private:
std::string path_;
fs::path path_;
int align_{0}; // for the alignment of the summary output
};

/// @brief %Rename a file to its metadata creation timestamp, in the specified format.
class Rename : public Task {
public:
int run(const std::string& path) override;
int run(const fs::path& path) override;
[[nodiscard]] Task::UniquePtr clone() const override;
}; // class Rename

//! %Adjust the Exif (or other metadata) timestamps
class Adjust : public Task {
public:
int run(const std::string& path) override;
int run(const fs::path& path) override;
[[nodiscard]] Task::UniquePtr clone() const override;

private:
int adjustDateTime(Exiv2::ExifData& exifData, const std::string& key, const std::string& path) const;
int adjustDateTime(Exiv2::ExifData& exifData, const std::string& key, const fs::path& path) const;

int64_t adjustment_{0};
int64_t yearAdjustment_{0};
@@ -201,7 +209,7 @@ class Adjust : public Task {
/// @brief %Erase the entire exif data or only the thumbnail section.
class Erase : public Task {
public:
int run(const std::string& path) override;
int run(const fs::path& path) override;
[[nodiscard]] Task::UniquePtr clone() const override;

/// @brief Delete the thumbnail image, incl IFD1 metadata from the file.
@@ -223,13 +231,13 @@ class Erase : public Task {
static int eraseIccProfile(Exiv2::Image* image);

private:
std::string path_;
fs::path path_;
};

/// @brief %Extract the entire exif data or only the thumbnail section.
class Extract : public Task {
public:
int run(const std::string& path) override;
int run(const fs::path& path) override;
[[nodiscard]] Task::UniquePtr clone() const override;

/*!
@@ -252,39 +260,39 @@ class Extract : public Task {
[[nodiscard]] int writeIccProfile(const std::string& target) const;

private:
std::string path_;
fs::path path_;
};

/// @brief %Insert the Exif data from corresponding *.exv files.
class Insert : public Task {
public:
int run(const std::string& path) override;
int run(const fs::path& path) override;
[[nodiscard]] Task::UniquePtr clone() const override;

/*!
@brief Insert a Jpeg thumbnail image from a file into file \em path.
The filename of the thumbnail is expected to be the image
filename (\em path) minus its suffix plus "-thumb.jpg".
*/
static int insertThumbnail(const std::string& path);
static int insertThumbnail(const fs::path& path);

/// @brief Insert an XMP packet from a xmpPath into file \em path.
static int insertXmpPacket(const std::string& path, const std::string& xmpPath);
static int insertXmpPacket(const fs::path& path, const std::string& xmpPath);

/// @brief Insert xmp from a DataBuf into file \em path.
static int insertXmpPacket(const std::string& path, const Exiv2::DataBuf& xmpBlob, bool usePacket = false);
static int insertXmpPacket(const fs::path& path, const Exiv2::DataBuf& xmpBlob, bool usePacket = false);

/// @brief Insert an ICC profile from iccPath into file \em path.
static int insertIccProfile(const std::string& path, const std::string& iccPath);
static int insertIccProfile(const fs::path& path, const std::string& iccPath);

/// @brief Insert an ICC profile from binary DataBuf into file \em path.
static int insertIccProfile(const std::string& path, Exiv2::DataBuf&& iccProfileBlob);
static int insertIccProfile(const fs::path& path, Exiv2::DataBuf&& iccProfileBlob);
};

/// @brief %Modify the Exif data according to the commands in the modification table.
class Modify : public Task {
public:
int run(const std::string& path) override;
int run(const fs::path& path) override;
[[nodiscard]] Task::UniquePtr clone() const override;
//! Apply modification commands to the \em pImage, return 0 if successful.
static int applyCommands(Exiv2::Image* pImage);
@@ -303,23 +311,23 @@ class Modify : public Task {
/// @brief %Copy ISO settings from any of the Nikon makernotes to the regular Exif tag, Exif.Photo.ISOSpeedRatings.
class FixIso : public Task {
public:
int run(const std::string& path) override;
int run(const fs::path& path) override;
[[nodiscard]] Task::UniquePtr clone() const override;

private:
std::string path_;
fs::path path_;
};

/// @brief Fix the character encoding of Exif UNICODE user comments.
///
/// Decodes the comment using the auto-detected or specified character encoding and writes it back in UCS-2.
class FixCom : public Task {
public:
int run(const std::string& path) override;
int run(const fs::path& path) override;
[[nodiscard]] Task::UniquePtr clone() const override;

private:
std::string path_;
fs::path path_;
};

} // namespace Action
42 changes: 41 additions & 1 deletion include/exiv2/basicio.hpp
Original file line number Diff line number Diff line change
@@ -286,8 +286,14 @@ 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);
/*!
@brief Like FileIo(const std::string& path) but accepts a
unicode path in an std::wstring.
@note This constructor is only available on Windows.
*/
explicit FileIo(const std::wstring& wpath);
#endif

//! Destructor. Flushes and closes an open file.
@@ -686,6 +692,15 @@ class EXIV2API XPathIo : public FileIo {
//! Default constructor that reads data from stdin/data uri path and writes them to the temp file.
explicit XPathIo(const std::string& orgPath);

#ifdef _WIN32
/*!
@brief Like XPathIo(const std::string& path) but accepts a
unicode url in an std::wstring.
@note This constructor is only available on Windows.
*/
explicit XPathIo(const std::wstring& wpath);
#endif

//! Destructor. Releases all managed memory and removes the temp file.
~XPathIo() override;
//@}
@@ -712,6 +727,14 @@ class EXIV2API XPathIo : public FileIo {
@throw Error if it fails.
*/
static std::string writeDataToFile(const std::string& orgPath);
#ifdef _WIN32
/*!
@brief Like writeDataToFile(const std::string& orgPath) but accepts a
unicode url in an std::wstring.
@note This constructor is only available on Windows.
*/
static std::string writeDataToFile(const std::wstring& wOrgPath);
#endif
//@}

private:
@@ -905,6 +928,15 @@ class EXIV2API HttpIo : public RemoteIo {
*/
explicit HttpIo(const std::string& url, size_t blockSize = 1024);

#ifdef _WIN32
/*!
@brief Like HttpIo(const std::string& url, size_t blockSize = 1024) but accepts a
unicode url in an std::wstring.
@note This constructor is only available on Windows.
*/
explicit HttpIo(const std::wstring& wurl, size_t blockSize = 1024);
#endif

private:
// Pimpl idiom
class HttpImpl;
@@ -929,6 +961,14 @@ class EXIV2API CurlIo : public RemoteIo {
@throw Error if it is unable to init curl pointer.
*/
explicit CurlIo(const std::string& url, size_t blockSize = 0);
#ifdef _WIN32
/*!
@brief Like CurlIo(const std::string& url, size_t blockSize = 0) but accepts a
unicode url in an std::wstring.
@note This constructor is only available on Windows.
*/
explicit CurlIo(const std::wstring& wurl, size_t blockSize = 0);
#endif

/*!
@brief Write access is only available for some protocols. This method
17 changes: 17 additions & 0 deletions include/exiv2/futils.hpp
Original file line number Diff line number Diff line change
@@ -70,6 +70,14 @@ EXIV2API size_t base64decode(const char* in, char* out, size_t out_size);
*/
EXIV2API Protocol fileProtocol(const std::string& path);

#ifdef _WIN32
/*!
@brief Like fileProtocol() but accepts a unicode path in an std::wstring.
@note This function is only available on Windows.
*/
EXIV2API Protocol fileProtocol(const std::wstring& path);
#endif

/*!
@brief Test if a file exists.
@@ -83,6 +91,15 @@ EXIV2API Protocol fileProtocol(const std::string& path);
*/
EXIV2API bool fileExists(const std::string& path);

#ifdef _WIN32
/*!
@brief Like fileExists(const std::string& path) but
accepts a unicode path in an std::wstring.
@note This function is only available on Windows.
*/
EXIV2API bool fileExists(const std::wstring& path);
#endif

/*!
@brief Return a system error message and the error code (errno).
See %strerror(3).
23 changes: 21 additions & 2 deletions include/exiv2/image.hpp
Original file line number Diff line number Diff line change
@@ -522,9 +522,15 @@ 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);
/*!
@brief Like createIo() but accepts a unicode path in an std::wstring.
@note This function is only available on Windows.
*/
static BasicIo::UniquePtr createIo(const std::wstring& wpath, bool useCurl = true);
#endif

/*!
@brief Create an Image subclass of the appropriate type by reading
the specified file. %Image type is derived from the file
@@ -539,9 +545,15 @@ 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);
/*!
@brief Like open() but accepts a unicode path in an std::wstring.
@note This function is only available on Windows.
*/
static Image::UniquePtr open(const std::wstring& wpath, bool useCurl = true);
#endif

/*!
@brief Create an Image subclass of the appropriate type by reading
the provided memory. %Image type is derived from the memory
@@ -582,6 +594,13 @@ class EXIV2API ImageFactory {
@throw Error If the image type is not supported.
*/
static Image::UniquePtr create(ImageType type, const std::string& path);
#ifdef _WIN32
/*!
@brief Like create() but accepts a unicode path in an std::wstring.
@note This function is only available on Windows.
*/
static Image::UniquePtr create(ImageType type, const std::wstring& wpath);
#endif
/*!
@brief Create an Image subclass of the requested type by creating a
new image in memory.
83 changes: 81 additions & 2 deletions src/basicio.cpp
Original file line number Diff line number Diff line change
@@ -122,6 +122,7 @@ FileIo::Impl::Impl(std::string path) : path_(std::move(path)) {
wpath_.assign(t, nw);
#endif
}

#ifdef _WIN32
FileIo::Impl::Impl(std::wstring path) : wpath_(std::move(path)) {
char t[1024];
@@ -209,8 +210,9 @@ int FileIo::Impl::stat(StructStat& buf) const {

FileIo::FileIo(const std::string& path) : p_(std::make_unique<Impl>(path)) {
}

#ifdef _WIN32
FileIo::FileIo(const std::wstring& path) : p_(std::make_unique<Impl>(path)) {
FileIo::FileIo(const std::wstring& wpath) : p_(std::make_unique<Impl>(wpath)) {
}
#endif

@@ -901,6 +903,11 @@ void MemIo::populateFakeData() {
XPathIo::XPathIo(const std::string& orgPath) : FileIo(XPathIo::writeDataToFile(orgPath)), tempFilePath_(path()) {
}

#ifdef _WIN32
XPathIo::XPathIo(const std::wstring& worgPath) : FileIo(XPathIo::writeDataToFile(worgPath)), tempFilePath_(path()) {
}
#endif

XPathIo::~XPathIo() {
if (isTemp_ && !fs::remove(tempFilePath_)) {
// error when removing file
@@ -984,21 +991,35 @@ std::string XPathIo::writeDataToFile(const std::string& orgPath) {
return path;
}

#ifdef _WIN32
std::string XPathIo::writeDataToFile(const std::wstring& wOrgPath) {
std::string orgPath;
orgPath.assign(wOrgPath.begin(), wOrgPath.end());
return XPathIo::writeDataToFile(orgPath);
}
#endif

#endif

//! Internal Pimpl abstract structure of class RemoteIo.
class RemoteIo::Impl {
public:
//! Constructor
Impl(const std::string& url, size_t blockSize);
#ifdef _WIN32
Impl(const std::wstring& wpath, size_t blockSize);
#endif
//! Destructor. Releases all managed memory.
virtual ~Impl();

Impl(const Impl&) = delete;
Impl& operator=(const Impl&) = delete;

// DATA
std::string path_; //!< (Standard) path
std::string path_; //!< (Standard) path
#ifdef _WIN32
std::wstring wpath_; //!< Unicode path
#endif
size_t blockSize_; //!< Size of the block memory.
BlockMap* blocksMap_{nullptr}; //!< An array contains all blocksMap
size_t size_{0}; //!< The file size
@@ -1050,6 +1071,12 @@ RemoteIo::Impl::Impl(const std::string& url, size_t blockSize) :
path_(url), blockSize_(blockSize), protocol_(fileProtocol(url)) {
}

#ifdef _WIN32
RemoteIo::Impl::Impl(const std::wstring& wurl, size_t blockSize) :
wpath_(wurl), blockSize_(blockSize), protocol_(fileProtocol(wurl)) {
}
#endif

size_t RemoteIo::Impl::populateBlocks(size_t lowBlock, size_t highBlock) {
// optimize: ignore all true blocks on left & right sides.
while (!blocksMap_[lowBlock].isNone() && lowBlock < highBlock)
@@ -1376,6 +1403,10 @@ class HttpIo::HttpImpl : public Impl {
public:
//! Constructor
HttpImpl(const std::string& url, size_t blockSize);
#ifdef _WIN32
//! Constructor accepting a unicode path in an std::wstring
HttpImpl(const std::wstring& wpath, size_t blockSize);
#endif
Exiv2::Uri hostInfo_; //!< the host information extracted from the path

// METHODS
@@ -1415,6 +1446,16 @@ HttpIo::HttpImpl::HttpImpl(const std::string& url, size_t blockSize) : Impl(url,
Exiv2::Uri::Decode(hostInfo_);
}

#ifdef _WIN32
HttpIo::HttpImpl::HttpImpl(const std::wstring& wurl, size_t blockSize) : Impl(wurl, blockSize) {
std::string url;
url.assign(wurl.begin(), wurl.end());
path_ = url;
hostInfo_ = Exiv2::Uri::Parse(url);
Exiv2::Uri::Decode(hostInfo_);
}
#endif

int64_t HttpIo::HttpImpl::getFileLength() {
Exiv2::Dictionary response;
Exiv2::Dictionary request;
@@ -1503,6 +1544,12 @@ void HttpIo::HttpImpl::writeRemote(const byte* data, size_t size, size_t from, s
HttpIo::HttpIo(const std::string& url, size_t blockSize) {
p_ = std::make_unique<HttpImpl>(url, blockSize);
}

#ifdef _WIN32
HttpIo::HttpIo(const std::wstring& url, size_t blockSize) {
p_ = std::make_unique<HttpImpl>(url, blockSize);
}
#endif
#endif

#ifdef EXV_USE_CURL
@@ -1511,6 +1558,10 @@ class CurlIo::CurlImpl : public Impl {
public:
//! Constructor
CurlImpl(const std::string& url, size_t blockSize);
#ifdef _WIN32
//! Constructor accepting a unicode path in an std::wstring
CurlImpl(const std::wstring& wpath, size_t blockSize);
#endif
//! Destructor. Cleans up the curl pointer and releases all managed memory.
~CurlImpl() override;

@@ -1574,6 +1625,28 @@ CurlIo::CurlImpl::CurlImpl(const std::string& url, size_t blockSize) : Impl(url,
}
}

#ifdef _WIN32
CurlIo::CurlImpl::CurlImpl(const std::wstring& wurl, size_t blockSize) :
Impl(wurl, blockSize), curl_(curl_easy_init()) {
std::string url;
url.assign(wurl.begin(), wurl.end());
path_ = url;

// init curl pointer
curl_ = curl_easy_init();
if (!curl_) {
throw Error(ErrorCode::kerErrorMessage, "Unable to init libcurl.");
}

// The default block size for FTP is much larger than other protocols
// the reason is that getDataByRange() in FTP always creates the new connection,
// so we need the large block size to reduce the overhead of creating the connection.
if (blockSize_ == 0) {
blockSize_ = protocol_ == pFtp ? 102400 : 1024;
}
}
#endif

int64_t CurlIo::CurlImpl::getFileLength() {
curl_easy_reset(curl_); // reset all options
std::string response;
@@ -1695,6 +1768,12 @@ CurlIo::CurlIo(const std::string& url, size_t blockSize) {
p_ = std::make_unique<CurlImpl>(url, blockSize);
}

#ifdef _WIN32
CurlIo::CurlIo(const std::wstring& wurl, size_t blockSize) {
p_ = std::make_unique<CurlImpl>(wurl, blockSize);
}
#endif

#endif

// *************************************************************************
37 changes: 37 additions & 0 deletions src/futils.cpp
Original file line number Diff line number Diff line change
@@ -230,6 +230,30 @@ Protocol fileProtocol(const std::string& path) {
return result;
} // fileProtocol

#ifdef _WIN32
Protocol fileProtocol(const std::wstring& path) {
Protocol result = pFile;
struct {
std::wstring name;
Protocol prot;
bool isUrl; // path.size() > name.size()
} prots[] = {
{L"http://", pHttp, true}, {L"https://", pHttps, true}, {L"ftp://", pFtp, true}, {L"sftp://", pSftp, true},
{L"file://", pFileUri, true}, {L"data://", pDataUri, true}, {L"-", pStdin, false},
};
for (const auto& prot : prots) {
if (result != pFile)
break;

if (path.rfind(prot.name, 0) == 0)
// URL's require data. Stdin == "-" and no further data
if (prot.isUrl ? path.size() > prot.name.size() : path.size() == prot.name.size())
result = prot.prot;
}
return result;
}
#endif

bool fileExists(const std::string& path) {
if (fileProtocol(path) != pFile) {
return true;
@@ -241,6 +265,19 @@ bool fileExists(const std::string& path) {
#endif
}

#ifdef _WIN32
bool fileExists(const std::wstring& wpath) {
if (fileProtocol(wpath) != pFile) {
return true;
}
#ifdef EXV_ENABLE_FILESYSTEM
return fs::exists(wpath);
#else
return false;
#endif
}
#endif

std::string strError() {
int error = errno;
std::ostringstream os;
53 changes: 48 additions & 5 deletions src/image.cpp
Original file line number Diff line number Diff line change
@@ -130,6 +130,14 @@ std::string pathOfFileUrl(const std::string& url) {
size_t found = path.find('/');
return (found == std::string::npos) ? path : path.substr(found);
}

#ifdef _WIN32
std::wstring pathOfFileUrl(const std::wstring& url) {
std::wstring path = url.substr(7);
size_t found = path.find('/');
return (found == std::wstring::npos) ? path : path.substr(found);
}
#endif
#endif

} // namespace
@@ -835,11 +843,28 @@ 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& wpath, [[maybe_unused]] bool useCurl) {
Protocol fProt = fileProtocol(wpath);

#ifdef EXV_USE_CURL
if (useCurl && (fProt == pHttp || fProt == pHttps || fProt == pFtp)) {
return std::make_unique<CurlIo>(wpath); // may throw
}
#endif

#ifdef EXV_ENABLE_WEBREADY
if (fProt == pHttp)
return std::make_unique<HttpIo>(wpath); // may throw
#endif
#ifdef EXV_ENABLE_FILESYSTEM
return std::make_unique<FileIo>(path);
if (fProt == pFileUri)
return std::make_unique<FileIo>(pathOfFileUrl(wpath));
if (fProt == pStdin || fProt == pDataUri)
return std::make_unique<XPathIo>(wpath); // may throw

return std::make_unique<FileIo>(wpath);
#else
return nullptr;
throw Error(ErrorCode::kerFileAccessDisabled, wpath);
#endif
}
#endif
@@ -852,8 +877,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);
@@ -897,6 +922,24 @@ 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& wpath) {
auto fileIo = std::make_unique<FileIo>(wpath);
// Create or overwrite the file, then close it
if (fileIo->open("w+b") != 0) {
// throw WError(ErrorCode::kerFileOpenFailed, wpath, "w+b", strError());
throw;
}
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) {