Merge pull request #2109 from Exiv2/main_StringView

Refactoring & cleanup
main
Luis Díaz Más 3 years ago committed by GitHub
commit c5a9dfd9af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

2
.gitignore vendored

@ -25,3 +25,5 @@ doc/html
contrib/vms/.vagrant contrib/vms/.vagrant
/.vscode /.vscode
.vs/ .vs/
*cppcheck*

@ -83,7 +83,6 @@ namespace {
public: public:
//! C'tor //! C'tor
Timestamp() = default; Timestamp() = default;
//! Read the timestamp of a file
int read(const std::string& path); int read(const std::string& path);
//! Read the timestamp from a broken-down time in buffer \em tm. //! Read the timestamp from a broken-down time in buffer \em tm.
int read(struct tm* tm); int read(struct tm* tm);
@ -176,11 +175,6 @@ namespace Action {
registry_.clear(); registry_.clear();
} }
void TaskFactory::registerTask(TaskType type, Task::UniquePtr task)
{
registry_[type] = std::move(task);
}
TaskFactory::TaskFactory() TaskFactory::TaskFactory()
{ {
registry_.emplace(adjust, std::make_unique<Adjust>()); registry_.emplace(adjust, std::make_unique<Adjust>());
@ -268,7 +262,7 @@ namespace Action {
int Print::printSummary() int Print::printSummary()
{ {
if (!Exiv2::fileExists(path_, true)) { if (!Exiv2::fileExists(path_)) {
std::cerr << path_ << ": " << _("Failed to open the file\n"); std::cerr << path_ << ": " << _("Failed to open the file\n");
return -1; return -1;
} }
@ -284,11 +278,8 @@ namespace Action {
std::cout << path_ << std::endl; std::cout << path_ << std::endl;
// Filesize // Filesize
struct stat buf;
if (0 == stat(path_.c_str(), &buf)) {
printLabel(_("File size")); printLabel(_("File size"));
std::cout << buf.st_size << " " << _("Bytes") << std::endl; std::cout << fs::file_size(path_) << " " << _("Bytes") << std::endl;
}
// MIME type // MIME type
printLabel(_("MIME type")); printLabel(_("MIME type"));
@ -402,7 +393,7 @@ namespace Action {
int Print::printList() int Print::printList()
{ {
if (!Exiv2::fileExists(path_, true)) { if (!Exiv2::fileExists(path_)) {
std::cerr << path_ << ": " << _("Failed to open the file\n"); std::cerr << path_ << ": " << _("Failed to open the file\n");
return -1; return -1;
} }
@ -596,7 +587,6 @@ namespace Action {
if (Params::instance().printItems_ & Params::prHex) { if (Params::instance().printItems_ & Params::prHex) {
if (!first) if (!first)
std::cout << std::endl; std::cout << std::endl;
first = false;
Exiv2::DataBuf buf(md.size()); Exiv2::DataBuf buf(md.size());
md.copy(buf.data(), pImage->byteOrder()); md.copy(buf.data(), pImage->byteOrder());
Exiv2::hexdump(std::cout, buf.c_data(), buf.size()); Exiv2::hexdump(std::cout, buf.c_data(), buf.size());
@ -607,7 +597,7 @@ namespace Action {
int Print::printComment() int Print::printComment()
{ {
if (!Exiv2::fileExists(path_, true)) { if (!Exiv2::fileExists(path_)) {
std::cerr << path_ << ": " << _("Failed to open the file\n"); std::cerr << path_ << ": " << _("Failed to open the file\n");
return -1; return -1;
} }
@ -624,7 +614,7 @@ namespace Action {
int Print::printPreviewList() int Print::printPreviewList()
{ {
if (!Exiv2::fileExists(path_, true)) { if (!Exiv2::fileExists(path_)) {
std::cerr << path_ << ": " << _("Failed to open the file\n"); std::cerr << path_ << ": " << _("Failed to open the file\n");
return -1; return -1;
} }
@ -658,7 +648,7 @@ namespace Action {
int Rename::run(const std::string& path) int Rename::run(const std::string& path)
{ {
try { try {
if (!Exiv2::fileExists(path, true)) { if (!Exiv2::fileExists(path)) {
std::cerr << path << ": " << _("Failed to open the file\n"); std::cerr << path << ": " << _("Failed to open the file\n");
return -1; return -1;
} }
@ -740,7 +730,7 @@ namespace Action {
try { try {
path_ = path; path_ = path;
if (!Exiv2::fileExists(path_, true)) { if (!Exiv2::fileExists(path_)) {
std::cerr << path_ << ": " << _("Failed to open the file\n"); std::cerr << path_ << ": " << _("Failed to open the file\n");
return -1; return -1;
} }
@ -900,7 +890,7 @@ namespace Action {
int Extract::writeThumbnail() const int Extract::writeThumbnail() const
{ {
if (!Exiv2::fileExists(path_, true)) { if (!Exiv2::fileExists(path_)) {
std::cerr << path_ << ": " << _("Failed to open the file\n"); std::cerr << path_ << ": " << _("Failed to open the file\n");
return -1; return -1;
} }
@ -947,7 +937,7 @@ namespace Action {
int Extract::writePreviews() const int Extract::writePreviews() const
{ {
if (!Exiv2::fileExists(path_, true)) { if (!Exiv2::fileExists(path_)) {
std::cerr << path_ << ": " << _("Failed to open the file\n"); std::cerr << path_ << ": " << _("Failed to open the file\n");
return -1; return -1;
} }
@ -983,7 +973,7 @@ namespace Action {
int Extract::writeIccProfile(const std::string& target) const int Extract::writeIccProfile(const std::string& target) const
{ {
int rc = 0; int rc = 0;
if (!Exiv2::fileExists(path_, true)) { if (!Exiv2::fileExists(path_)) {
std::cerr << path_ << ": " << _("Failed to open the file\n"); std::cerr << path_ << ": " << _("Failed to open the file\n");
rc = -1; rc = -1;
} }
@ -1049,7 +1039,7 @@ namespace Action {
// -i{tgt}- reading from stdin? // -i{tgt}- reading from stdin?
bool bStdin = (Params::instance().target_ & Params::ctStdInOut) != 0; bool bStdin = (Params::instance().target_ & Params::ctStdInOut) != 0;
if (!Exiv2::fileExists(path, true)) { if (!Exiv2::fileExists(path)) {
std::cerr << path std::cerr << path
<< ": " << _("Failed to open the file\n"); << ": " << _("Failed to open the file\n");
return -1; return -1;
@ -1106,12 +1096,12 @@ namespace Action {
Params::instance().getStdin(xmpBlob); Params::instance().getStdin(xmpBlob);
rc = insertXmpPacket(path,xmpBlob,true); rc = insertXmpPacket(path,xmpBlob,true);
} else { } else {
if (!Exiv2::fileExists(xmpPath, true)) { if (!Exiv2::fileExists(xmpPath)) {
std::cerr << xmpPath std::cerr << xmpPath
<< ": " << _("Failed to open the file\n"); << ": " << _("Failed to open the file\n");
rc = -1; rc = -1;
} }
if (rc == 0 && !Exiv2::fileExists(path, true)) { if (rc == 0 && !Exiv2::fileExists(path)) {
std::cerr << path std::cerr << path
<< ": " << _("Failed to open the file\n"); << ": " << _("Failed to open the file\n");
rc = -1; rc = -1;
@ -1152,7 +1142,7 @@ namespace Action {
Params::instance().getStdin(iccProfile); Params::instance().getStdin(iccProfile);
rc = insertIccProfile(path,std::move(iccProfile)); rc = insertIccProfile(path,std::move(iccProfile));
} else { } else {
if (!Exiv2::fileExists(iccProfilePath, true)) { if (!Exiv2::fileExists(iccProfilePath)) {
std::cerr << iccProfilePath std::cerr << iccProfilePath
<< ": " << _("Failed to open the file\n"); << ": " << _("Failed to open the file\n");
rc = -1; rc = -1;
@ -1168,7 +1158,7 @@ namespace Action {
{ {
int rc = 0; int rc = 0;
// test path exists // test path exists
if (!Exiv2::fileExists(path, true)) { if (!Exiv2::fileExists(path)) {
std::cerr << path << ": " << _("Failed to open the file\n"); std::cerr << path << ": " << _("Failed to open the file\n");
rc=-1; rc=-1;
} }
@ -1192,12 +1182,12 @@ namespace Action {
int Insert::insertThumbnail(const std::string& path) int Insert::insertThumbnail(const std::string& path)
{ {
std::string thumbPath = newFilePath(path, "-thumb.jpg"); std::string thumbPath = newFilePath(path, "-thumb.jpg");
if (!Exiv2::fileExists(thumbPath, true)) { if (!Exiv2::fileExists(thumbPath)) {
std::cerr << thumbPath std::cerr << thumbPath
<< ": " << _("Failed to open the file\n"); << ": " << _("Failed to open the file\n");
return -1; return -1;
} }
if (!Exiv2::fileExists(path, true)) { if (!Exiv2::fileExists(path)) {
std::cerr << path std::cerr << path
<< ": " << _("Failed to open the file\n"); << ": " << _("Failed to open the file\n");
return -1; return -1;
@ -1220,7 +1210,7 @@ namespace Action {
int Modify::run(const std::string& path) int Modify::run(const std::string& path)
{ {
try { try {
if (!Exiv2::fileExists(path, true)) { if (!Exiv2::fileExists(path)) {
std::cerr << path << ": " << _("Failed to open the file\n"); std::cerr << path << ": " << _("Failed to open the file\n");
return -1; return -1;
} }
@ -1452,7 +1442,7 @@ namespace Action {
monthAdjustment_ = Params::instance().yodAdjust_[Params::yodMonth].adjustment_; monthAdjustment_ = Params::instance().yodAdjust_[Params::yodMonth].adjustment_;
dayAdjustment_ = Params::instance().yodAdjust_[Params::yodDay].adjustment_; dayAdjustment_ = Params::instance().yodAdjust_[Params::yodDay].adjustment_;
if (!Exiv2::fileExists(path, true)) { if (!Exiv2::fileExists(path)) {
std::cerr << path << ": " << _("Failed to open the file\n"); std::cerr << path << ": " << _("Failed to open the file\n");
return -1; return -1;
} }
@ -1579,7 +1569,7 @@ namespace Action {
int FixIso::run(const std::string& path) int FixIso::run(const std::string& path)
{ {
try { try {
if (!Exiv2::fileExists(path, true)) { if (!Exiv2::fileExists(path)) {
std::cerr << path << ": " <<_("Failed to open the file\n"); std::cerr << path << ": " <<_("Failed to open the file\n");
return -1; return -1;
} }
@ -1632,7 +1622,7 @@ namespace Action {
int FixCom::run(const std::string& path) int FixCom::run(const std::string& path)
{ {
try { try {
if (!Exiv2::fileExists(path, true)) { if (!Exiv2::fileExists(path)) {
std::cerr << path << ": " <<_("Failed to open the file\n"); std::cerr << path << ": " <<_("Failed to open the file\n");
return -1; return -1;
} }
@ -1821,7 +1811,7 @@ namespace {
// read the source metadata // read the source metadata
int rc = -1 ; int rc = -1 ;
if (!Exiv2::fileExists(source, true)) { if (!Exiv2::fileExists(source)) {
std::cerr << source << ": " << _("Failed to open the file\n"); std::cerr << source << ": " << _("Failed to open the file\n");
return rc; return rc;
} }
@ -1893,7 +1883,6 @@ namespace {
// #1148 use Raw XMP packet if there are no XMP modification commands // #1148 use Raw XMP packet if there are no XMP modification commands
int tRawSidecar = Params::ctXmpSidecar | Params::ctXmpRaw; // option -eXX int tRawSidecar = Params::ctXmpSidecar | Params::ctXmpRaw; // option -eXX
// printTarget("in metacopy",Params::instance().target_,true);
if (Params::instance().modifyCmds_.empty() && (Params::instance().target_ & tRawSidecar) == tRawSidecar) { if (Params::instance().modifyCmds_.empty() && (Params::instance().target_ & tRawSidecar) == tRawSidecar) {
// std::cout << "short cut" << std::endl; // std::cout << "short cut" << std::endl;
// http://www.cplusplus.com/doc/tutorial/files/ // http://www.cplusplus.com/doc/tutorial/files/
@ -1946,7 +1935,8 @@ namespace {
} }
// delete temporary target // delete temporary target
if ( bStdout ) std::remove(target.c_str()); if ( bStdout )
fs::remove(target.c_str());
return rc; return rc;
} // metacopy } // metacopy
@ -2046,14 +2036,7 @@ namespace {
std::cout << std::endl; std::cout << std::endl;
} }
// Workaround for MinGW rename which does not overwrite existing files fs::rename(path, newPath);
remove(newPath.c_str());
if (std::rename(path.c_str(), newPath.c_str()) == -1) {
std::cerr << Params::instance().progname() << ": " << _("Failed to rename") << " " << path << " " << _("to")
<< " " << newPath << ": " << Exiv2::strError() << "\n";
return 1;
}
return 0; return 0;
} }
@ -2096,7 +2079,7 @@ namespace {
int printStructure(std::ostream& out, Exiv2::PrintStructureOption option, const std::string &path) int printStructure(std::ostream& out, Exiv2::PrintStructureOption option, const std::string &path)
{ {
if (!Exiv2::fileExists(path, true)) { if (!Exiv2::fileExists(path)) {
std::cerr << path << ": " std::cerr << path << ": "
<< _("Failed to open the file\n"); << _("Failed to open the file\n");
return -1; return -1;

@ -123,20 +123,6 @@ namespace Action {
*/ */
Task::UniquePtr create(TaskType type); Task::UniquePtr create(TaskType type);
/*!
@brief Register a task prototype together with its type.
The task factory creates new tasks of a given type by cloning its
associated prototype. Additional tasks can be registered. If called
for a type which already exists in the list, the corresponding
prototype is replaced.
@param type Task type.
@param task Pointer to the prototype. Ownership is transferred to the
task factory. That's what the auto pointer indicates.
*/
void registerTask(TaskType type, Task::UniquePtr task);
private: private:
//! Prevent construction other than through instance(). //! Prevent construction other than through instance().
TaskFactory(); TaskFactory();

@ -160,7 +160,6 @@ int main(int argc, char* const argv[])
assert(task); assert(task);
// Process all files // Process all files
int n = 1;
int s = static_cast<int>(params.files_.size()); int s = static_cast<int>(params.files_.size());
if (params.action_ & Action::extract && params.target_ & Params::ctStdInOut && s > 1) { if (params.action_ & Action::extract && params.target_ & Params::ctStdInOut && s > 1) {
std::cerr << params.progname() << ": " << _("Only one file is allowed when extracting to stdout") << std::endl; std::cerr << params.progname() << ": " << _("Only one file is allowed when extracting to stdout") << std::endl;
@ -168,6 +167,7 @@ int main(int argc, char* const argv[])
} }
else { else {
int w = s > 9 ? s > 99 ? 3 : 2 : 1; int w = s > 9 ? s > 99 ? 3 : 2 : 1;
int n = 1;
for (auto&& file : params.files_) { for (auto&& file : params.files_) {
// If extracting to stdout then ignore verbose // If extracting to stdout then ignore verbose
if (params.verbose_ && !(params.action_ & Action::extract && params.target_ & Params::ctStdInOut)) { if (params.verbose_ && !(params.action_ & Action::extract && params.target_ & Params::ctStdInOut)) {
@ -248,25 +248,6 @@ void Params::usage(std::ostream& os) const
<< _("Image metadata manipulation tool.\n"); << _("Image metadata manipulation tool.\n");
} }
std::string Params::printTarget(const std::string &before, int target, bool bPrint, std::ostream& out)
{
std::string t;
if ( target & Params::ctExif ) t+= 'e';
if ( target & Params::ctXmpSidecar ) t+= 'X';
if ( target & Params::ctXmpRaw ) t+= target & Params::ctXmpSidecar ? 'X' : 'R' ;
if ( target & Params::ctIptc ) t+= 'i';
if ( target & Params::ctIccProfile ) t+= 'C';
if ( target & Params::ctIptcRaw ) t+= 'I';
if ( target & Params::ctXmp ) t+= 'x';
if ( target & Params::ctComment ) t+= 'c';
if ( target & Params::ctThumb ) t+= 't';
if ( target & Params::ctPreview ) t+= 'p';
if ( target & Params::ctStdInOut ) t+= '-';
if ( bPrint ) out << before << " :" << t << std::endl;
return t;
}
void Params::help(std::ostream& os) const void Params::help(std::ostream& os) const
{ {
usage(os); usage(os);

@ -339,10 +339,6 @@ public:
//! Print version information to an output stream. //! Print version information to an output stream.
static void version(bool verbose = false, std::ostream& os = std::cout); static void version(bool verbose = false, std::ostream& os = std::cout);
//! Print target_
static std::string printTarget(const std::string& before, int target, bool bPrint = false,
std::ostream& out = std::cout);
//! getStdin binary data read from stdin to DataBuf //! getStdin binary data read from stdin to DataBuf
/* /*
stdin can be used by multiple images in the exiv2 command line: stdin can be used by multiple images in the exiv2 command line:

@ -240,7 +240,7 @@ namespace Exiv2 {
comprehensive error messages where only a BasicIo instance is comprehensive error messages where only a BasicIo instance is
available. available.
*/ */
virtual std::string path() const =0; virtual const std::string& path() const noexcept =0;
/*! /*!
@brief Mark all the bNone blocks to bKnow. This avoids allocating memory @brief Mark all the bNone blocks to bKnow. This avoids allocating memory
@ -472,7 +472,7 @@ namespace Exiv2 {
//! Returns true if the file position has reached the end, otherwise false. //! Returns true if the file position has reached the end, otherwise false.
bool eof() const override; bool eof() const override;
//! Returns the path of the file //! Returns the path of the file
std::string path() const override; const std::string& path() const noexcept override;
/*! /*!
@brief Mark all the bNone blocks to bKnow. This avoids allocating memory @brief Mark all the bNone blocks to bKnow. This avoids allocating memory
@ -654,7 +654,7 @@ namespace Exiv2 {
//!Returns true if the IO position has reached the end, otherwise false. //!Returns true if the IO position has reached the end, otherwise false.
bool eof() const override; bool eof() const override;
//! Returns a dummy path, indicating that memory access is used //! Returns a dummy path, indicating that memory access is used
std::string path() const override; const std::string& path() const noexcept override;
/*! /*!
@brief Mark all the bNone blocks to bKnow. This avoids allocating memory @brief Mark all the bNone blocks to bKnow. This avoids allocating memory
@ -898,7 +898,7 @@ namespace Exiv2 {
//!Returns true if the IO position has reached the end, otherwise false. //!Returns true if the IO position has reached the end, otherwise false.
bool eof() const override; bool eof() const override;
//!Returns the URL of the file. //!Returns the URL of the file.
std::string path() const override; const std::string& path() const noexcept override;
/*! /*!
@brief Mark all the bNone blocks to bKnow. This avoids allocating memory @brief Mark all the bNone blocks to bKnow. This avoids allocating memory
@ -1008,12 +1008,6 @@ namespace Exiv2 {
@throw Error In case of failure. @throw Error In case of failure.
*/ */
EXIV2API long writeFile(const DataBuf& buf, const std::string& path); EXIV2API long writeFile(const DataBuf& buf, const std::string& path);
/*!
@brief replace each substring of the subject that matches the given search string with the given replacement.
@return the subject after replacing.
*/
EXIV2API std::string ReplaceStringInPlace(std::string subject, const std::string& search,
const std::string& replace);
#ifdef EXV_USE_CURL #ifdef EXV_USE_CURL
/*! /*!
@brief The callback function is called by libcurl to write the data @brief The callback function is called by libcurl to write the data

@ -25,7 +25,8 @@
// included header files // included header files
#include "image.hpp" #include "image.hpp"
#include "iostream"
#include <set>
// ***************************************************************************** // *****************************************************************************
// namespace extensions // namespace extensions
@ -127,7 +128,7 @@ namespace Exiv2
//@{ //@{
void readMetadata() override /* override */; void readMetadata() override /* override */;
void writeMetadata() override /* override */; void writeMetadata() override /* override */;
void setComment(const std::string& comment) override /* override */; void setComment(std::string_view comment) override /* override */;
void printStructure(std::ostream& out, Exiv2::PrintStructureOption option, int depth) override; void printStructure(std::ostream& out, Exiv2::PrintStructureOption option, int depth) override;
//@} //@}

@ -85,7 +85,7 @@ namespace Exiv2 {
void setIptcData(const IptcData& iptcData) override; void setIptcData(const IptcData& iptcData) override;
/// @throws Error(kerInvalidSettingForImage) /// @throws Error(kerInvalidSettingForImage)
void setComment(const std::string& comment) override; void setComment(std::string_view comment) override;
//@} //@}
//! @name Accessors //! @name Accessors

@ -6,29 +6,8 @@
///// Start of Visual Studio Support ///// ///// Start of Visual Studio Support /////
#ifdef _MSC_VER #ifdef _MSC_VER
#define _MSC_VER_2010 1600
#define _MSC_VER_2008 1500
// Constants required by Microsoft SDKs to define SHGetFolderPathA and others
#ifndef _WIN32_WINNT
// Visual Studio 2012 and earlier
# if _MSC_VER < 1800
# define _WIN32_WINNT 0x0501
# else
# define _WIN32_WINNT 0x0600
# endif
#endif
#if _MSC_VER >= _MSC_VER_2008
#pragma warning(disable : 4996) // Disable warnings about 'deprecated' standard functions #pragma warning(disable : 4996) // Disable warnings about 'deprecated' standard functions
#pragma warning(disable : 4251) // Disable warnings from std templates about exporting interfaces #pragma warning(disable : 4251) // Disable warnings from std templates about exporting interfaces
#endif
/* On Microsoft compilers pid_t has to be set to int. */
#ifndef HAVE_PID_T
typedef int pid_t;
#endif
#endif // _MSC_VER #endif // _MSC_VER
///// End of Visual Studio Support ///// ///// End of Visual Studio Support /////
@ -93,16 +72,4 @@ typedef int pid_t;
#endif #endif
////////////////////////////////////// //////////////////////////////////////
// https://softwareengineering.stackexchange.com/questions/291141/how-to-handle-design-changes-for-auto-ptr-deprecation-in-c11
#if __cplusplus >= 201103L
#include <memory>
#include <sys/types.h>
#ifndef _MSC_VER
#include <unistd.h>
#endif
template <typename T>
using auto_ptr = std::unique_ptr<T>;
#endif
#endif // _CONFIG_H_ #endif // _CONFIG_H_

@ -81,7 +81,7 @@ namespace Exiv2 {
@brief Not supported. CR2 format does not contain a comment. @brief Not supported. CR2 format does not contain a comment.
Calling this function will throw an Error(kerInvalidSettingForImage). Calling this function will throw an Error(kerInvalidSettingForImage).
*/ */
void setComment(const std::string& comment) override; void setComment(std::string_view comment) override;
//@} //@}
//! @name Accessors //! @name Accessors

@ -32,11 +32,6 @@
// included header files // included header files
#include "metadatum.hpp" #include "metadatum.hpp"
// + standard includes
#include <set>
#include <vector>
#include <map>
// ***************************************************************************** // *****************************************************************************
// namespace extensions // namespace extensions
namespace Exiv2 { namespace Exiv2 {

@ -80,7 +80,7 @@ namespace Exiv2
@brief Not supported. @brief Not supported.
Calling this function will throw an instance of Error(kerInvalidSettingForImage). Calling this function will throw an instance of Error(kerInvalidSettingForImage).
*/ */
void setComment(const std::string& comment) override; void setComment(std::string_view comment) override;
//@} //@}
//! @name Accessors //! @name Accessors

@ -34,10 +34,6 @@
// included header files // included header files
#include "types.hpp" #include "types.hpp"
// + standard includes
#include <exception>
#include <string>
// ***************************************************************************** // *****************************************************************************
// namespace extensions // namespace extensions
namespace Exiv2 { namespace Exiv2 {

@ -63,18 +63,7 @@ namespace Exiv2
@note Source: http://www.geekhideout.com/urlcode.shtml @note Source: http://www.geekhideout.com/urlcode.shtml
@todo This function can probably be hidden into the implementation details @todo This function can probably be hidden into the implementation details
*/ */
EXIV2API std::string urlencode(const char* str); EXIV2API std::string urlencode(std::string_view str);
/*!
@brief Decode the input url.
@param str The url needs decoding.
@return the url-decoded version of str.
@note Be sure to 'free' the returned string after use with 'delete []'.
Source: http://www.geekhideout.com/urlcode.shtml
@todo This function can probably be hidden into the implementation details
*/
EXIV2API char* urldecode(const char* str);
/*! /*!
@brief Like urlencode(char* str) but accept the input url in the std::string and modify it. @brief Like urlencode(char* str) but accept the input url in the std::string and modify it.
@ -125,15 +114,7 @@ namespace Exiv2
and its type, see stat(2). <b>errno</b> is left unchanged and its type, see stat(2). <b>errno</b> is left unchanged
in case of an error. in case of an error.
*/ */
EXIV2API bool fileExists(const std::string& path, bool ct = false); EXIV2API bool fileExists(const std::string& path);
/*!
@brief Get the path of file URL.
@param url The file URL in the format file:///path or file://host/path
@return the path of file URL.
*/
EXIV2API std::string pathOfFileUrl(const std::string& url);
/*! /*!
@brief Return a system error message and the error code (errno). @brief Return a system error message and the error code (errno).

@ -86,7 +86,7 @@ namespace Exiv2 {
@brief Not supported. Calling this function will throw an instance @brief Not supported. Calling this function will throw an instance
of Error(kerInvalidSettingForImage). of Error(kerInvalidSettingForImage).
*/ */
void setComment(const std::string& comment) override; void setComment(std::string_view comment) override;
//@} //@}
//! @name Accessors //! @name Accessors

@ -25,8 +25,6 @@
#include "datasets.hpp" #include "datasets.hpp"
#include <string>
namespace Exiv2 { namespace Exiv2 {
/*! /*!

@ -30,10 +30,6 @@
#include "image_types.hpp" #include "image_types.hpp"
#include "xmp_exiv2.hpp" #include "xmp_exiv2.hpp"
// + standard includes
#include <string>
#include <vector>
// ***************************************************************************** // *****************************************************************************
// namespace extensions // namespace extensions
namespace Exiv2 { namespace Exiv2 {
@ -199,12 +195,10 @@ namespace Exiv2 {
writeXmpFromPacket(true) or setXmpPacket(). writeXmpFromPacket(true) or setXmpPacket().
*/ */
virtual void clearXmpData(); virtual void clearXmpData();
/*!
@brief Set the image comment. The new comment is not written /// @brief Set the image comment. The comment is written to the image when writeMetadata() is called.
to the image until the writeMetadata() method is called. virtual void setComment(std::string_view comment);
@param comment String containing comment.
*/
virtual void setComment(const std::string& comment);
/*! /*!
@brief Erase any buffered comment. Comment is not removed @brief Erase any buffered comment. Comment is not removed
from the actual image until the writeMetadata() method is called. from the actual image until the writeMetadata() method is called.

@ -32,7 +32,6 @@
#include <map> #include <map>
#include <string> #include <string>
#include <stdio.h>
namespace Exiv2 { namespace Exiv2 {

@ -80,7 +80,7 @@ namespace Exiv2
@brief Todo: Not supported yet(?). Calling this function will throw @brief Todo: Not supported yet(?). Calling this function will throw
an instance of Error(kerInvalidSettingForImage). an instance of Error(kerInvalidSettingForImage).
*/ */
void setComment(const std::string& comment) override; void setComment(std::string_view comment) override;
//@} //@}
//! @name Accessors //! @name Accessors

@ -89,7 +89,7 @@ namespace Exiv2 {
@brief Not supported. MRW format does not contain a comment. @brief Not supported. MRW format does not contain a comment.
Calling this function will throw an Error(kerInvalidSettingForImage). Calling this function will throw an Error(kerInvalidSettingForImage).
*/ */
void setComment(const std::string& comment) override; void setComment(std::string_view comment) override;
//@} //@}
//! @name Accessors //! @name Accessors

@ -76,7 +76,7 @@ namespace Exiv2 {
@brief Not supported. ORF format does not contain a comment. @brief Not supported. ORF format does not contain a comment.
Calling this function will throw an Error(kerInvalidSettingForImage). Calling this function will throw an Error(kerInvalidSettingForImage).
*/ */
void setComment(const std::string& comment) override; void setComment(std::string_view comment) override;
//@} //@}
//! @name Accessors //! @name Accessors

@ -70,7 +70,7 @@ namespace Exiv2 {
/*! /*!
@brief Not supported. Calling this function will throw an Error(kerInvalidSettingForImage). @brief Not supported. Calling this function will throw an Error(kerInvalidSettingForImage).
*/ */
void setComment(const std::string& comment) override; void setComment(std::string_view comment) override;
//@} //@}
//! @name Accessors //! @name Accessors

@ -25,11 +25,6 @@
// included header files // included header files
#include "image.hpp" #include "image.hpp"
#include "basicio.hpp"
#include "types.hpp"
// + standard includes
#include <string>
// ***************************************************************************** // *****************************************************************************
// namespace extensions // namespace extensions
@ -87,7 +82,7 @@ namespace Exiv2 {
@brief Not supported. RAF format does not contain a comment. @brief Not supported. RAF format does not contain a comment.
Calling this function will throw an Error(kerInvalidSettingForImage). Calling this function will throw an Error(kerInvalidSettingForImage).
*/ */
void setComment(const std::string& comment) override; void setComment(std::string_view comment) override;
//@} //@}
//! @name Accessors //! @name Accessors

@ -80,7 +80,7 @@ namespace Exiv2 {
@brief Not supported. RW2 format does not contain a comment. @brief Not supported. RW2 format does not contain a comment.
Calling this function will throw an Error(kerInvalidSettingForImage). Calling this function will throw an Error(kerInvalidSettingForImage).
*/ */
void setComment(const std::string& comment) override; void setComment(std::string_view comment) override;
//@} //@}
//! @name Accessors //! @name Accessors

@ -26,11 +26,6 @@
// included header files // included header files
#include "metadatum.hpp" #include "metadatum.hpp"
// + standard includes
#include <string>
#include <iosfwd>
#include <memory>
// ***************************************************************************** // *****************************************************************************
// namespace extensions // namespace extensions
namespace Exiv2 { namespace Exiv2 {

@ -86,7 +86,7 @@ namespace Exiv2 {
@brief Not supported. Calling this function will throw an instance @brief Not supported. Calling this function will throw an instance
of Error(kerInvalidSettingForImage). of Error(kerInvalidSettingForImage).
*/ */
void setComment(const std::string& comment) override; void setComment(std::string_view comment) override;
//@} //@}
//! @name Accessors //! @name Accessors

@ -77,7 +77,7 @@ namespace Exiv2 {
@brief Not supported. TIFF format does not contain a comment. @brief Not supported. TIFF format does not contain a comment.
Calling this function will throw an Error(kerInvalidSettingForImage). Calling this function will throw an Error(kerInvalidSettingForImage).
*/ */
void setComment(const std::string& comment) override; void setComment(std::string_view comment) override;
//@} //@}
//! @name Accessors //! @name Accessors

@ -27,13 +27,11 @@
#include "slice.hpp" #include "slice.hpp"
// + standard includes // + standard includes
#include <cstdint>
#include <string>
#include <vector>
#include <limits>
#include <algorithm> #include <algorithm>
#include <limits>
#include <sstream> #include <sstream>
#include <string>
#include <vector>
/*! /*!
@brief Macro to make calls to member functions through a pointer more readable. @brief Macro to make calls to member functions through a pointer more readable.
@ -42,12 +40,6 @@
*/ */
#define EXV_CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember)) #define EXV_CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember))
#ifndef _MSC_VER
#define EXV_UNUSED [[gnu::unused]]
#else
#define EXV_UNUSED
#endif
// ***************************************************************************** // *****************************************************************************
// forward declarations // forward declarations
struct tm; struct tm;
@ -576,11 +568,6 @@ namespace Exiv2 {
// This is abs() - given the existence of broken compilers with Koenig // This is abs() - given the existence of broken compilers with Koenig
// lookup issues and other problems, I code this explicitly. (Remember, // lookup issues and other problems, I code this explicitly. (Remember,
// IntType may be a user-defined type). // IntType may be a user-defined type).
#ifdef _MSC_VER
#pragma warning( disable : 4146 )
#undef max
#undef min
#endif
if (n < zero) { if (n < zero) {
if (n == std::numeric_limits<IntType>::min()) { if (n == std::numeric_limits<IntType>::min()) {
n = std::numeric_limits<IntType>::max(); n = std::numeric_limits<IntType>::max();
@ -590,9 +577,6 @@ namespace Exiv2 {
} }
if (m < zero) if (m < zero)
m = -m; m = -m;
#ifdef _MSC_VER
#pragma warning( default : 4146 )
#endif
// As n and m are now positive, we can be sure that %= returns a // As n and m are now positive, we can be sure that %= returns a
// positive value (the standard guarantees this for built-in types, // positive value (the standard guarantees this for built-in types,

@ -27,11 +27,9 @@
#include "types.hpp" #include "types.hpp"
// + standard includes // + standard includes
#include <map>
#include <iomanip>
#include <memory>
#include <cstring> #include <cstring>
#include <climits> #include <iomanip>
#include <map>
// ***************************************************************************** // *****************************************************************************
// namespace extensions // namespace extensions

@ -65,7 +65,7 @@ namespace Exiv2 {
/*! /*!
@brief Not supported. Calling this function will throw an Error(kerInvalidSettingForImage). @brief Not supported. Calling this function will throw an Error(kerInvalidSettingForImage).
*/ */
void setComment(const std::string& comment) override; void setComment(std::string_view comment) override;
void setIptcData(const IptcData& /*iptcData*/) override; void setIptcData(const IptcData& /*iptcData*/) override;
//! @name Accessors //! @name Accessors

@ -64,7 +64,7 @@ namespace Exiv2 {
@brief Not supported. XMP sidecar files do not contain a comment. @brief Not supported. XMP sidecar files do not contain a comment.
Calling this function will throw an instance of Error(kerInvalidSettingForImage). Calling this function will throw an instance of Error(kerInvalidSettingForImage).
*/ */
void setComment(const std::string& comment) override; void setComment(std::string_view comment) override;
//@} //@}
//! @name Accessors //! @name Accessors

@ -36,6 +36,7 @@ add_library( exiv2lib_int OBJECT
tifffwd_int.hpp tifffwd_int.hpp
timegm.h timegm.h
unused.h unused.h
utils.hpp utils.cpp
) )
set(PUBLIC_HEADERS set(PUBLIC_HEADERS

@ -34,18 +34,22 @@
#include "image_int.hpp" #include "image_int.hpp"
// + standard includes // + standard includes
#include <string>
#include <memory>
#include <iostream>
#include <cstring> // std::memcpy
#include <cassert>
#include <fstream> // write the temporary file
#include <fcntl.h> // _O_BINARY in FileIo::FileIo #include <fcntl.h> // _O_BINARY in FileIo::FileIo
#include <sys/stat.h> // for stat, chmod
#include <sys/types.h> // for stat, chmod
#include <cassert>
#include <cstdio> // for remove, rename #include <cstdio> // for remove, rename
#include <cstdlib> // for alloc, realloc, free #include <cstdlib> // for alloc, realloc, free
#include <cstring> // std::memcpy
#include <ctime> // timestamp for the name of temporary file #include <ctime> // timestamp for the name of temporary file
#include <sys/types.h> // for stat, chmod #include <filesystem>
#include <sys/stat.h> // for stat, chmod #include <fstream> // write the temporary file
#include <iostream>
#include <memory>
#include <string>
namespace fs = std::filesystem;
#ifdef EXV_HAVE_SYS_MMAN_H #ifdef EXV_HAVE_SYS_MMAN_H
# include <sys/mman.h> // for mmap and munmap # include <sys/mman.h> // for mmap and munmap
@ -63,20 +67,25 @@
#define mode_t unsigned short #define mode_t unsigned short
// Platform specific headers for handling extended attributes (xattr)
#if defined(__APPLE__)
# include <sys/xattr.h>
#endif
#if defined(__MINGW__) || (defined(WIN32) && !defined(__CYGWIN__)) #if defined(__MINGW__) || (defined(WIN32) && !defined(__CYGWIN__))
// Windows doesn't provide nlink_t
using nlink_t = short;
# include <windows.h> # include <windows.h>
# include <io.h> # include <io.h>
#endif #endif
// ***************************************************************************** // *****************************************************************************
// class member definitions // class member definitions
namespace {
/// @brief replace each substring of the subject that matches the given search string with the given replacement.
void ReplaceStringInPlace(std::string& subject, const std::string& search, const std::string& replace)
{
size_t pos = 0;
while ((pos = subject.find(search, pos)) != std::string::npos) {
subject.replace(pos, search.length(), replace);
pos += replace.length();
}
}
}
namespace Exiv2 { namespace Exiv2 {
void BasicIo::readOrThrow(byte* buf, long rcount, ErrorCode err) { void BasicIo::readOrThrow(byte* buf, long rcount, ErrorCode err) {
const long nread = read(buf, rcount); const long nread = read(buf, rcount);
@ -117,7 +126,6 @@ namespace Exiv2 {
StructStat() = default; StructStat() = default;
mode_t st_mode{0}; //!< Permissions mode_t st_mode{0}; //!< Permissions
off_t st_size{0}; //!< Size off_t st_size{0}; //!< Size
nlink_t st_nlink{0}; //!< Number of hard links (broken on Windows, see winNumberOfLinks())
}; };
// #endif // #endif
// METHODS // METHODS
@ -130,12 +138,6 @@ namespace Exiv2 {
int switchMode(OpMode opMode); int switchMode(OpMode opMode);
//! stat wrapper for internal use //! stat wrapper for internal use
int stat(StructStat& buf) const; int stat(StructStat& buf) const;
//! copy extended attributes (xattr) from another file
void copyXattrFrom(const FileIo& src);
#if defined WIN32 && !defined __CYGWIN__
// Windows function to determine the number of hardlinks (on NTFS)
DWORD winNumberOfLinks() const;
#endif
// NOT IMPLEMENTED // NOT IMPLEMENTED
Impl(const Impl& rhs) = delete; //!< Copy constructor Impl(const Impl& rhs) = delete; //!< Copy constructor
Impl& operator=(const Impl& rhs) = delete; //!< Assignment Impl& operator=(const Impl& rhs) = delete; //!< Assignment
@ -211,96 +213,11 @@ namespace Exiv2 {
ret = ::stat(path_.c_str(), &st); ret = ::stat(path_.c_str(), &st);
if (0 == ret) { if (0 == ret) {
buf.st_size = st.st_size; buf.st_size = st.st_size;
buf.st_nlink = st.st_nlink;
buf.st_mode = st.st_mode; buf.st_mode = st.st_mode;
} }
return ret; return ret;
} // FileIo::Impl::stat } // FileIo::Impl::stat
#if defined(__APPLE__)
void FileIo::Impl::copyXattrFrom(const FileIo& src)
#else
void FileIo::Impl::copyXattrFrom(const FileIo&)
#endif
{
#if defined(__APPLE__)
ssize_t namebufSize = ::listxattr(src.p_->path_.c_str(), 0, 0, 0);
if (namebufSize < 0) {
throw Error(kerCallFailed, src.p_->path_, strError(), "listxattr");
}
if (namebufSize == 0) {
// No extended attributes in source file
return;
}
char* namebuf = new char[namebufSize];
if (::listxattr(src.p_->path_.c_str(), namebuf, namebufSize, 0) != namebufSize) {
throw Error(kerCallFailed, src.p_->path_, strError(), "listxattr");
}
for (ssize_t namebufPos = 0; namebufPos < namebufSize;) {
const char *name = namebuf + namebufPos;
namebufPos += strlen(name) + 1;
const ssize_t valueSize = ::getxattr(src.p_->path_.c_str(), name, 0, 0, 0, 0);
if (valueSize < 0) {
throw Error(kerCallFailed, src.p_->path_, strError(), "getxattr");
}
char* value = new char[valueSize];
if (::getxattr(src.p_->path_.c_str(), name, value, valueSize, 0, 0) != valueSize) {
throw Error(kerCallFailed, src.p_->path_, strError(), "getxattr");
}
// #906. Mountain Lion 'sandbox' terminates the app when we call setxattr
#ifndef __APPLE__
#ifdef EXIV2_DEBUG_MESSAGES
EXV_DEBUG << "Copying xattr \"" << name << "\" with value size " << valueSize << "\n";
#endif
if (::setxattr(path_.c_str(), name, value, valueSize, 0, 0) != 0) {
throw Error(kerCallFailed, path_, strError(), "setxattr");
}
delete [] value;
#endif
}
delete [] namebuf;
#else
// No xattr support for this platform.
#endif
} // FileIo::Impl::copyXattrFrom
#if defined WIN32 && !defined __CYGWIN__
DWORD FileIo::Impl::winNumberOfLinks() const
{
DWORD nlink = 1;
HANDLE hFd = (HANDLE)_get_osfhandle(fileno(fp_));
if (hFd != INVALID_HANDLE_VALUE) {
using GetFileInformationByHandle_t = BOOL(WINAPI*)(HANDLE, LPBY_HANDLE_FILE_INFORMATION);
HMODULE hKernel = ::GetModuleHandleA("kernel32.dll");
if (hKernel) {
GetFileInformationByHandle_t pfcn_GetFileInformationByHandle = (GetFileInformationByHandle_t)GetProcAddress(hKernel, "GetFileInformationByHandle");
if (pfcn_GetFileInformationByHandle) {
BY_HANDLE_FILE_INFORMATION fi = {0,0,0,0,0,0,0,0,0,0,0,0,0};
if (pfcn_GetFileInformationByHandle(hFd, &fi)) {
nlink = fi.nNumberOfLinks;
}
#ifdef EXIV2_DEBUG_MESSAGES
else EXV_DEBUG << "GetFileInformationByHandle failed\n";
#endif
}
#ifdef EXIV2_DEBUG_MESSAGES
else EXV_DEBUG << "GetProcAddress(hKernel, \"GetFileInformationByHandle\") failed\n";
#endif
}
#ifdef EXIV2_DEBUG_MESSAGES
else EXV_DEBUG << "GetModuleHandleA(\"kernel32.dll\") failed\n";
#endif
}
#ifdef EXIV2_DEBUG_MESSAGES
else EXV_DEBUG << "_get_osfhandle failed: INVALID_HANDLE_VALUE\n";
#endif
return nlink;
} // FileIo::Impl::winNumberOfLinks
#endif // defined WIN32 && !defined __CYGWIN__
FileIo::FileIo(const std::string& path) FileIo::FileIo(const std::string& path)
: p_(new Impl(path)) : p_(new Impl(path))
{ {
@ -435,10 +352,10 @@ namespace Exiv2 {
byte buf[4096]; byte buf[4096];
long readCount = 0; long readCount = 0;
long writeCount = 0;
long writeTotal = 0; long writeTotal = 0;
while ((readCount = src.read(buf, sizeof(buf)))) { while ((readCount = src.read(buf, sizeof(buf)))) {
writeTotal += writeCount = static_cast<long>(std::fwrite(buf, 1, readCount, p_->fp_)); long writeCount = static_cast<long>(std::fwrite(buf, 1, readCount, p_->fp_));
writeTotal += writeCount;
if (writeCount != readCount) { if (writeCount != readCount) {
// try to reset back to where write stopped // try to reset back to where write stopped
src.seek(writeCount-readCount, BasicIo::cur); src.seek(writeCount-readCount, BasicIo::cur);
@ -460,56 +377,21 @@ namespace Exiv2 {
fileIo->close(); fileIo->close();
// Check if the file can be written to, if it already exists // Check if the file can be written to, if it already exists
if (open("a+b") != 0) { if (open("a+b") != 0) {
/// \todo Use std::filesystem once C++17 can be used
// Remove the (temporary) file // Remove the (temporary) file
::remove(fileIo->path().c_str()); fs::remove(fileIo->path().c_str());
throw Error(kerFileOpenFailed, path(), "a+b", strError()); throw Error(kerFileOpenFailed, path(), "a+b", strError());
} }
close(); close();
bool statOk = true; bool statOk = true;
mode_t origStMode = 0; mode_t origStMode = 0;
std::string spf; auto pf = path().c_str();
char* pf = nullptr;
spf = path();
pf = const_cast<char*>(spf.c_str());
// Get the permissions of the file, or linked-to file, on platforms which have lstat
#ifdef EXV_HAVE_LSTAT
struct stat buf1;
if (::lstat(pf, &buf1) == -1) {
statOk = false;
#ifndef SUPPRESS_WARNINGS
EXV_WARNING << Error(kerCallFailed, pf, strError(), "::lstat") << "\n";
#endif
}
origStMode = buf1.st_mode;
DataBuf lbuf; // So that the allocated memory is freed. Must have same scope as pf
// In case path() is a symlink, get the path of the linked-to file
if (statOk && S_ISLNK(buf1.st_mode)) {
lbuf.alloc(buf1.st_size + 1);
lbuf.clear();
pf = reinterpret_cast<char*>(lbuf.data());
if (::readlink(path().c_str(), pf, lbuf.size() - 1) == -1) {
throw Error(kerCallFailed, path(), strError(), "readlink");
}
// We need the permissions of the file, not the symlink
if (::stat(pf, &buf1) == -1) {
statOk = false;
#ifndef SUPPRESS_WARNINGS
EXV_WARNING << Error(kerCallFailed, pf, strError(), "::stat") << "\n";
#endif
}
origStMode = buf1.st_mode;
}
#else // EXV_HAVE_LSTAT
Impl::StructStat buf1; Impl::StructStat buf1;
if (p_->stat(buf1) == -1) { if (p_->stat(buf1) == -1) {
statOk = false; statOk = false;
} }
origStMode = buf1.st_mode; origStMode = buf1.st_mode;
#endif // !EXV_HAVE_LSTAT
{ {
#if defined(WIN32) && defined(REPLACEFILE_IGNORE_MERGE_ERRORS) #if defined(WIN32) && defined(REPLACEFILE_IGNORE_MERGE_ERRORS)
@ -526,10 +408,8 @@ namespace Exiv2 {
BOOL ret = pfcn_ReplaceFileA(pf, fileIo->path().c_str(), NULL, REPLACEFILE_IGNORE_MERGE_ERRORS, NULL, NULL); BOOL ret = pfcn_ReplaceFileA(pf, fileIo->path().c_str(), NULL, REPLACEFILE_IGNORE_MERGE_ERRORS, NULL, NULL);
if (ret == 0) { if (ret == 0) {
if (GetLastError() == ERROR_FILE_NOT_FOUND) { if (GetLastError() == ERROR_FILE_NOT_FOUND) {
if (::rename(fileIo->path().c_str(), pf) == -1) { fs::rename(fileIo->path().c_str(), pf);
throw Error(kerFileRenameFailed, fileIo->path(), pf, strError()); fs::remove(fileIo->path().c_str());
}
::remove(fileIo->path().c_str());
} }
else { else {
throw Error(kerFileRenameFailed, fileIo->path(), pf, strError()); throw Error(kerFileRenameFailed, fileIo->path(), pf, strError());
@ -538,22 +418,18 @@ namespace Exiv2 {
} }
else { else {
if (fileExists(pf) && ::remove(pf) != 0) { if (fileExists(pf) && ::remove(pf) != 0) {
throw Error(kerCallFailed, pf, strError(), "::remove"); throw Error(kerCallFailed, pf, strError(), "fs::remove");
} }
if (::rename(fileIo->path().c_str(), pf) == -1) { fs::rename(fileIo->path().c_str(), pf);
throw Error(kerFileRenameFailed, fileIo->path(), pf, strError()); fs::remove(fileIo->path().c_str());
}
::remove(fileIo->path().c_str());
} }
} }
#else #else
if (fileExists(pf) && ::remove(pf) != 0) { if (fileExists(pf) && fs::remove(pf) != 0) {
throw Error(kerCallFailed, pf, strError(), "::remove"); throw Error(kerCallFailed, pf, strError(), "fs::remove");
}
if (::rename(fileIo->path().c_str(), pf) == -1) {
throw Error(kerFileRenameFailed, fileIo->path(), pf, strError());
} }
::remove(fileIo->path().c_str()); fs::rename(fileIo->path().c_str(), pf);
fs::remove(fileIo->path().c_str());
#endif #endif
// Check permissions of new file // Check permissions of new file
struct stat buf2; struct stat buf2;
@ -720,7 +596,7 @@ namespace Exiv2 {
return std::feof(p_->fp_) != 0; return std::feof(p_->fp_) != 0;
} }
std::string FileIo::path() const const std::string& FileIo::path() const noexcept
{ {
return p_->path_; return p_->path_;
} }
@ -802,18 +678,17 @@ namespace Exiv2 {
{ {
return type_ == bNone; return type_ == bNone;
} }
bool isInMem () const
{
return type_ == bMemory;
}
bool isKnown () const bool isKnown () const
{ {
return type_ == bKnown; return type_ == bKnown;
} }
byte* getData () const byte* getData () const
{ {
return data_; return data_;
} }
size_t getSize () const size_t getSize () const
{ {
return size_; return size_;
@ -1044,9 +919,10 @@ namespace Exiv2 {
return p_->eof_; return p_->eof_;
} }
std::string MemIo::path() const const std::string& MemIo::path() const noexcept
{ {
return "MemIo"; static std::string _path{"MemIo"};
return _path;
} }
void MemIo::populateFakeData() { void MemIo::populateFakeData() {
@ -1107,7 +983,7 @@ namespace Exiv2 {
} }
XPathIo::~XPathIo() { XPathIo::~XPathIo() {
if (isTemp_ && remove(tempFilePath_.c_str()) != 0) { if (isTemp_ && !fs::remove(tempFilePath_)) {
// error when removing file // error when removing file
// printf ("Warning: Unable to remove the temp file %s.\n", tempFilePath_.c_str()); // printf ("Warning: Unable to remove the temp file %s.\n", tempFilePath_.c_str());
} }
@ -1116,13 +992,12 @@ namespace Exiv2 {
void XPathIo::transfer(BasicIo& src) { void XPathIo::transfer(BasicIo& src) {
if (isTemp_) { if (isTemp_) {
// replace temp path to gent path. // replace temp path to gent path.
std::string currentPath = path(); auto currentPath = path();
setPath(ReplaceStringInPlace(currentPath, XPathIo::TEMP_FILE_EXT, XPathIo::GEN_FILE_EXT)); ReplaceStringInPlace(currentPath, XPathIo::TEMP_FILE_EXT, XPathIo::GEN_FILE_EXT);
// rename the file setPath(currentPath);
tempFilePath_ = path(); tempFilePath_ = path();
if (rename(currentPath.c_str(), tempFilePath_.c_str()) != 0) { fs::rename(currentPath, tempFilePath_);
// printf("Warning: Failed to rename the temp file. \n");
}
isTemp_ = false; isTemp_ = false;
// call super class method // call super class method
FileIo::transfer(src); FileIo::transfer(src);
@ -1371,21 +1246,18 @@ namespace Exiv2 {
size_t left = 0; size_t left = 0;
size_t right = 0; size_t right = 0;
size_t blockIndex = 0; size_t blockIndex = 0;
size_t i = 0; std::vector<byte> buf(p_->blockSize_);
size_t readCount = 0;
size_t blockSize = 0;
auto buf = new byte [p_->blockSize_];
size_t nBlocks = (p_->size_ + p_->blockSize_ - 1) / p_->blockSize_; size_t nBlocks = (p_->size_ + p_->blockSize_ - 1) / p_->blockSize_;
// find $left // find $left
src.seek(0, BasicIo::beg); src.seek(0, BasicIo::beg);
bool findDiff = false; bool findDiff = false;
while (blockIndex < nBlocks && !src.eof() && !findDiff) { while (blockIndex < nBlocks && !src.eof() && !findDiff) {
blockSize = p_->blocksMap_[blockIndex].getSize(); size_t blockSize = p_->blocksMap_[blockIndex].getSize();
bool isFakeData = p_->blocksMap_[blockIndex].isKnown(); // fake data bool isFakeData = p_->blocksMap_[blockIndex].isKnown(); // fake data
readCount = static_cast<size_t>(src.read(buf, static_cast<long>(blockSize))); size_t readCount = static_cast<size_t>(src.read(buf.data(), static_cast<long>(blockSize)));
byte* blockData = p_->blocksMap_[blockIndex].getData(); byte* blockData = p_->blocksMap_[blockIndex].getData();
for (i = 0; (i < readCount) && (i < blockSize) && !findDiff; i++) { for (size_t i = 0; (i < readCount) && (i < blockSize) && !findDiff; i++) {
if ((!isFakeData && buf[i] != blockData[i]) || (isFakeData && buf[i] != 0)) { if ((!isFakeData && buf[i] != blockData[i]) || (isFakeData && buf[i] != 0)) {
findDiff = true; findDiff = true;
} else { } else {
@ -1400,14 +1272,14 @@ namespace Exiv2 {
blockIndex = nBlocks; blockIndex = nBlocks;
while (blockIndex > 0 && right < src.size() && !findDiff) { while (blockIndex > 0 && right < src.size() && !findDiff) {
blockIndex--; blockIndex--;
blockSize = p_->blocksMap_[blockIndex].getSize(); size_t blockSize = p_->blocksMap_[blockIndex].getSize();
if(src.seek(-1 * (blockSize + right), BasicIo::end)) { if(src.seek(-1 * (blockSize + right), BasicIo::end)) {
findDiff = true; findDiff = true;
} else { } else {
bool isFakeData = p_->blocksMap_[blockIndex].isKnown(); // fake data bool isFakeData = p_->blocksMap_[blockIndex].isKnown(); // fake data
readCount = src.read(buf, static_cast<long>(blockSize)); size_t readCount = src.read(buf.data(), static_cast<long>(blockSize));
byte* blockData = p_->blocksMap_[blockIndex].getData(); byte* blockData = p_->blocksMap_[blockIndex].getData();
for (i = 0; (i < readCount) && (i < blockSize) && !findDiff; i++) { for (size_t i = 0; (i < readCount) && (i < blockSize) && !findDiff; i++) {
if ((!isFakeData && buf[readCount - i - 1] != blockData[blockSize - i - 1]) || (isFakeData && buf[readCount - i - 1] != 0)) { if ((!isFakeData && buf[readCount - i - 1] != blockData[blockSize - i - 1]) || (isFakeData && buf[readCount - i - 1] != 0)) {
findDiff = true; findDiff = true;
} else { } else {
@ -1417,8 +1289,6 @@ namespace Exiv2 {
} }
} }
delete []buf;
// submit to the remote machine. // submit to the remote machine.
long dataSize = static_cast<long>(src.size() - left - right); long dataSize = static_cast<long>(src.size() - left - right);
if (dataSize > 0) { if (dataSize > 0) {
@ -1585,7 +1455,7 @@ namespace Exiv2 {
return p_->eof_; return p_->eof_;
} }
std::string RemoteIo::path() const const std::string& RemoteIo::path() const noexcept
{ {
return p_->path_; return p_->path_;
} }
@ -1989,15 +1859,6 @@ namespace Exiv2 {
return file.write(buf.c_data(), buf.size()); return file.write(buf.c_data(), buf.size());
} }
std::string ReplaceStringInPlace(std::string subject, const std::string& search,
const std::string& replace) {
size_t pos = 0;
while((pos = subject.find(search, pos)) != std::string::npos) {
subject.replace(pos, search.length(), replace);
pos += replace.length();
}
return subject;
}
#ifdef EXV_USE_CURL #ifdef EXV_USE_CURL
size_t curlWriter(char* data, size_t size, size_t nmemb, size_t curlWriter(char* data, size_t size, size_t nmemb,

@ -627,11 +627,11 @@ namespace Exiv2
} }
} }
void BmffImage::setComment(const std::string& /*comment*/) void BmffImage::setComment(std::string_view /*comment*/)
{ {
// bmff files are read-only // bmff files are read-only
throw(Error(kerInvalidSettingForImage, "Image comment", "BMFF")); throw(Error(kerInvalidSettingForImage, "Image comment", "BMFF"));
} // BmffImage::setComment }
void BmffImage::openOrThrow() void BmffImage::openOrThrow()
{ {

@ -61,7 +61,7 @@ namespace Exiv2
throw(Error(kerInvalidSettingForImage, "IPTC metadata", "BMP")); throw(Error(kerInvalidSettingForImage, "IPTC metadata", "BMP"));
} }
void BmpImage::setComment(const std::string& /*comment*/) void BmpImage::setComment(std::string_view /*comment*/)
{ {
throw(Error(kerInvalidSettingForImage, "Image comment", "BMP")); throw(Error(kerInvalidSettingForImage, "Image comment", "BMP"));
} }

@ -437,7 +437,7 @@ namespace Exiv2 {
// Categories, tag 0x0023 // Categories, tag 0x0023
EXV_UNUSED constexpr TagDetails canonCategories[] = { [[maybe_unused]] constexpr TagDetails canonCategories[] = {
{ 0x0001, N_("People") }, { 0x0001, N_("People") },
{ 0x0002, N_("Scenery") }, { 0x0002, N_("Scenery") },
{ 0x0004, N_("Events") }, { 0x0004, N_("Events") },
@ -2110,7 +2110,7 @@ namespace Exiv2 {
}; };
//! ManualFlashOutput, tag 0x0029 //! ManualFlashOutput, tag 0x0029
EXV_UNUSED constexpr TagDetails canonCsManualFlashOutput[] = { [[maybe_unused]] constexpr TagDetails canonCsManualFlashOutput[] = {
{ 0x0000, N_("n/a") }, { 0x0000, N_("n/a") },
{ 0x0500, N_("Full") }, { 0x0500, N_("Full") },
{ 0x0502, N_("Medium") }, { 0x0502, N_("Medium") },

@ -37,11 +37,6 @@
#include "tags.hpp" #include "tags.hpp"
#include "types.hpp" #include "types.hpp"
// + standard includes
#include <string>
#include <iosfwd>
#include <memory>
// ***************************************************************************** // *****************************************************************************
// namespace extensions // namespace extensions
namespace Exiv2 { namespace Exiv2 {

@ -33,10 +33,6 @@
#include "tags.hpp" #include "tags.hpp"
#include "types.hpp" #include "types.hpp"
// + standard includes
#include <string>
#include <iosfwd>
// ***************************************************************************** // *****************************************************************************
// namespace extensions // namespace extensions
namespace Exiv2 { namespace Exiv2 {

@ -37,13 +37,14 @@
#include "unused.h" #include "unused.h"
// + standard includes // + standard includes
#include <utility> #include <stdio.h> // for snprintf (C99)
#include <iostream> #include <algorithm>
#include <cstring>
#include <iomanip> #include <iomanip>
#include <ios> #include <ios>
#include <iostream>
#include <sstream> #include <sstream>
#include <stdio.h> // for snprintf (C99) #include <utility>
#include <cstring>
#if defined WIN32 && !defined __CYGWIN__ #if defined WIN32 && !defined __CYGWIN__
# include <windows.h> # include <windows.h>
@ -284,8 +285,6 @@ namespace Exiv2 {
//@{ //@{
//! Get the value of the erase flag, see also setErase(bool on). //! Get the value of the erase flag, see also setErase(bool on).
bool erase() const { return erase_; } bool erase() const { return erase_; }
//! Get the value of the overwrite flag, see also setOverwrite(bool on).
bool overwrite() const { return overwrite_; }
//@} //@}
private: private:
@ -293,7 +292,6 @@ namespace Exiv2 {
bool prepareIptcTarget(const char* to, bool force =false); bool prepareIptcTarget(const char* to, bool force =false);
bool prepareXmpTarget(const char* to, bool force =false); bool prepareXmpTarget(const char* to, bool force =false);
std::string computeExifDigest(bool tiff); std::string computeExifDigest(bool tiff);
std::string computeIptcDigest();
// DATA // DATA
static const Conversion conversion_[]; //<! Conversion rules static const Conversion conversion_[]; //<! Conversion rules
@ -1084,7 +1082,6 @@ namespace Exiv2 {
else { else {
sec = (min - static_cast<int>(min)) * 60.0; sec = (min - static_cast<int>(min)) * 60.0;
min = static_cast<double>(static_cast<int>(min)); min = static_cast<double>(static_cast<int>(min));
sep2 = ',';
} }
if ( in.bad() || !(ref == 'N' || ref == 'S' || ref == 'E' || ref == 'W') if ( in.bad() || !(ref == 'N' || ref == 'S' || ref == 'E' || ref == 'W')
@ -1256,28 +1253,6 @@ namespace Exiv2 {
writeExifDigest(); writeExifDigest();
} }
std::string Converter::computeIptcDigest()
{
#ifdef EXV_HAVE_XMP_TOOLKIT
std::ostringstream res;
MD5_CTX context;
unsigned char digest[16];
MD5Init(&context);
DataBuf data = IptcParser::encode(*iptcData_);
MD5Update(&context, data.c_data(), data.size());
MD5Final(digest, &context);
res << std::setw(2) << std::setfill('0') << std::hex << std::uppercase;
for (auto&& i : digest) {
res << static_cast<int>(i);
}
return res.str();
#else
return std::string("");
#endif
}
// ************************************************************************* // *************************************************************************
// free functions // free functions
@ -1288,6 +1263,7 @@ namespace Exiv2 {
converter.cnvToXmp(); converter.cnvToXmp();
} }
/// \todo not used internally. We should at least have unit tests for this.
void moveExifToXmp(ExifData& exifData, XmpData& xmpData) void moveExifToXmp(ExifData& exifData, XmpData& xmpData)
{ {
Converter converter(exifData, xmpData); Converter converter(exifData, xmpData);
@ -1301,6 +1277,7 @@ namespace Exiv2 {
converter.cnvFromXmp(); converter.cnvFromXmp();
} }
/// \todo not used internally. We should at least have unit tests for this.
void moveXmpToExif(XmpData& xmpData, ExifData& exifData) void moveXmpToExif(XmpData& xmpData, ExifData& exifData)
{ {
Converter converter(exifData, xmpData); Converter converter(exifData, xmpData);
@ -1323,6 +1300,7 @@ namespace Exiv2 {
converter.cnvToXmp(); converter.cnvToXmp();
} }
/// \todo not used internally. We should at least have unit tests for this.
void moveIptcToXmp(IptcData& iptcData, XmpData& xmpData, const char *iptcCharset) void moveIptcToXmp(IptcData& iptcData, XmpData& xmpData, const char *iptcCharset)
{ {
if (!iptcCharset) iptcCharset = iptcData.detectCharset(); if (!iptcCharset) iptcCharset = iptcData.detectCharset();
@ -1338,6 +1316,7 @@ namespace Exiv2 {
converter.cnvFromXmp(); converter.cnvFromXmp();
} }
/// \todo not used internally. We should at least have unit tests for this.
void moveXmpToIptc(XmpData& xmpData, IptcData& iptcData) void moveXmpToIptc(XmpData& xmpData, IptcData& iptcData)
{ {
Converter converter(iptcData, xmpData); Converter converter(iptcData, xmpData);

@ -81,7 +81,7 @@ namespace Exiv2 {
printTiffStructure(io(),out,option,depth-1); printTiffStructure(io(),out,option,depth-1);
} }
void Cr2Image::setComment(const std::string& /*comment*/) void Cr2Image::setComment(std::string_view /*comment*/)
{ {
// not supported // not supported
throw(Error(kerInvalidSettingForImage, "Image comment", "CR2")); throw(Error(kerInvalidSettingForImage, "Image comment", "CR2"));

@ -147,9 +147,6 @@ namespace Exiv2 {
// Parse the image, starting with a CIFF header component // Parse the image, starting with a CIFF header component
CiffHeader header; CiffHeader header;
header.read(pData, size); header.read(pData, size);
#ifdef EXIV2_DEBUG_MESSAGES
header.print(std::cerr);
#endif
header.decode(*pCrwImage); header.decode(*pCrwImage);
// a hack to get absolute offset of preview image inside CRW structure // a hack to get absolute offset of preview image inside CRW structure

@ -21,13 +21,13 @@
#include "crwimage_int.hpp" #include "crwimage_int.hpp"
#include "canonmn_int.hpp" #include "canonmn_int.hpp"
#include "i18n.h" // NLS support. #include "i18n.h" // NLS support.
#include "timegm.h"
#include "unused.h" #include "unused.h"
#include "error.hpp" #include "error.hpp"
#include "enforce.hpp" #include "enforce.hpp"
#include <cassert> #include <cassert>
#include <ctime> #include <ctime>
#include <iostream>
// ***************************************************************************** // *****************************************************************************
// local declarations // local declarations
@ -53,7 +53,6 @@ namespace {
// ***************************************************************************** // *****************************************************************************
// local definitions // local definitions
namespace { namespace {
//! @cond IGNORE
constexpr RotationMap::OmList RotationMap::omList_[] = { constexpr RotationMap::OmList RotationMap::omList_[] = {
{ 1, 0 }, { 1, 0 },
{ 3, 180 }, { 3, 180 },
@ -87,7 +86,6 @@ namespace {
} }
return d; return d;
} }
//! @endcond
} // namespace } // namespace
namespace Exiv2 { namespace Exiv2 {
@ -503,16 +501,6 @@ namespace Exiv2 {
} }
} // CiffComponent::writeDirEntry } // CiffComponent::writeDirEntry
void CiffHeader::print(std::ostream& os, const std::string& prefix) const
{
std::ios::fmtflags f( os.flags() );
os << prefix
<< _("Header, offset") << " = 0x" << std::setw(8) << std::setfill('0')
<< std::hex << std::right << offset_ << "\n";
if (pRootDir_) pRootDir_->print(os, byteOrder_, prefix);
os.flags(f);
} // CiffHeader::print
void CiffComponent::print(std::ostream& os, void CiffComponent::print(std::ostream& os,
ByteOrder byteOrder, ByteOrder byteOrder,
const std::string& prefix) const const std::string& prefix) const
@ -617,10 +605,10 @@ namespace Exiv2 {
CiffComponent* CiffDirectory::doFindComponent(uint16_t crwTagId, CiffComponent* CiffDirectory::doFindComponent(uint16_t crwTagId,
uint16_t crwDir) const uint16_t crwDir) const
{ {
CiffComponent* cc;
for (auto&& component : components_) { for (auto&& component : components_) {
cc = component->findComponent(crwTagId, crwDir); auto cc = component->findComponent(crwTagId, crwDir);
if (cc) return cc; if (cc)
return cc;
} }
return nullptr; return nullptr;
} // CiffDirectory::doFindComponent } // CiffDirectory::doFindComponent

@ -26,8 +26,6 @@
#include "image.hpp" #include "image.hpp"
// + standard includes // + standard includes
#include <iosfwd>
#include <string>
#include <vector> #include <vector>
#include <stack> #include <stack>
@ -481,13 +479,7 @@ namespace Exiv2 {
@param image Image to add metadata to @param image Image to add metadata to
*/ */
void decode(Image& image) const; void decode(Image& image) const;
/*!
@brief Print debug info for the CRW image to \em os.
@param os Output stream to write to.
@param prefix Prefix to be written before each line of output.
*/
void print(std::ostream& os, const std::string& prefix ="") const;
//! Return the byte order (little or big endian). //! Return the byte order (little or big endian).
ByteOrder byteOrder() const { return byteOrder_; } ByteOrder byteOrder() const { return byteOrder_; }
/*! /*!

@ -32,6 +32,7 @@
#include "basicio.hpp" #include "basicio.hpp"
#include "error.hpp" #include "error.hpp"
#include "futils.hpp" #include "futils.hpp"
#include "utils.hpp"
#include "version.hpp" #include "version.hpp"
// + standard includes // + standard includes
@ -103,11 +104,6 @@ namespace {
// closing part of all valid XMP trailers // closing part of all valid XMP trailers
const std::string xmpTrailerEnd = "?>"; const std::string xmpTrailerEnd = "?>";
constexpr bool startsWith(const std::string_view& s, const std::string_view& start)
{
return s.find(start) == 0;
}
//! Write data into temp file, taking care of errors //! Write data into temp file, taking care of errors
void writeTemp(BasicIo& tempIo, const byte* data, size_t size) void writeTemp(BasicIo& tempIo, const byte* data, size_t size)
{ {
@ -1098,7 +1094,7 @@ namespace Exiv2
return "application/postscript"; return "application/postscript";
} }
void EpsImage::setComment(const std::string& /*comment*/) void EpsImage::setComment(std::string_view /*comment*/)
{ {
throw Error(kerInvalidSettingForImage, "Image comment", "EPS"); throw Error(kerInvalidSettingForImage, "Image comment", "EPS");
} }

@ -24,7 +24,6 @@
// ***************************************************************************** // *****************************************************************************
// included header files // included header files
#include "tags.hpp" #include "tags.hpp"
#include "types.hpp"
// ***************************************************************************** // *****************************************************************************
// namespace extensions // namespace extensions

@ -27,19 +27,23 @@
#include "image_int.hpp" #include "image_int.hpp"
// + standard includes // + standard includes
#include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h>
#include <algorithm>
#include <array> #include <array>
#include <cstdio>
#include <cerrno> #include <cerrno>
#include <sstream> #include <cstdio>
#include <cstring> #include <cstring>
#include <algorithm> #include <filesystem>
#include <sstream>
#include <stdexcept> #include <stdexcept>
#ifdef EXV_HAVE_UNISTD_H #ifdef EXV_HAVE_UNISTD_H
#include <unistd.h> // for stat() #include <unistd.h> // for stat()
#endif #endif
namespace fs = std::filesystem;
#if defined(WIN32) #if defined(WIN32)
#include <windows.h> #include <windows.h>
#include <psapi.h> // For access to GetModuleFileNameEx #include <psapi.h> // For access to GetModuleFileNameEx
@ -101,52 +105,43 @@ namespace Exiv2 {
return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10; return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
} }
std::string urlencode(const char* str) { std::string urlencode(std::string_view str)
const char* pstr = str; {
// \todo try to use std::string for buf and avoid the creation of another string for just std::string encoded;
// returning the final value encoded.reserve(str.size() * 3);
auto buf = new char[strlen(str) * 3 + 1]; for (uint8_t c : str) {
char* pbuf = buf; if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~')
while (*pstr) { encoded += c;
if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~') else if (c == ' ')
*pbuf++ = *pstr; encoded += '+';
else if (*pstr == ' ') else {
*pbuf++ = '+'; encoded += '%';
else encoded += to_hex(c >> 4);
*pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15); encoded += to_hex(c & 15);
pstr++;
}
*pbuf = '\0';
std::string ret(buf);
delete [] buf;
return ret;
}
char* urldecode(const char* str) {
const char* pstr = str;
auto buf = new char[(strlen(str) + 1)];
char* pbuf = buf;
while (*pstr) {
if (*pstr == '%') {
if (pstr[1] && pstr[2]) {
*pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
pstr += 2;
}
} else if (*pstr == '+') {
*pbuf++ = ' ';
} else {
*pbuf++ = *pstr;
} }
pstr++;
} }
*pbuf = '\0'; encoded.shrink_to_fit();
return buf; return encoded;
} }
void urldecode(std::string& str) { void urldecode(std::string& str)
char* decodeStr = Exiv2::urldecode(str.c_str()); {
str = std::string(decodeStr); size_t idxIn{0}, idxOut{0};
delete [] decodeStr; size_t sizeStr = str.size();
while (idxIn < sizeStr) {
if (str[idxIn] == '%') {
if (str[idxIn+1] && str[idxIn+2]) {
str[idxOut++] = from_hex(str[idxIn+1]) << 4 | from_hex(str[idxIn+2]);
idxIn += 2;
}
} else if (str[idxIn] == '+') {
str[idxOut++] = ' ';
} else {
str[idxOut++] = str[idxIn];
}
idxIn++;
}
str.erase(idxOut);
} }
// https://stackoverflow.com/questions/342409/how-do-i-base64-encode-decode-in-c // https://stackoverflow.com/questions/342409/how-do-i-base64-encode-decode-in-c
@ -157,7 +152,6 @@ namespace Exiv2 {
int base64encode(const void* data_buf, size_t dataLength, char* result, size_t resultSize) { int base64encode(const void* data_buf, size_t dataLength, char* result, size_t resultSize) {
auto encoding_table = base64_encode; auto encoding_table = base64_encode;
size_t mod_table[] = {0, 2, 1};
size_t output_length = 4 * ((dataLength + 2) / 3); size_t output_length = 4 * ((dataLength + 2) / 3);
int rc = result && data_buf && output_length < resultSize ? 1 : 0; int rc = result && data_buf && output_length < resultSize ? 1 : 0;
@ -177,6 +171,7 @@ namespace Exiv2 {
result[j++] = encoding_table[(triple >> 0 * 6) & 0x3F]; result[j++] = encoding_table[(triple >> 0 * 6) & 0x3F];
} }
const size_t mod_table[] = {0, 2, 1};
for (size_t i = 0; i < mod_table[dataLength % 3]; i++) for (size_t i = 0; i < mod_table[dataLength % 3]; i++)
result[output_length - 1 - i] = '='; result[output_length - 1 - i] = '=';
result[output_length]=0; result[output_length]=0;
@ -252,25 +247,12 @@ namespace Exiv2 {
return result; return result;
} // fileProtocol } // fileProtocol
bool fileExists(const std::string& path, bool ct) bool fileExists(const std::string& path)
{ {
// special case: accept "-" (means stdin) if (fileProtocol(path) != pFile) {
if (path == "-" || fileProtocol(path) != pFile) {
return true; return true;
} }
return fs::exists(path);
struct stat buf;
int ret = ::stat(path.c_str(), &buf);
if (0 != ret) return false;
if (ct && !S_ISREG(buf.st_mode)) return false;
return true;
} // fileExists
std::string pathOfFileUrl(const std::string& url) {
std::string path = url.substr(7);
size_t found = path.find('/');
if (found == std::string::npos) return path;
return path.substr(found);
} }
std::string strError() std::string strError()

@ -58,7 +58,7 @@ namespace Exiv2 {
throw(Error(kerInvalidSettingForImage, "IPTC metadata", "GIF")); throw(Error(kerInvalidSettingForImage, "IPTC metadata", "GIF"));
} }
void GifImage::setComment(const std::string& /*comment*/) void GifImage::setComment(std::string_view /*comment*/)
{ {
// not supported // not supported
throw(Error(kerInvalidSettingForImage, "Image comment", "GIF")); throw(Error(kerInvalidSettingForImage, "Image comment", "GIF"));

@ -239,8 +239,6 @@ int Exiv2::http(Exiv2::Dictionary& request,Exiv2::Dictionary& response,std::stri
servername_p = Proxy.Host.c_str(); servername_p = Proxy.Host.c_str();
port_p = Proxy.Port.c_str(); port_p = Proxy.Port.c_str();
page = url.c_str(); page = url.c_str();
std::string p(proxy?proxi:PROXI);
// std::cerr << p << '=' << prox << " page = " << page << std::endl;
} }
if ( !port [0] ) port = "80"; if ( !port [0] ) port = "80";
if ( !port_p[0] ) port_p = "80"; if ( !port_p[0] ) port_p = "80";

@ -135,6 +135,12 @@ namespace {
{ ImageType::none, nullptr, nullptr, amNone, amNone, amNone, amNone } { ImageType::none, nullptr, nullptr, amNone, amNone, amNone, amNone }
}; };
std::string pathOfFileUrl(const std::string& url) {
std::string path = url.substr(7);
size_t found = path.find('/');
return (found == std::string::npos) ? path : path.substr(found);
}
} // namespace } // namespace
// ***************************************************************************** // *****************************************************************************
@ -278,6 +284,7 @@ namespace Exiv2 {
return Image::byteSwap(v,bSwap); return Image::byteSwap(v,bSwap);
} }
/// \todo not used internally. At least we should test it
uint64_t Image::byteSwap8(const DataBuf& buf,size_t offset,bool bSwap) uint64_t Image::byteSwap8(const DataBuf& buf,size_t offset,bool bSwap)
{ {
uint64_t v = 0; uint64_t v = 0;
@ -367,7 +374,6 @@ namespace Exiv2 {
// Break for unknown tag types else we may segfault. // Break for unknown tag types else we may segfault.
if ( !typeValid(type) ) { if ( !typeValid(type) ) {
EXV_ERROR << "invalid type in tiff structure" << type << std::endl; EXV_ERROR << "invalid type in tiff structure" << type << std::endl;
start = 0; // break from do loop
throw Error(kerInvalidTypeValue); throw Error(kerInvalidTypeValue);
} }
@ -519,7 +525,6 @@ namespace Exiv2 {
out << Internal::indent(depth) << "END " << io.path() << std::endl; out << Internal::indent(depth) << "END " << io.path() << std::endl;
} }
out.flush(); out.flush();
depth--;
} }
void Image::printTiffStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStructureOption option,int depth,size_t offset /*=0*/) void Image::printTiffStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStructureOption option,int depth,size_t offset /*=0*/)
@ -576,6 +581,7 @@ namespace Exiv2 {
return xmpPacket_; return xmpPacket_;
} }
/// \todo not used internally. At least we should test it
void Image::setMetadata(const Image& image) void Image::setMetadata(const Image& image)
{ {
if (checkMode(mdExif) & amWrite) { if (checkMode(mdExif) & amWrite) {
@ -624,7 +630,6 @@ namespace Exiv2 {
void Image::setXmpPacket(const std::string& xmpPacket) void Image::setXmpPacket(const std::string& xmpPacket)
{ {
xmpPacket_ = xmpPacket;
if ( XmpParser::decode(xmpData_, xmpPacket) ) { if ( XmpParser::decode(xmpData_, xmpPacket) ) {
throw Error(kerInvalidXMP); throw Error(kerInvalidXMP);
} }
@ -657,7 +662,7 @@ namespace Exiv2 {
comment_.erase(); comment_.erase();
} }
void Image::setComment(const std::string& comment) void Image::setComment(std::string_view comment)
{ {
comment_ = comment; comment_ = comment;
} }
@ -749,6 +754,7 @@ namespace Exiv2 {
return ImageFactory::checkType(imageType_, *io_, false); return ImageFactory::checkType(imageType_, *io_, false);
} }
/// \todo not used internally. At least we should test it
bool Image::supportsMetadata(MetadataId metadataId) const bool Image::supportsMetadata(MetadataId metadataId) const
{ {
return (supportedMetadata_ & metadataId) != 0; return (supportedMetadata_ & metadataId) != 0;

@ -57,52 +57,6 @@ namespace Exiv2
return result; return result;
} }
std::string binaryToHex(const byte* data, size_t size)
{
std::stringstream hexOutput;
auto tl = size_t(size / 16) * 16;
auto tl_offset = size_t(size) - tl;
for (size_t loop = 0; loop < size; loop++) {
if (data[loop] < 16) {
hexOutput << "0";
}
hexOutput << std::hex << static_cast<int>(data[loop]);
if ((loop % 8) == 7) {
hexOutput << " ";
}
if ((loop % 16) == 15 || loop == (tl + tl_offset - 1)) {
int max = 15;
if (loop >= tl) {
max = int(tl_offset) - 1;
for (int offset = 0; offset < int(16 - tl_offset); offset++) {
if ((offset % 8) == 7) {
hexOutput << " ";
}
hexOutput << " ";
}
}
hexOutput << " ";
for (int offset = max; offset >= 0; offset--) {
if (offset == (max - 8)) {
hexOutput << " ";
}
byte c = '.';
if (data[loop - offset] >= 0x20 && data[loop - offset] <= 0x7E) {
c = data[loop - offset];
}
hexOutput << static_cast<char>(c);
}
hexOutput << std::endl;
}
}
hexOutput << std::endl << std::endl << std::endl;
return hexOutput.str();
}
std::string indent(int32_t d) std::string indent(int32_t d)
{ {
std::string result; std::string result;

@ -120,14 +120,7 @@ namespace Exiv2 {
return binaryToStringHelper<T>(sl); return binaryToStringHelper<T>(sl);
} }
/*! /// @brief indent output for kpsRecursive in \em printStructure() \em .
@brief format binary for display of raw data .
*/
std::string binaryToHex(const byte *data, size_t size);
/*!
@brief indent output for kpsRecursive in \em printStructure() \em .
*/
std::string indent(int32_t depth); std::string indent(int32_t depth);
}} // namespace Internal, Exiv2 }} // namespace Internal, Exiv2

@ -327,11 +327,13 @@ namespace Exiv2 {
FindIptcdatum(dataset, record)); FindIptcdatum(dataset, record));
} }
/// \todo not used internally. At least we should test it
void IptcData::sortByKey() void IptcData::sortByKey()
{ {
std::sort(iptcMetadata_.begin(), iptcMetadata_.end(), cmpMetadataByKey); std::sort(iptcMetadata_.begin(), iptcMetadata_.end(), cmpMetadataByKey);
} }
/// \todo not used internally. At least we should test it
void IptcData::sortByTag() void IptcData::sortByTag()
{ {
std::sort(iptcMetadata_.begin(), iptcMetadata_.end(), cmpMetadataByTag); std::sort(iptcMetadata_.begin(), iptcMetadata_.end(), cmpMetadataByTag);
@ -350,8 +352,7 @@ namespace Exiv2 {
size_t i = 0; size_t i = 0;
while (i < bytes.size() - 3 && bytes.at(i) != 0x1c) while (i < bytes.size() - 3 && bytes.at(i) != 0x1c)
i++; i++;
depth++; out << Internal::indent(++depth) << "Record | DataSet | Name | Length | Data" << std::endl;
out << Internal::indent(depth) << "Record | DataSet | Name | Length | Data" << std::endl;
while (i < bytes.size() - 3) { while (i < bytes.size() - 3) {
if (bytes.at(i) != 0x1c) { if (bytes.at(i) != 0x1c) {
break; break;
@ -370,7 +371,6 @@ namespace Exiv2 {
<< std::endl; << std::endl;
i += 5 + len; i += 5 + len;
} }
depth--;
} }
const char *IptcData::detectCharset() const const char *IptcData::detectCharset() const

@ -158,11 +158,11 @@ namespace Exiv2
return "image/jp2"; return "image/jp2";
} }
void Jp2Image::setComment(const std::string& /*comment*/) void Jp2Image::setComment(std::string_view /*comment*/)
{ {
// Todo: implement me! // Todo: implement me!
throw(Error(kerInvalidSettingForImage, "Image comment", "JP2")); throw(Error(kerInvalidSettingForImage, "Image comment", "JP2"));
} // Jp2Image::setComment }
static void lf(std::ostream& out,bool& bLF) static void lf(std::ostream& out,bool& bLF)
{ {
@ -221,7 +221,6 @@ static void boxes_check(size_t b,size_t m)
throw Error(kerNotAnImage, "JPEG-2000"); throw Error(kerNotAnImage, "JPEG-2000");
} }
long position = 0;
Jp2BoxHeader box = {0,0}; Jp2BoxHeader box = {0,0};
Jp2BoxHeader subBox = {0,0}; Jp2BoxHeader subBox = {0,0};
Jp2ImageHeaderBox ihdr = {0,0,0,0,0,0,0,0}; Jp2ImageHeaderBox ihdr = {0,0,0,0,0,0,0,0};
@ -231,7 +230,7 @@ static void boxes_check(size_t b,size_t m)
while (io_->read(reinterpret_cast<byte*>(&box), sizeof(box)) == sizeof(box)) { while (io_->read(reinterpret_cast<byte*>(&box), sizeof(box)) == sizeof(box)) {
boxes_check(boxes++,boxem ); boxes_check(boxes++,boxem );
position = io_->tell(); long position = io_->tell();
box.length = getLong(reinterpret_cast<byte*>(&box.length), bigEndian); box.length = getLong(reinterpret_cast<byte*>(&box.length), bigEndian);
box.type = getLong(reinterpret_cast<byte*>(&box.type), bigEndian); box.type = getLong(reinterpret_cast<byte*>(&box.type), bigEndian);
#ifdef EXIV2_DEBUG_MESSAGES #ifdef EXIV2_DEBUG_MESSAGES
@ -490,7 +489,6 @@ static void boxes_check(size_t b,size_t m)
if ( bPrint || bXMP || bICC || bIPTCErase ) { if ( bPrint || bXMP || bICC || bIPTCErase ) {
long position = 0;
Jp2BoxHeader box = {1,1}; Jp2BoxHeader box = {1,1};
Jp2BoxHeader subBox = {1,1}; Jp2BoxHeader subBox = {1,1};
Jp2UuidBox uuid = {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; Jp2UuidBox uuid = {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
@ -498,7 +496,7 @@ static void boxes_check(size_t b,size_t m)
while (box.length && box.type != kJp2BoxTypeClose && while (box.length && box.type != kJp2BoxTypeClose &&
io_->read(reinterpret_cast<byte*>(&box), sizeof(box)) == sizeof(box)) { io_->read(reinterpret_cast<byte*>(&box), sizeof(box)) == sizeof(box)) {
position = io_->tell(); long position = io_->tell();
box.length = getLong(reinterpret_cast<byte*>(&box.length), bigEndian); box.length = getLong(reinterpret_cast<byte*>(&box.length), bigEndian);
box.type = getLong(reinterpret_cast<byte*>(&box.type), bigEndian); box.type = getLong(reinterpret_cast<byte*>(&box.type), bigEndian);
enforce(box.length <= sizeof(box)+io_->size()-io_->tell() , Exiv2::kerCorruptedMetadata); enforce(box.length <= sizeof(box)+io_->size()-io_->tell() , Exiv2::kerCorruptedMetadata);

@ -32,11 +32,15 @@
#include "tiffvisitor_int.hpp" #include "tiffvisitor_int.hpp"
#include "tiffimage.hpp" #include "tiffimage.hpp"
#include "tiffimage_int.hpp" #include "tiffimage_int.hpp"
#include "utils.hpp"
// + standard includes // + standard includes
#include <string> #include <array>
#include <filesystem>
#include <fstream> #include <fstream>
#include <cstring> #include <iostream>
namespace fs = std::filesystem;
#if defined(__MINGW32__) || defined(__MINGW64__) #if defined(__MINGW32__) || defined(__MINGW64__)
#ifndef __MINGW__ #ifndef __MINGW__
@ -52,25 +56,6 @@
#include <windows.h> #include <windows.h>
#include <direct.h> // _getcwd #include <direct.h> // _getcwd
#include <shlobj.h> #include <shlobj.h>
/* older SDKs not have these */
# ifndef CSIDL_MYMUSIC
# define CSIDL_MYMUSIC 13
# endif
# ifndef CSIDL_MYVIDEO
# define CSIDL_MYVIDEO 14
# endif
# ifndef CSIDL_INTERNET_CACHE
# define CSIDL_INTERNET_CACHE 32
# endif
# ifndef CSIDL_COMMON_APPDATA
# define CSIDL_COMMON_APPDATA 35
# endif
# ifndef CSIDL_MYPICTURES
# define CSIDL_MYPICTURES 0x27
# endif
# ifndef CSIDL_COMMON_DOCUMENTS
# define CSIDL_COMMON_DOCUMENTS 46
# endif
# ifndef CSIDL_PROFILE # ifndef CSIDL_PROFILE
# define CSIDL_PROFILE 40 # define CSIDL_PROFILE 40
# endif # endif
@ -96,7 +81,6 @@ namespace {
namespace Exiv2 { namespace Exiv2 {
namespace Internal { namespace Internal {
// C++17 use std::filesystem
// Function first looks for a config file in current working directory // Function first looks for a config file in current working directory
// on Win the file should be named "exiv2.ini" // on Win the file should be named "exiv2.ini"
// on Lin the file should be named ".exiv2" // on Lin the file should be named ".exiv2"
@ -104,36 +88,27 @@ namespace Exiv2 {
// which is the user profile path on win and the home dir on linux // which is the user profile path on win and the home dir on linux
std::string getExiv2ConfigPath() std::string getExiv2ConfigPath()
{ {
std::string dir;
#if defined(_MSC_VER) || defined(__MINGW__) #if defined(_MSC_VER) || defined(__MINGW__)
std::string inifile("exiv2.ini"); std::string inifile("exiv2.ini");
#else #else
std::string inifile(".exiv2"); std::string inifile(".exiv2");
#endif #endif
auto currentPath = fs::current_path();
// first lets get the current working directory to check if there is a config file auto iniPath = currentPath / inifile;
char buffer[1024]; if (fs::exists(iniPath)) {
#if defined(_MSC_VER) || defined(__MINGW__) return iniPath.string();
auto path = _getcwd(buffer, sizeof(buffer));
#else
auto path = getcwd(buffer, sizeof(buffer));
#endif
dir = std::string(path ? path : "");
auto const filename = dir + EXV_SEPARATOR_CHR + inifile;
// true if the file exists
if (std::ifstream(filename).good()) {
return filename;
} }
#if defined(_MSC_VER) || defined(__MINGW__) #if defined(_MSC_VER) || defined(__MINGW__)
if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_PROFILE, NULL, 0, path))) { char buffer[1024];
dir = std::string(path); if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_PROFILE, NULL, 0, buffer))) {
currentPath = buffer;
} }
#else #else
struct passwd* pw = getpwuid(getuid()); struct passwd* pw = getpwuid(getuid());
dir = std::string(pw ? pw->pw_dir : ""); currentPath = std::string(pw ? pw->pw_dir : "");
#endif #endif
return dir + EXV_SEPARATOR_CHR + inifile; return (currentPath / inifile).string();
} }
std::string readExiv2Config(const std::string& section, const std::string& value, const std::string& def) std::string readExiv2Config(const std::string& section, const std::string& value, const std::string& def)
@ -1223,11 +1198,8 @@ namespace Exiv2 {
{ {
// Not valid for models beginning // Not valid for models beginning
std::string model = getExifModel(pRoot); std::string model = getExifModel(pRoot);
for (auto& m : { "SLT-", "HV", "ILCA-" }) { const std::array strs { "SLT-", "HV", "ILCA-"};
if (model.find(m) == 0) return std::any_of(strs.begin(), strs.end(), [&model](auto& m){return startsWith(model, m);}) ? -1 : 0;
return -1;
}
return 0;
} }
int sonyMisc2bSelector(uint16_t /*tag*/, const byte* /*pData*/, uint32_t /*size*/, TiffComponent* const pRoot) int sonyMisc2bSelector(uint16_t /*tag*/, const byte* /*pData*/, uint32_t /*size*/, TiffComponent* const pRoot)

@ -24,12 +24,8 @@
// included header files // included header files
#include "tifffwd_int.hpp" #include "tifffwd_int.hpp"
#include "tags_int.hpp" #include "tags_int.hpp"
#include "ini.hpp"
#include "types.hpp" #include "types.hpp"
// + standard includes
#include <string>
// ***************************************************************************** // *****************************************************************************
// namespace extensions // namespace extensions
namespace Exiv2 { namespace Exiv2 {

@ -63,7 +63,7 @@ namespace Exiv2 {
}; };
//! Lookup table to translate Minolta image quality values to readable labels //! Lookup table to translate Minolta image quality values to readable labels
EXV_UNUSED constexpr TagDetails minoltaImageQuality[] = { [[maybe_unused]] constexpr TagDetails minoltaImageQuality[] = {
{ 0, N_("Raw") }, { 0, N_("Raw") },
{ 1, N_("Super Fine") }, { 1, N_("Super Fine") },
{ 2, N_("Fine") }, { 2, N_("Fine") },
@ -273,7 +273,7 @@ namespace Exiv2 {
}; };
//! Lookup table to translate Minolta Std camera settings AF points values to readable labels //! Lookup table to translate Minolta Std camera settings AF points values to readable labels
EXV_UNUSED constexpr TagDetails minoltaAFPointsStd[] = { [[maybe_unused]] constexpr TagDetails minoltaAFPointsStd[] = {
{ 0, N_("Center") }, { 0, N_("Center") },
{ 1, N_("Top") }, { 1, N_("Top") },
{ 2, N_("Top-right") }, { 2, N_("Top-right") },
@ -2490,16 +2490,5 @@ namespace Exiv2 {
return EXV_PRINT_TAG(minoltaSonyZoneMatching)(os, value, metadata); return EXV_PRINT_TAG(minoltaSonyZoneMatching)(os, value, metadata);
} }
std::ostream& printMinoltaSonyFlashExposureComp(std::ostream& os, const Value& value, const ExifData*)
{
std::ios::fmtflags f( os.flags() );
if (value.count() != 1 || value.typeId() != signedRational) {
return os << "(" << value << ")";
}
os << std::fixed << std::setprecision(2) << value.toFloat(0) << " EV";
os.flags(f);
return os;
}
} // namespace Internal } // namespace Internal
} // namespace Exiv2 } // namespace Exiv2

@ -136,9 +136,6 @@ namespace Exiv2 {
//! Print Minolta/Sony ZoneMatching values to readable labels. //! Print Minolta/Sony ZoneMatching values to readable labels.
std::ostream& printMinoltaSonyZoneMatching(std::ostream&, const Value&, const ExifData*); std::ostream& printMinoltaSonyZoneMatching(std::ostream&, const Value&, const ExifData*);
//! Print Minolta/Sony FlashExposureComp values to readable labels.
std::ostream& printMinoltaSonyFlashExposureComp(std::ostream&, const Value&, const ExifData*);
// TODO: Added shared methods here. // TODO: Added shared methods here.
}} // namespace Internal, Exiv2 }} // namespace Internal, Exiv2

@ -79,7 +79,7 @@ namespace Exiv2 {
throw(Error(kerInvalidSettingForImage, "IPTC metadata", "MRW")); throw(Error(kerInvalidSettingForImage, "IPTC metadata", "MRW"));
} }
void MrwImage::setComment(const std::string& /*comment*/) void MrwImage::setComment(std::string_view /*comment*/)
{ {
// not supported // not supported
throw(Error(kerInvalidSettingForImage, "Image comment", "MRW")); throw(Error(kerInvalidSettingForImage, "Image comment", "MRW"));

@ -490,7 +490,7 @@ namespace Exiv2 {
}; };
//! FocusMode, tag 0x0301 //! FocusMode, tag 0x0301
EXV_UNUSED constexpr TagDetails olympusCsFocusMode[] = { [[maybe_unused]] constexpr TagDetails olympusCsFocusMode[] = {
{ 0, N_("Single AF") }, { 0, N_("Single AF") },
{ 1, N_("Sequential shooting AF") }, { 1, N_("Sequential shooting AF") },
{ 2, N_("Continuous AF") }, { 2, N_("Continuous AF") },

@ -72,7 +72,7 @@ namespace Exiv2 {
return 0; return 0;
} }
void OrfImage::setComment(const std::string& /*comment*/) void OrfImage::setComment(std::string_view /*comment*/)
{ {
// not supported // not supported
throw(Error(kerInvalidSettingForImage, "Image comment", "ORF")); throw(Error(kerInvalidSettingForImage, "Image comment", "ORF"));

@ -25,10 +25,6 @@
#include "tags.hpp" #include "tags.hpp"
#include "types.hpp" #include "types.hpp"
// + standard includes
#include <string>
#include <iosfwd>
// ***************************************************************************** // *****************************************************************************
// namespace extensions // namespace extensions
namespace Exiv2 { namespace Exiv2 {

@ -26,10 +26,6 @@
#include "tags_int.hpp" #include "tags_int.hpp"
#include "types.hpp" #include "types.hpp"
// + standard includes
#include <iostream>
#include <iomanip>
// ***************************************************************************** // *****************************************************************************
// namespace extensions // namespace extensions
namespace Exiv2 { namespace Exiv2 {

@ -25,11 +25,6 @@
#include "types.hpp" #include "types.hpp"
#include "pngimage.hpp" #include "pngimage.hpp"
// + standard includes
#include <iosfwd>
#include <cassert>
#include <cstdarg>
// ***************************************************************************** // *****************************************************************************
// namespace extensions // namespace extensions
namespace Exiv2 { namespace Exiv2 {

@ -35,6 +35,7 @@
#include "types.hpp" #include "types.hpp"
// + standard includes // + standard includes
#include <algorithm>
#include <array> #include <array>
#include <string> #include <string>
#include <cstring> #include <cstring>
@ -150,11 +151,11 @@ namespace Exiv2 {
static bool tEXtToDataBuf(const byte* bytes,long length,DataBuf& result) static bool tEXtToDataBuf(const byte* bytes,long length,DataBuf& result)
{ {
static const char* hexdigits = "0123456789ABCDEF";
static std::array<int, 256> value; static std::array<int, 256> value;
static bool bFirst = true; static bool bFirst = true;
if ( bFirst ) { if ( bFirst ) {
value.fill(0); value.fill(0);
const char* hexdigits = "0123456789ABCDEF";
for ( int i = 0 ; i < 16 ; i++ ) { for ( int i = 0 ; i < 16 ; i++ ) {
value[tolower(hexdigits[i])]=i+1; value[tolower(hexdigits[i])]=i+1;
value[toupper(hexdigits[i])]=i+1; value[toupper(hexdigits[i])]=i+1;

@ -21,6 +21,7 @@
// included header files // included header files
#include "config.h" #include "config.h"
#include <algorithm>
#include <array> #include <array>
#include <climits> #include <climits>
#include <string> #include <string>

@ -3943,6 +3943,7 @@ namespace Exiv2 {
XmpProperties::NsRegistry XmpProperties::nsRegistry_; XmpProperties::NsRegistry XmpProperties::nsRegistry_;
std::mutex XmpProperties::mutex_; std::mutex XmpProperties::mutex_;
/// \todo not used internally. At least we should test it
const XmpNsInfo* XmpProperties::lookupNsRegistry(const XmpNsInfo::Prefix& prefix) const XmpNsInfo* XmpProperties::lookupNsRegistry(const XmpNsInfo::Prefix& prefix)
{ {
std::lock_guard<std::mutex> scoped_read_lock(mutex_); std::lock_guard<std::mutex> scoped_read_lock(mutex_);
@ -4095,6 +4096,7 @@ namespace Exiv2 {
return pi; return pi;
} }
/// \todo not used internally. At least we should test it
const char* XmpProperties::nsDesc(const std::string& prefix) const char* XmpProperties::nsDesc(const std::string& prefix)
{ {
return nsInfo(prefix)->desc_; return nsInfo(prefix)->desc_;

@ -127,7 +127,7 @@ namespace Exiv2 {
return "image/x-photoshop"; return "image/x-photoshop";
} }
void PsdImage::setComment(const std::string& /*comment*/) void PsdImage::setComment(std::string_view /*comment*/)
{ {
// not supported // not supported
throw(Error(kerInvalidSettingForImage, "Image comment", "Photoshop")); throw(Error(kerInvalidSettingForImage, "Image comment", "Photoshop"));
@ -399,13 +399,15 @@ namespace Exiv2 {
#endif #endif
// Copy colorData // Copy colorData
uint32_t readTotal = 0; uint32_t readTotal = 0;
long toRead = 0;
while (readTotal < colorDataLength) { while (readTotal < colorDataLength) {
toRead = static_cast<long>(colorDataLength - readTotal) < lbuf.size() long toRead = static_cast<long>(colorDataLength - readTotal) < lbuf.size()
? static_cast<long>(colorDataLength - readTotal) : lbuf.size(); ? static_cast<long>(colorDataLength - readTotal)
if (io_->read(lbuf.data(), toRead) != toRead) throw Error(kerNotAnImage, "Photoshop"); : lbuf.size();
if (io_->read(lbuf.data(), toRead) != toRead)
throw Error(kerNotAnImage, "Photoshop");
readTotal += toRead; readTotal += toRead;
if (outIo.write(lbuf.c_data(), toRead) != toRead) throw Error(kerImageWriteFailed); if (outIo.write(lbuf.c_data(), toRead) != toRead)
throw Error(kerImageWriteFailed);
} }
if (outIo.error()) throw Error(kerImageWriteFailed); if (outIo.error()) throw Error(kerImageWriteFailed);
@ -505,15 +507,17 @@ namespace Exiv2 {
if (outIo.write(buf, 4) != 4) throw Error(kerImageWriteFailed); if (outIo.write(buf, 4) != 4) throw Error(kerImageWriteFailed);
readTotal = 0; readTotal = 0;
toRead = 0;
while (readTotal < pResourceSize) { while (readTotal < pResourceSize) {
toRead = static_cast<long>(pResourceSize - readTotal) < lbuf.size() /// \todo almost same code as in lines 403-410. Factor out & reuse!
? static_cast<long>(pResourceSize - readTotal) : lbuf.size(); long toRead = static_cast<long>(pResourceSize - readTotal) < lbuf.size()
? static_cast<long>(pResourceSize - readTotal)
: lbuf.size();
if (io_->read(lbuf.data(), toRead) != toRead) { if (io_->read(lbuf.data(), toRead) != toRead) {
throw Error(kerNotAnImage, "Photoshop"); throw Error(kerNotAnImage, "Photoshop");
} }
readTotal += toRead; readTotal += toRead;
if (outIo.write(lbuf.c_data(), toRead) != toRead) throw Error(kerImageWriteFailed); if (outIo.write(lbuf.c_data(), toRead) != toRead)
throw Error(kerImageWriteFailed);
} }
if (outIo.error()) throw Error(kerImageWriteFailed); if (outIo.error()) throw Error(kerImageWriteFailed);
newResLength += pResourceSize + adjResourceNameLen + 12; newResLength += pResourceSize + adjResourceNameLen + 12;
@ -532,13 +536,11 @@ namespace Exiv2 {
// Append ExifInfo resource block, if not yet written // Append ExifInfo resource block, if not yet written
if (!exifDone) { if (!exifDone) {
newResLength += writeExifData(exifData_, outIo); newResLength += writeExifData(exifData_, outIo);
exifDone = true;
} }
// Append XmpPacket resource block, if not yet written // Append XmpPacket resource block, if not yet written
if (!xmpDone) { if (!xmpDone) {
newResLength += writeXmpData(xmpData_, outIo); newResLength += writeXmpData(xmpData_, outIo);
xmpDone = true;
} }
// Populate the fake data, only make sense for remoteio, httpio and sshio. // Populate the fake data, only make sense for remoteio, httpio and sshio.

@ -81,7 +81,7 @@ namespace Exiv2 {
throw(Error(kerInvalidSettingForImage, "IPTC metadata", "RAF")); throw(Error(kerInvalidSettingForImage, "IPTC metadata", "RAF"));
} }
void RafImage::setComment(const std::string& /*comment*/) void RafImage::setComment(std::string_view /*comment*/)
{ {
// not supported // not supported
throw(Error(kerInvalidSettingForImage, "Image comment", "RAF")); throw(Error(kerInvalidSettingForImage, "Image comment", "RAF"));
@ -96,12 +96,11 @@ namespace Exiv2 {
if (io_->error() || io_->eof()) throw Error(kerFailedToReadImageData); if (io_->error() || io_->eof()) throw Error(kerFailedToReadImageData);
throw Error(kerNotAnImage, "RAF"); throw Error(kerNotAnImage, "RAF");
} }
size_t address = 0 ;
size_t address2 = 0 ;
const bool bPrint = option==kpsBasic || option==kpsRecursive; const bool bPrint = option==kpsBasic || option==kpsRecursive;
if ( bPrint ) { if ( bPrint ) {
io_->seek(0,BasicIo::beg); // rewind io_->seek(0,BasicIo::beg); // rewind
address = io_->tell(); size_t address = io_->tell();
const char* format = " %8d | %8d | "; const char* format = " %8d | %8d | ";
{ {
@ -174,7 +173,7 @@ namespace Exiv2 {
byte jpg_img_offset [4]; byte jpg_img_offset [4];
io_->read(jpg_img_offset, 4); io_->read(jpg_img_offset, 4);
byte jpg_img_length [4]; byte jpg_img_length [4];
address2 = io_->tell(); size_t address2 = io_->tell();
io_->read(jpg_img_length, 4); io_->read(jpg_img_length, 4);
long jpg_img_off = Exiv2::getULong(jpg_img_offset, bigEndian); long jpg_img_off = Exiv2::getULong(jpg_img_offset, bigEndian);

@ -83,7 +83,7 @@ namespace Exiv2 {
throw(Error(kerInvalidSettingForImage, "IPTC metadata", "RW2")); throw(Error(kerInvalidSettingForImage, "IPTC metadata", "RW2"));
} }
void Rw2Image::setComment(const std::string& /*comment*/) void Rw2Image::setComment(std::string_view /*comment*/)
{ {
// not supported // not supported
throw(Error(kerInvalidSettingForImage, "Image comment", "RW2")); throw(Error(kerInvalidSettingForImage, "Image comment", "RW2"));

@ -23,10 +23,6 @@
// ***************************************************************************** // *****************************************************************************
// included header files // included header files
#include "tiffimage_int.hpp" #include "tiffimage_int.hpp"
#include "types.hpp"
// + standard includes
#include <string>
// ***************************************************************************** // *****************************************************************************
// namespace extensions // namespace extensions

@ -25,11 +25,6 @@
#include "tags.hpp" #include "tags.hpp"
#include "types.hpp" #include "types.hpp"
// + standard includes
#include <string>
#include <iosfwd>
#include <memory>
// ***************************************************************************** // *****************************************************************************
// namespace extensions // namespace extensions
namespace Exiv2 { namespace Exiv2 {

@ -25,11 +25,6 @@
#include "tags.hpp" #include "tags.hpp"
#include "types.hpp" #include "types.hpp"
// + standard includes
#include <string>
#include <iosfwd>
#include <memory>
// ***************************************************************************** // *****************************************************************************
// namespace extensions // namespace extensions
namespace Exiv2 { namespace Exiv2 {

@ -22,14 +22,8 @@
// ***************************************************************************** // *****************************************************************************
// included header files // included header files
#include "tags.hpp"
#include "types.hpp"
#include "tiffcomposite_int.hpp" #include "tiffcomposite_int.hpp"
// + standard includes
#include <string>
#include <iosfwd>
// ***************************************************************************** // *****************************************************************************
// namespace extensions // namespace extensions
namespace Exiv2 { namespace Exiv2 {

@ -127,6 +127,7 @@ namespace Exiv2 {
return sectionInfo[ti->sectionId_].name_; return sectionInfo[ti->sectionId_].name_;
} }
/// \todo not used internally. At least we should test it
uint16_t ExifTags::defaultCount(const ExifKey& key) uint16_t ExifTags::defaultCount(const ExifKey& key)
{ {
const TagInfo* ti = tagInfo(key.tag(), static_cast<Internal::IfdId>(key.ifdId())); const TagInfo* ti = tagInfo(key.tag(), static_cast<Internal::IfdId>(key.ifdId()));

@ -40,6 +40,7 @@
#include "sonymn_int.hpp" #include "sonymn_int.hpp"
#include <cmath> #include <cmath>
#include <algorithm>
// ***************************************************************************** // *****************************************************************************
// local declarations // local declarations

@ -22,14 +22,7 @@
// ***************************************************************************** // *****************************************************************************
// included header files // included header files
#include "types.hpp"
#include "tags.hpp" #include "tags.hpp"
#include "value.hpp"
// + standard includes
#include <string>
#include <iostream>
#include <memory>
// ***************************************************************************** // *****************************************************************************
// namespace extensions // namespace extensions

@ -58,7 +58,7 @@ namespace Exiv2 {
throw(Error(kerInvalidSettingForImage, "IPTC metadata", "TGA")); throw(Error(kerInvalidSettingForImage, "IPTC metadata", "TGA"));
} }
void TgaImage::setComment(const std::string& /*comment*/) void TgaImage::setComment(std::string_view /*comment*/)
{ {
// not supported // not supported
throw(Error(kerInvalidSettingForImage, "Image comment", "TGA")); throw(Error(kerInvalidSettingForImage, "Image comment", "TGA"));
@ -133,7 +133,7 @@ namespace Exiv2 {
bool isTgaType(BasicIo& iIo, bool /*advance*/) bool isTgaType(BasicIo& iIo, bool /*advance*/)
{ {
// not all TARGA files have a signature string, so first just try to match the file name extension // not all TARGA files have a signature string, so first just try to match the file name extension
std::string path = iIo.path(); const std::string& path = iIo.path();
if( path.rfind(".tga") != std::string::npos if( path.rfind(".tga") != std::string::npos
|| path.rfind(".TGA") != std::string::npos) { || path.rfind(".TGA") != std::string::npos) {
return true; return true;

@ -22,16 +22,9 @@
// ***************************************************************************** // *****************************************************************************
// included header files // included header files
#include "value.hpp"
#include "tifffwd_int.hpp" #include "tifffwd_int.hpp"
#include "types.hpp"
// + standard includes
#include <iosfwd>
#include <memory> #include <memory>
#include <vector>
#include <string>
#include <cassert>
// ***************************************************************************** // *****************************************************************************
// namespace extensions // namespace extensions

@ -26,9 +26,7 @@
#include "tags_int.hpp" #include "tags_int.hpp"
// + standard includes // + standard includes
#include <memory>
#include <stack> #include <stack>
#include <vector>
// ***************************************************************************** // *****************************************************************************
// Exiv2 namespace extensions // Exiv2 namespace extensions

@ -162,7 +162,7 @@ namespace Exiv2 {
return pixelHeightPrimary_; return pixelHeightPrimary_;
} }
void TiffImage::setComment(const std::string& /*comment*/) void TiffImage::setComment(std::string_view /*comment*/)
{ {
// not supported // not supported
throw(Error(kerInvalidSettingForImage, "Image comment", "TIFF")); throw(Error(kerInvalidSettingForImage, "Image comment", "TIFF"));

@ -26,6 +26,8 @@
#include "tiffvisitor_int.hpp" #include "tiffvisitor_int.hpp"
#include "i18n.h" // NLS support. #include "i18n.h" // NLS support.
#include <iostream>
// Shortcuts for the newTiffBinaryArray templates. // Shortcuts for the newTiffBinaryArray templates.
#define EXV_BINARY_ARRAY(arrayCfg, arrayDef) (newTiffBinaryArray0<&arrayCfg, EXV_COUNTOF(arrayDef), arrayDef>) #define EXV_BINARY_ARRAY(arrayCfg, arrayDef) (newTiffBinaryArray0<&arrayCfg, EXV_COUNTOF(arrayDef), arrayDef>)
#define EXV_SIMPLE_BINARY_ARRAY(arrayCfg) (newTiffBinaryArray1<&arrayCfg>) #define EXV_SIMPLE_BINARY_ARRAY(arrayCfg) (newTiffBinaryArray1<&arrayCfg>)

@ -25,12 +25,6 @@
#include "tifffwd_int.hpp" #include "tifffwd_int.hpp"
#include "tiffcomposite_int.hpp" #include "tiffcomposite_int.hpp"
#include "image.hpp" #include "image.hpp"
#include "tags_int.hpp"
#include "types.hpp"
// + standard includes
#include <map>
#include <utility>
// ***************************************************************************** // *****************************************************************************
// namespace extensions // namespace extensions

@ -469,6 +469,7 @@ namespace Exiv2 {
const uint16_t nMasks = (nPoints+15)/(sizeof(uint16_t) * 8); const uint16_t nMasks = (nPoints+15)/(sizeof(uint16_t) * 8);
int nStart = 0; int nStart = 0;
/// \todo make this static
struct { struct {
uint16_t tag ; uint16_t tag ;
uint16_t size ; uint16_t size ;

@ -26,15 +26,7 @@
#include "tifffwd_int.hpp" #include "tifffwd_int.hpp"
#include "types.hpp" #include "types.hpp"
// + standard includes
#include <array> #include <array>
#include <memory>
#include <iostream>
#include <iomanip>
#include <cassert>
#include <map>
#include <set>
#include <vector>
// ***************************************************************************** // *****************************************************************************
// namespace extensions // namespace extensions
@ -42,6 +34,8 @@ namespace Exiv2 {
class IptcData; class IptcData;
class XmpData; class XmpData;
class TiffImageEntry;
class TiffDataEntryBase;
namespace Internal { namespace Internal {

@ -0,0 +1,9 @@
#include "utils.hpp"
namespace Exiv2
{
bool startsWith(const std::string_view& s, const std::string_view& start)
{
return s.find(start) == 0;
}
}

@ -0,0 +1,11 @@
#ifndef EXIV2_UTILS_HPP
#define EXIV2_UTILS_HPP
#include <string_view>
namespace Exiv2
{
bool startsWith(const std::string_view& s, const std::string_view& start);
}
#endif // EXIV2_UTILS_HPP

@ -804,7 +804,6 @@ namespace Exiv2 {
std::string lang = "x-default"; std::string lang = "x-default";
if (buf.length() > 5 && buf.substr(0, 5) == "lang=") { if (buf.length() > 5 && buf.substr(0, 5) == "lang=") {
static const char* ALPHA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; static const char* ALPHA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
static const char* ALPHA_NUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
const std::string::size_type pos = buf.find_first_of(' '); const std::string::size_type pos = buf.find_first_of(' ');
if (pos == std::string::npos) { if (pos == std::string::npos) {
@ -829,6 +828,7 @@ namespace Exiv2 {
// Check language is in the correct format (see https://www.ietf.org/rfc/rfc3066.txt) // Check language is in the correct format (see https://www.ietf.org/rfc/rfc3066.txt)
std::string::size_type charPos = lang.find_first_not_of(ALPHA); std::string::size_type charPos = lang.find_first_not_of(ALPHA);
if (charPos != std::string::npos) { if (charPos != std::string::npos) {
static const char* ALPHA_NUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
if (lang.at(charPos) != '-' || lang.find_first_not_of(ALPHA_NUM, charPos+1) != std::string::npos) if (lang.at(charPos) != '-' || lang.find_first_not_of(ALPHA_NUM, charPos+1) != std::string::npos)
throw Error(kerInvalidLangAltValue, buf); throw Error(kerInvalidLangAltValue, buf);
} }
@ -1110,6 +1110,7 @@ namespace Exiv2 {
return 1; return 1;
} }
/// \todo not used internally. At least we should test it
void TimeValue::setTime( const Time& src ) void TimeValue::setTime( const Time& src )
{ {
std::memcpy(&time_, &src, sizeof(time_)); std::memcpy(&time_, &src, sizeof(time_));

@ -36,13 +36,10 @@
#endif #endif
// + standard includes // + standard includes
#include <iomanip>
#include <sstream>
#include <string>
#include <stdio.h>
#include <iostream>
#include <fstream> #include <fstream>
#include <regex> #include <regex>
#include <set>
#include <sstream>
// #1147 // #1147
#ifndef WIN32 #ifndef WIN32
@ -139,7 +136,7 @@ static void output(std::ostream& os,const std::vector<std::regex>& greps,const c
static bool pushPath(std::string& path,std::vector<std::string>& libs,std::set<std::string>& paths) static bool pushPath(std::string& path,std::vector<std::string>& libs,std::set<std::string>& paths)
{ {
bool result = Exiv2::fileExists(path,true) && paths.find(path) == paths.end() && path != "/" ; bool result = Exiv2::fileExists(path) && paths.find(path) == paths.end() && path != "/" ;
if ( result ) { if ( result ) {
paths.insert(path); paths.insert(path);
libs.push_back(path); libs.push_back(path);
@ -313,7 +310,6 @@ void Exiv2::dumpLibraryInfo(std::ostream& os,const std::vector<std::regex>& keys
int have_lensdata =0; int have_lensdata =0;
int have_iconv =0; int have_iconv =0;
int have_memory =0; int have_memory =0;
int have_lstat =0;
int have_stdbool =0; int have_stdbool =0;
int have_stdint =0; int have_stdint =0;
int have_stdlib =0; int have_stdlib =0;
@ -362,10 +358,6 @@ void Exiv2::dumpLibraryInfo(std::ostream& os,const std::vector<std::regex>& keys
have_memory=1; have_memory=1;
#endif #endif
#ifdef EXV_HAVE_LSTAT
have_lstat=1;
#endif
#ifdef EXV_HAVE_STDBOOL_H #ifdef EXV_HAVE_STDBOOL_H
have_stdbool=1; have_stdbool=1;
#endif #endif
@ -492,7 +484,6 @@ void Exiv2::dumpLibraryInfo(std::ostream& os,const std::vector<std::regex>& keys
output(os,keys,"have_lensdata" ,have_lensdata ); output(os,keys,"have_lensdata" ,have_lensdata );
output(os,keys,"have_iconv" ,have_iconv ); output(os,keys,"have_iconv" ,have_iconv );
output(os,keys,"have_memory" ,have_memory ); output(os,keys,"have_memory" ,have_memory );
output(os,keys,"have_lstat" ,have_lstat );
output(os,keys,"have_stdbool" ,have_stdbool ); output(os,keys,"have_stdbool" ,have_stdbool );
output(os,keys,"have_stdint" ,have_stdint ); output(os,keys,"have_stdint" ,have_stdint );
output(os,keys,"have_stdlib" ,have_stdlib ); output(os,keys,"have_stdlib" ,have_stdlib );

@ -50,6 +50,54 @@
#define CHECK_BIT(var,pos) ((var) & (1<<(pos))) #define CHECK_BIT(var,pos) ((var) & (1<<(pos)))
namespace {
[[maybe_unused]] std::string binaryToHex(const uint8_t* data, size_t size)
{
std::stringstream hexOutput;
auto tl = size_t(size / 16) * 16;
auto tl_offset = size_t(size) - tl;
for (size_t loop = 0; loop < size; loop++) {
if (data[loop] < 16) {
hexOutput << "0";
}
hexOutput << std::hex << static_cast<int>(data[loop]);
if ((loop % 8) == 7) {
hexOutput << " ";
}
if ((loop % 16) == 15 || loop == (tl + tl_offset - 1)) {
int max = 15;
if (loop >= tl) {
max = int(tl_offset) - 1;
for (int offset = 0; offset < int(16 - tl_offset); offset++) {
if ((offset % 8) == 7) {
hexOutput << " ";
}
hexOutput << " ";
}
}
hexOutput << " ";
for (int offset = max; offset >= 0; offset--) {
if (offset == (max - 8)) {
hexOutput << " ";
}
uint8_t c = '.';
if (data[loop - offset] >= 0x20 && data[loop - offset] <= 0x7E) {
c = data[loop - offset];
}
hexOutput << static_cast<char>(c);
}
hexOutput << std::endl;
}
}
hexOutput << std::endl << std::endl << std::endl;
return hexOutput.str();
}
} // namespace
// ***************************************************************************** // *****************************************************************************
// class member definitions // class member definitions
namespace Exiv2 { namespace Exiv2 {
@ -96,7 +144,7 @@ namespace Exiv2 {
// throw(Error(kerInvalidSettingForImage, "IPTC metadata", "WebP")); // throw(Error(kerInvalidSettingForImage, "IPTC metadata", "WebP"));
} }
void WebPImage::setComment(const std::string& /*comment*/) void WebPImage::setComment(std::string_view /*comment*/)
{ {
// not supported // not supported
throw(Error(kerInvalidSettingForImage, "Image comment", "WebP")); throw(Error(kerInvalidSettingForImage, "Image comment", "WebP"));
@ -688,7 +736,7 @@ namespace Exiv2 {
#ifdef EXIV2_DEBUG_MESSAGES #ifdef EXIV2_DEBUG_MESSAGES
std::cout << "Display Hex Dump [size:" << static_cast<unsigned long>(sizePayload) << "]" << std::endl; std::cout << "Display Hex Dump [size:" << static_cast<unsigned long>(sizePayload) << "]" << std::endl;
std::cout << Internal::binaryToHex(rawExifData.c_data(), sizePayload); std::cout << binaryToHex(rawExifData.c_data(), sizePayload);
#endif #endif
if (pos != -1) { if (pos != -1) {
@ -716,7 +764,7 @@ namespace Exiv2 {
#ifdef EXIV2_DEBUG_MESSAGES #ifdef EXIV2_DEBUG_MESSAGES
std::cout << "Display Hex Dump [size:" << static_cast<unsigned long>(payload.size()) << "]" std::cout << "Display Hex Dump [size:" << static_cast<unsigned long>(payload.size()) << "]"
<< std::endl; << std::endl;
std::cout << Internal::binaryToHex(payload.c_data(), payload.size()); std::cout << binaryToHex(payload.c_data(), payload.size());
#endif #endif
} }
} else { } else {
@ -833,8 +881,6 @@ namespace Exiv2 {
if (iIo.tell() % 2) { if (iIo.tell() % 2) {
if (iIo.write(&WEBP_PAD_ODD, 1) != 1) throw Error(kerImageWriteFailed); if (iIo.write(&WEBP_PAD_ODD, 1) != 1) throw Error(kerImageWriteFailed);
} }
has_icc = false;
} }
} }

@ -30,6 +30,7 @@
#include "convert.hpp" #include "convert.hpp"
// + standard includes // + standard includes
#include <algorithm>
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <cassert> #include <cassert>
@ -61,7 +62,7 @@ namespace Exiv2 {
return "application/rdf+xml"; return "application/rdf+xml";
} }
void XmpSidecar::setComment(const std::string& /*comment*/) void XmpSidecar::setComment(std::string_view /*comment*/)
{ {
// not supported // not supported
throw(Error(kerInvalidSettingForImage, "Image comment", "XMP")); throw(Error(kerInvalidSettingForImage, "Image comment", "XMP"));

@ -65,7 +65,7 @@ TEST(TheImageFactory, createsInstancesForFewSupportedTypesInFiles)
EXPECT_NO_THROW(ImageFactory::create(ImageType::pgf, filePath)); EXPECT_NO_THROW(ImageFactory::create(ImageType::pgf, filePath));
EXPECT_NO_THROW(ImageFactory::create(ImageType::png, filePath)); EXPECT_NO_THROW(ImageFactory::create(ImageType::png, filePath));
EXPECT_EQ(0, std::remove(filePath.c_str())); EXPECT_TRUE(fs::remove(filePath));
} }
TEST(TheImageFactory, cannotCreateInstancesForSomeTypesInFiles) TEST(TheImageFactory, cannotCreateInstancesForSomeTypesInFiles)

@ -23,6 +23,7 @@
#include <exiv2/futils.hpp> #include <exiv2/futils.hpp>
// Auxiliary headers // Auxiliary headers
#include <filesystem>
#include <fstream> #include <fstream>
#include <cstdio> #include <cstdio>
#include <cerrno> #include <cerrno>
@ -30,6 +31,8 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
namespace fs = std::filesystem;
using namespace Exiv2; using namespace Exiv2;
TEST(strError, returnSuccessAfterClosingFile) TEST(strError, returnSuccessAfterClosingFile)
@ -42,7 +45,7 @@ TEST(strError, returnSuccessAfterClosingFile)
std::string tmpFile("tmp.dat"); std::string tmpFile("tmp.dat");
std::ofstream auxFile(tmpFile.c_str()); std::ofstream auxFile(tmpFile.c_str());
auxFile.close(); auxFile.close();
std::remove(tmpFile.c_str()); fs::remove(tmpFile.c_str());
ASSERT_TRUE(strError().find("(errno = 0)") != std::string::npos); ASSERT_TRUE(strError().find("(errno = 0)") != std::string::npos);
} }
@ -97,15 +100,6 @@ TEST(urlencode, encodesGivenUrlWithSpace)
ASSERT_STREQ("http%3a%2f%2fwww.geekhideout.com%2furl+code.shtml", url.c_str()); ASSERT_STREQ("http%3a%2f%2fwww.geekhideout.com%2furl+code.shtml", url.c_str());
} }
TEST(urldecode, decodesGivenUrl)
{
const std::string expectedDecodedUrl ("http://www.geekhideout.com/urlcode.shtml");
const std::string url ("http%3a%2f%2fwww.geekhideout.com%2furlcode.shtml");
char * url3 = urldecode(url.c_str());
ASSERT_STREQ(expectedDecodedUrl.c_str(), url3);
delete [] url3;
}
TEST(urldecode, decodesGivenUrlInPlace) TEST(urldecode, decodesGivenUrlInPlace)
{ {
const std::string expectedDecodedUrl ("http://www.geekhideout.com/urlcode.shtml"); const std::string expectedDecodedUrl ("http://www.geekhideout.com/urlcode.shtml");

Loading…
Cancel
Save