Merge branch 'main' into TestVideoData

main
Mohamed Ali Chebbi 2 years ago committed by Mohamed Ali Chebbi
commit a36e4dd1e8

@ -143,8 +143,17 @@ if (EXIV2_TEAM_PACKAGING)
include(cmake/packaging.cmake) include(cmake/packaging.cmake)
endif() endif()
join_paths(libdir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_LIBDIR}") # Handle both relative and absolute paths (e.g. NixOS) for a relocatable package
join_paths(includedir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}") if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}")
set(libdir_for_pc_file "${CMAKE_INSTALL_LIBDIR}")
else()
join_paths(libdir_for_pc_file "\${exec_prefix}" "${CMAKE_INSTALL_LIBDIR}")
endif()
if(IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}")
set(includedir_for_pc_file "${CMAKE_INSTALL_INCLUDEDIR}")
else()
join_paths(includedir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
endif()
configure_file(cmake/exiv2.pc.in exiv2.pc @ONLY) configure_file(cmake/exiv2.pc.in exiv2.pc @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/exiv2.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/exiv2.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)

@ -17,17 +17,16 @@
#include "types.hpp" #include "types.hpp"
#include "xmp_exiv2.hpp" #include "xmp_exiv2.hpp"
// + standard includes
#include <sys/stat.h> // for stat()
#include <sys/types.h> // for stat()
#include <filesystem>
#include <fstream> #include <fstream>
#include <iomanip> #include <iomanip>
#include <iostream> #include <iostream>
#include <mutex> #include <mutex>
#include <sstream> #include <sstream>
#ifdef EXV_HAVE_UNISTD_H
// + standard includes
#include <sys/stat.h> // for stat()
#include <sys/types.h> // for stat()
#if __has_include(<unistd.h>)
#include <unistd.h> // for stat() #include <unistd.h> // for stat()
#endif #endif
@ -46,7 +45,13 @@
} while (false) } while (false)
#endif #endif
#if __has_include(<filesystem>)
#include <filesystem>
namespace fs = std::filesystem; namespace fs = std::filesystem;
#else
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#endif
// ***************************************************************************** // *****************************************************************************
// local declarations // local declarations
@ -631,7 +636,7 @@ int Rename::run(const std::string& path) {
return 1; return 1;
} }
std::string v = md->toString(); std::string v = md->toString();
if (v.length() == 0 || v[0] == ' ') { if (v.empty() || v.front() == ' ') {
std::cerr << _("Image file creation timestamp not set in the file") << " " << path << "\n"; std::cerr << _("Image file creation timestamp not set in the file") << " " << path << "\n";
return 1; return 1;
} }
@ -1408,30 +1413,32 @@ int Adjust::adjustDateTime(Exiv2::ExifData& exifData, const std::string& key, co
} }
// bounds checking for yearAdjustment_ // bounds checking for yearAdjustment_
enforce<std::overflow_error>(yearAdjustment_ >= std::numeric_limits<decltype(tm.tm_year)>::min(), Exiv2::Internal::enforce<std::overflow_error>(yearAdjustment_ >= std::numeric_limits<decltype(tm.tm_year)>::min(),
"year adjustment too low"); "year adjustment too low");
enforce<std::overflow_error>(yearAdjustment_ <= std::numeric_limits<decltype(tm.tm_year)>::max(), Exiv2::Internal::enforce<std::overflow_error>(yearAdjustment_ <= std::numeric_limits<decltype(tm.tm_year)>::max(),
"year adjustment too high"); "year adjustment too high");
const auto yearAdjustment = static_cast<decltype(tm.tm_year)>(yearAdjustment_); const auto yearAdjustment = static_cast<decltype(tm.tm_year)>(yearAdjustment_);
// bounds checking for monthAdjustment_ // bounds checking for monthAdjustment_
enforce<std::overflow_error>(monthAdjustment_ >= std::numeric_limits<decltype(tm.tm_mon)>::min(), Exiv2::Internal::enforce<std::overflow_error>(monthAdjustment_ >= std::numeric_limits<decltype(tm.tm_mon)>::min(),
"month adjustment too low"); "month adjustment too low");
enforce<std::overflow_error>(monthAdjustment_ <= std::numeric_limits<decltype(tm.tm_mon)>::max(), Exiv2::Internal::enforce<std::overflow_error>(monthAdjustment_ <= std::numeric_limits<decltype(tm.tm_mon)>::max(),
"month adjustment too high"); "month adjustment too high");
const auto monthAdjustment = static_cast<decltype(tm.tm_mon)>(monthAdjustment_); const auto monthAdjustment = static_cast<decltype(tm.tm_mon)>(monthAdjustment_);
// bounds checking for dayAdjustment_ // bounds checking for dayAdjustment_
static constexpr time_t secondsInDay = 24 * 60 * 60; static constexpr time_t secondsInDay = 24 * 60 * 60;
enforce<std::overflow_error>(dayAdjustment_ >= std::numeric_limits<time_t>::min() / secondsInDay, Exiv2::Internal::enforce<std::overflow_error>(dayAdjustment_ >= std::numeric_limits<time_t>::min() / secondsInDay,
"day adjustment too low"); "day adjustment too low");
enforce<std::overflow_error>(dayAdjustment_ <= std::numeric_limits<time_t>::max() / secondsInDay, Exiv2::Internal::enforce<std::overflow_error>(dayAdjustment_ <= std::numeric_limits<time_t>::max() / secondsInDay,
"day adjustment too high"); "day adjustment too high");
const auto dayAdjustment = static_cast<time_t>(dayAdjustment_); const auto dayAdjustment = static_cast<time_t>(dayAdjustment_);
// bounds checking for adjustment_ // bounds checking for adjustment_
enforce<std::overflow_error>(adjustment_ >= std::numeric_limits<time_t>::min(), "seconds adjustment too low"); Exiv2::Internal::enforce<std::overflow_error>(adjustment_ >= std::numeric_limits<time_t>::min(),
enforce<std::overflow_error>(adjustment_ <= std::numeric_limits<time_t>::max(), "seconds adjustment too high"); "seconds adjustment too low");
Exiv2::Internal::enforce<std::overflow_error>(adjustment_ <= std::numeric_limits<time_t>::max(),
"seconds adjustment too high");
const auto adjustment = static_cast<time_t>(adjustment_); const auto adjustment = static_cast<time_t>(adjustment_);
const auto monOverflow = Safe::add(tm.tm_mon, monthAdjustment) / 12; const auto monOverflow = Safe::add(tm.tm_mon, monthAdjustment) / 12;
@ -1602,7 +1609,7 @@ int Timestamp::touch(const std::string& path) const {
//! @endcond //! @endcond
int str2Tm(const std::string& timeStr, struct tm* tm) { int str2Tm(const std::string& timeStr, struct tm* tm) {
if (timeStr.length() == 0 || timeStr[0] == ' ') if (timeStr.empty() || timeStr.front() == ' ')
return 1; return 1;
if (timeStr.length() < 19) if (timeStr.length() < 19)
return 2; return 2;

@ -41,12 +41,19 @@ constexpr auto emptyYodAdjust_ = std::array{
}; };
//! List of all command identifiers and corresponding strings //! List of all command identifiers and corresponding strings
constexpr auto cmdIdAndString = std::array{ constexpr struct CmdIdAndString {
std::pair(CmdId::add, "add"), CmdId cmdId_;
std::pair(CmdId::set, "set"), const char* string_;
std::pair(CmdId::del, "del"), //! Comparison operator for \em string
std::pair(CmdId::reg, "reg"), bool operator==(const std::string& string) const {
std::pair(CmdId::invalid, "invalidCmd"), // End of list marker return string == string_;
}
} cmdIdAndString[] = {
{CmdId::add, "add"},
{CmdId::set, "set"},
{CmdId::del, "del"},
{CmdId::reg, "reg"},
{CmdId::invalid, "invalidCmd"}, // End of list marker
}; };
// Return a command Id for a command string // Return a command Id for a command string
@ -1433,8 +1440,8 @@ bool parseLine(ModifyCmd& modifyCmd, const std::string& line, int num) {
} // parseLine } // parseLine
CmdId commandId(const std::string& cmdString) { CmdId commandId(const std::string& cmdString) {
auto it = std::find_if(cmdIdAndString.begin(), cmdIdAndString.end(), [&](auto cs) { return cs.second == cmdString; }); auto it = Exiv2::find(cmdIdAndString, cmdString);
return it != cmdIdAndString.end() ? it->first : CmdId::invalid; return it ? it->cmdId_ : CmdId::invalid;
} }
std::string parseEscapes(const std::string& input) { std::string parseEscapes(const std::string& input) {

@ -5,9 +5,14 @@
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include <filesystem>
#if __has_include(<filesystem>)
#include <filesystem>
namespace fs = std::filesystem; namespace fs = std::filesystem;
#else
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#endif
namespace Util { namespace Util {
// https://raw.githubusercontent.com/skeeto/getopt/master/getopt.h // https://raw.githubusercontent.com/skeeto/getopt/master/getopt.h

@ -1,132 +0,0 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
# This code is disabled for Visual Studio as explained in README.md
if ( NOT MSVC )
#[=======================================================================[.rst:
FindIconv
---------
This module finds the ``iconv()`` POSIX.1 functions on the system.
These functions might be provided in the regular C library or externally
in the form of an additional library.
The following variables are provided to indicate iconv support:
.. variable:: Iconv_FOUND
Variable indicating if the iconv support was found.
.. variable:: Iconv_INCLUDE_DIRS
The directories containing the iconv headers.
.. variable:: Iconv_LIBRARIES
The iconv libraries to be linked.
.. variable:: Iconv_IS_BUILT_IN
A variable indicating whether iconv support is stemming from the
C library or not. Even if the C library provides `iconv()`, the presence of
an external `libiconv` implementation might lead to this being false.
Additionally, the following :prop_tgt:`IMPORTED` target is being provided:
.. variable:: Iconv::Iconv
Imported target for using iconv.
The following cache variables may also be set:
.. variable:: Iconv_INCLUDE_DIR
The directory containing the iconv headers.
.. variable:: Iconv_LIBRARY
The iconv library (if not implicitly given in the C library).
.. note::
On POSIX platforms, iconv might be part of the C library and the cache
variables ``Iconv_INCLUDE_DIR`` and ``Iconv_LIBRARY`` might be empty.
#]=======================================================================]
if (WIN32)
# If neither C nor CXX are loaded, implicit iconv makes no sense.
set(Iconv_IS_BUILT_IN FALSE)
endif()
# iconv can only be provided in libc on a POSIX system.
# If any cache variable is already set, we'll skip this test.
if(NOT DEFINED Iconv_IS_BUILT_IN)
if(UNIX AND NOT DEFINED Iconv_INCLUDE_DIR AND NOT DEFINED Iconv_LIBRARY)
include(CheckCSourceCompiles)
# We always suppress the message here: Otherwise on supported systems
# not having iconv in their C library (e.g. those using libiconv)
# would always display a confusing "Looking for iconv - not found" message
set(CMAKE_FIND_QUIETLY TRUE)
# The following code will not work, but it's sufficient to see if it compiles.
# Note: libiconv will define the iconv functions as macros, so CheckSymbolExists
# will not yield correct results.
set(Iconv_IMPLICIT_TEST_CODE
"
#include <stddef.h>
#include <iconv.h>
int main() {
char *a, *b;
size_t i, j;
iconv_t ic;
ic = iconv_open(\"to\", \"from\");
iconv(ic, &a, &i, &b, &j);
iconv_close(ic);
}
"
)
if(CMAKE_C_COMPILER_LOADED)
check_c_source_compiles("${Iconv_IMPLICIT_TEST_CODE}" Iconv_IS_BUILT_IN)
else()
check_cxx_source_compiles("${Iconv_IMPLICIT_TEST_CODE}" Iconv_IS_BUILT_IN)
endif()
else()
set(Iconv_IS_BUILT_IN FALSE)
endif()
endif()
if(NOT Iconv_IS_BUILT_IN)
find_path(Iconv_INCLUDE_DIR
NAMES "iconv.h"
DOC "iconv include directory")
set(Iconv_LIBRARY_NAMES "iconv" "libiconv")
else()
set(Iconv_INCLUDE_DIR "" CACHE FILEPATH "iconv include directory")
set(Iconv_LIBRARY_NAMES "c")
endif()
find_library(Iconv_LIBRARY
NAMES ${Iconv_LIBRARY_NAMES}
DOC "iconv library (potentially the C library)")
mark_as_advanced(Iconv_INCLUDE_DIR)
mark_as_advanced(Iconv_LIBRARY)
include(FindPackageHandleStandardArgs)
if(NOT Iconv_IS_BUILT_IN)
find_package_handle_standard_args(Iconv REQUIRED_VARS Iconv_LIBRARY Iconv_INCLUDE_DIR)
else()
find_package_handle_standard_args(Iconv REQUIRED_VARS Iconv_LIBRARY)
endif()
if(Iconv_FOUND)
set(Iconv_INCLUDE_DIRS "${Iconv_INCLUDE_DIR}")
set(Iconv_LIBRARIES "${Iconv_LIBRARY}")
if(NOT TARGET Iconv::Iconv)
add_library(Iconv::Iconv INTERFACE IMPORTED)
endif()
set_property(TARGET Iconv::Iconv PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${Iconv_INCLUDE_DIRS}")
set_property(TARGET Iconv::Iconv PROPERTY INTERFACE_LINK_LIBRARIES "${Iconv_LIBRARIES}")
endif()
endif()

@ -9,9 +9,6 @@
// Define if you require webready support. // Define if you require webready support.
#cmakedefine EXV_ENABLE_WEBREADY #cmakedefine EXV_ENABLE_WEBREADY
// Define if you have the <libintl.h> header file.
#cmakedefine EXV_HAVE_LIBINTL_H
// Define if you want translation of program messages to the user's native language // Define if you want translation of program messages to the user's native language
#cmakedefine EXV_ENABLE_NLS #cmakedefine EXV_ENABLE_NLS
@ -44,15 +41,6 @@
// Define if you have the munmap function. // Define if you have the munmap function.
#cmakedefine EXV_HAVE_MUNMAP #cmakedefine EXV_HAVE_MUNMAP
/* Define if you have the <libproc.h> header file. */
#cmakedefine EXV_HAVE_LIBPROC_H
/* Define if you have the <unistd.h> header file. */
#cmakedefine EXV_HAVE_UNISTD_H
// Define if you have the <sys/mman.h> header file.
#cmakedefine EXV_HAVE_SYS_MMAN_H
// Define if you have the zlib library. // Define if you have the zlib library.
#cmakedefine EXV_HAVE_LIBZ #cmakedefine EXV_HAVE_LIBZ

@ -7,5 +7,7 @@ Name: exiv2
Description: @PROJECT_DESCRIPTION@ Description: @PROJECT_DESCRIPTION@
Version: @PROJECT_VERSION@ Version: @PROJECT_VERSION@
URL: @PACKAGE_URL@ URL: @PACKAGE_URL@
Requires.private: @requires_private_for_pc_file@
Libs: -L${libdir} -lexiv2 Libs: -L${libdir} -lexiv2
Libs.private: @libs_private_for_pc_file@
Cflags: -I${includedir} Cflags: -I${includedir}

@ -152,5 +152,4 @@ EXIV2API Image::UniquePtr newAsfInstance(BasicIo::UniquePtr io, bool create);
//! Check if the file iIo is a Windows Asf Video. //! Check if the file iIo is a Windows Asf Video.
EXIV2API bool isAsfType(BasicIo& iIo, bool advance); EXIV2API bool isAsfType(BasicIo& iIo, bool advance);
} // namespace Exiv2 } // namespace Exiv2

@ -116,7 +116,10 @@ class EXIV2API MatroskaVideo : public Image {
method to get a temporary reference. method to get a temporary reference.
*/ */
explicit MatroskaVideo(BasicIo::UniquePtr io); explicit MatroskaVideo(BasicIo::UniquePtr io);
//@}
//! @name NOT Implemented
//@{
//! Copy constructor //! Copy constructor
MatroskaVideo(const MatroskaVideo&) = delete; MatroskaVideo(const MatroskaVideo&) = delete;
//! Assignment operator //! Assignment operator
@ -184,6 +187,10 @@ class EXIV2API MatroskaVideo : public Image {
}; // class MatroskaVideo }; // class MatroskaVideo
// ***************************************************************************** // *****************************************************************************
// template, inline and free functions
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*! /*!
@brief Create a new MatroskaVideo instance and return an auto-pointer to it. @brief Create a new MatroskaVideo instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that Caller owns the returned object and the auto-pointer ensures that

@ -17,8 +17,8 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef QUICKTIMEVIDEO_HPP #ifndef QUICKTIMEVIDEO_HPP_
#define QUICKTIMEVIDEO_HPP #define QUICKTIMEVIDEO_HPP_
// ***************************************************************************** // *****************************************************************************
#include "exiv2lib_export.h" #include "exiv2lib_export.h"
@ -37,7 +37,7 @@ namespace Exiv2 {
/*! /*!
@brief Class to access QuickTime video files. @brief Class to access QuickTime video files.
*/ */
class QuickTimeVideo : public Image { class EXIV2API QuickTimeVideo : public Image {
public: public:
//! @name Creators //! @name Creators
//@{ //@{
@ -52,7 +52,7 @@ class QuickTimeVideo : public Image {
instance after it is passed to this method. Use the Image::io() instance after it is passed to this method. Use the Image::io()
method to get a temporary reference. method to get a temporary reference.
*/ */
QuickTimeVideo(BasicIo::UniquePtr io); explicit QuickTimeVideo(BasicIo::UniquePtr io);
//@} //@}
//! @name NOT Implemented //! @name NOT Implemented
@ -71,7 +71,7 @@ class QuickTimeVideo : public Image {
//! @name Accessors //! @name Accessors
//@{ //@{
std::string mimeType() const override; [[nodiscard]] std::string mimeType() const override;
//@} //@}
protected: protected:
@ -227,11 +227,11 @@ class QuickTimeVideo : public Image {
Caller owns the returned object and the auto-pointer ensures that Caller owns the returned object and the auto-pointer ensures that
it will be deleted. it will be deleted.
*/ */
Image::UniquePtr newQTimeInstance(BasicIo::UniquePtr io, bool create); EXIV2API Image::UniquePtr newQTimeInstance(BasicIo::UniquePtr io, bool create);
//! Check if the file iIo is a Quick Time Video. //! Check if the file iIo is a Quick Time Video.
bool isQTimeType(BasicIo& iIo, bool advance); EXIV2API bool isQTimeType(BasicIo& iIo, bool advance);
} // namespace Exiv2 } // namespace Exiv2
#endif // QUICKTIMEVIDEO_HPP #endif // QUICKTIMEVIDEO_HPP_

@ -42,7 +42,6 @@ class EXIV2API RiffVideo : public Image {
//! @name Manipulators //! @name Manipulators
//@{ //@{
void printStructure(std::ostream& out, PrintStructureOption option, size_t depth) override;
void readMetadata() override; void readMetadata() override;
void writeMetadata() override; void writeMetadata() override;
//@} //@}

@ -488,7 +488,7 @@ template <typename T>
T stringTo(const std::string& s, bool& ok) { T stringTo(const std::string& s, bool& ok) {
std::istringstream is(s); std::istringstream is(s);
T tmp = T(); T tmp = T();
ok = bool(is >> tmp); ok = static_cast<bool>(is >> tmp);
std::string rest; std::string rest;
is >> std::skipws >> rest; is >> std::skipws >> rest;
if (!rest.empty()) if (!rest.empty())

@ -60,7 +60,7 @@ class EXIV2API Xmpdatum : public Metadatum {
@brief Assign a boolean \em value to the %Xmpdatum. @brief Assign a boolean \em value to the %Xmpdatum.
Translates the value to a string "true" or "false". Translates the value to a string "true" or "false".
*/ */
Xmpdatum& operator=(bool value); inline Xmpdatum& operator=(bool value);
/*! /*!
@brief Assign a \em value of any type with an output operator @brief Assign a \em value of any type with an output operator
to the %Xmpdatum. Calls operator=(const std::string&). to the %Xmpdatum. Calls operator=(const std::string&).
@ -398,7 +398,7 @@ class EXIV2API XmpParser {
// ***************************************************************************** // *****************************************************************************
// free functions, template and inline definitions // free functions, template and inline definitions
inline Xmpdatum& Xmpdatum::operator=(bool value) { Xmpdatum& Xmpdatum::operator=(bool value) {
return operator=(value ? "True" : "False"); return operator=(value ? "True" : "False");
} }

@ -26,7 +26,7 @@
// getopt.{cpp|hpp} is not part of libexiv2 // getopt.{cpp|hpp} is not part of libexiv2
#include "getopt.hpp" #include "getopt.hpp"
#ifdef EXV_HAVE_UNISTD_H #if __has_include(<unistd.h>)
#include <unistd.h> #include <unistd.h>
#endif #endif
#include <iostream> #include <iostream>
@ -79,7 +79,7 @@ int main(int argc, char** const argv) {
int n; int n;
#ifdef EXV_HAVE_UNISTD_H #if __has_include(<unistd.h>)
std::cout << "standard getopt()" << std::endl; std::cout << "standard getopt()" << std::endl;
do { do {
n = ::getopt(argc, argv, ::optstring); n = ::getopt(argc, argv, ::optstring);

@ -2,11 +2,16 @@
#include <exiv2/exiv2.hpp> #include <exiv2/exiv2.hpp>
#include <filesystem>
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#if __has_include(<filesystem>)
#include <filesystem>
namespace fs = std::filesystem; namespace fs = std::filesystem;
#else
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#endif
int main(int argc, char* const argv[]) { int main(int argc, char* const argv[]) {
Exiv2::XmpParser::initialize(); Exiv2::XmpParser::initialize();

@ -46,23 +46,23 @@ void mini1(const char* path) {
// Write nothing to a new structure, without a previous binary image // Write nothing to a new structure, without a previous binary image
wm = ExifParser::encode(blob, nullptr, 0, bigEndian, exifData); wm = ExifParser::encode(blob, nullptr, 0, bigEndian, exifData);
enforce(wm == wmIntrusive, Exiv2::ErrorCode::kerErrorMessage, "encode returned an unexpected value"); Internal::enforce(wm == wmIntrusive, Exiv2::ErrorCode::kerErrorMessage, "encode returned an unexpected value");
std::cout << "Test 1: Writing empty Exif data without original binary data: ok.\n"; std::cout << "Test 1: Writing empty Exif data without original binary data: ok.\n";
// Write nothing, this time with a previous binary image // Write nothing, this time with a previous binary image
DataBuf buf = readFile(path); DataBuf buf = readFile(path);
wm = ExifParser::encode(blob, buf.c_data(), buf.size(), bigEndian, exifData); wm = ExifParser::encode(blob, buf.c_data(), buf.size(), bigEndian, exifData);
enforce(wm == wmIntrusive, Exiv2::ErrorCode::kerErrorMessage, "encode returned an unexpected value"); Internal::enforce(wm == wmIntrusive, Exiv2::ErrorCode::kerErrorMessage, "encode returned an unexpected value");
std::cout << "Test 2: Writing empty Exif data with original binary data: ok.\n"; std::cout << "Test 2: Writing empty Exif data with original binary data: ok.\n";
// Write something to a new structure, without a previous binary image // Write something to a new structure, without a previous binary image
exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon"; exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon";
wm = ExifParser::encode(blob, nullptr, 0, bigEndian, exifData); wm = ExifParser::encode(blob, nullptr, 0, bigEndian, exifData);
enforce(wm == wmIntrusive, Exiv2::ErrorCode::kerErrorMessage, "encode returned an unexpected value"); Internal::enforce(wm == wmIntrusive, Exiv2::ErrorCode::kerErrorMessage, "encode returned an unexpected value");
std::cout << "Test 3: Wrote non-empty Exif data without original binary data:\n"; std::cout << "Test 3: Wrote non-empty Exif data without original binary data:\n";
exifData.clear(); exifData.clear();
ByteOrder bo = ExifParser::decode(exifData, blob.data(), blob.size()); ByteOrder bo = ExifParser::decode(exifData, blob.data(), blob.size());
enforce(bo == bigEndian, Exiv2::ErrorCode::kerErrorMessage, "decode returned an unexpected value"); Internal::enforce(bo == bigEndian, Exiv2::ErrorCode::kerErrorMessage, "decode returned an unexpected value");
print(exifData); print(exifData);
} }

@ -158,11 +158,6 @@ endif()
# Other library target properties # Other library target properties
# --------------------------------------------------------- # ---------------------------------------------------------
if (${CMAKE_CXX_COMPILER_ID} STREQUAL GNU)
# Do not check format overflows on this file, to skip a false positive warning
set_source_files_properties(value.cpp PROPERTIES COMPILE_FLAGS -Wno-format-overflow)
endif()
set_target_properties( exiv2lib PROPERTIES set_target_properties( exiv2lib PROPERTIES
VERSION ${PROJECT_VERSION} VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MINOR} SOVERSION ${PROJECT_VERSION_MINOR}
@ -189,10 +184,12 @@ target_include_directories(exiv2lib SYSTEM PRIVATE
if (EXIV2_ENABLE_XMP OR EXIV2_ENABLE_EXTERNAL_XMP) if (EXIV2_ENABLE_XMP OR EXIV2_ENABLE_EXTERNAL_XMP)
target_include_directories(exiv2lib PRIVATE ${EXPAT_INCLUDE_DIR}) target_include_directories(exiv2lib PRIVATE ${EXPAT_INCLUDE_DIR})
target_link_libraries(exiv2lib PRIVATE EXPAT::EXPAT) target_link_libraries(exiv2lib PRIVATE EXPAT::EXPAT)
list(APPEND requires_private_list "expat")
endif() endif()
if (EXIV2_ENABLE_XMP) if (EXIV2_ENABLE_XMP)
target_link_libraries(exiv2lib PRIVATE exiv2-xmp) target_link_libraries(exiv2lib PRIVATE exiv2-xmp)
list(APPEND libs_private_list "exiv2-xmp")
elseif(EXIV2_ENABLE_EXTERNAL_XMP) elseif(EXIV2_ENABLE_EXTERNAL_XMP)
target_link_libraries(exiv2lib PUBLIC ${XMPSDK_LIBRARY}) target_link_libraries(exiv2lib PUBLIC ${XMPSDK_LIBRARY})
target_include_directories(exiv2lib PUBLIC ${XMPSDK_INCLUDE_DIR}) target_include_directories(exiv2lib PUBLIC ${XMPSDK_INCLUDE_DIR})
@ -211,12 +208,11 @@ target_include_directories(exiv2lib_int PUBLIC
) )
if (EXIV2_ENABLE_WEBREADY) if (EXIV2_ENABLE_WEBREADY)
if( EXIV2_ENABLE_CURL ) if( EXIV2_ENABLE_CURL )
target_include_directories(exiv2lib SYSTEM PRIVATE ${CURL_INCLUDE_DIR} ) target_include_directories(exiv2lib SYSTEM PRIVATE ${CURL_INCLUDE_DIR} )
target_link_libraries(exiv2lib PRIVATE ${CURL_LIBRARIES}) target_link_libraries(exiv2lib PRIVATE ${CURL_LIBRARIES})
list(APPEND requires_private_list "libcurl")
endif() endif()
endif() endif()
if (WIN32) if (WIN32)
@ -240,24 +236,30 @@ endif()
if( EXIV2_ENABLE_PNG ) if( EXIV2_ENABLE_PNG )
target_link_libraries( exiv2lib PRIVATE ZLIB::ZLIB) target_link_libraries( exiv2lib PRIVATE ZLIB::ZLIB)
list(APPEND requires_private_list "zlib")
endif() endif()
if( EXIV2_ENABLE_BMFF AND BROTLI_FOUND ) if( EXIV2_ENABLE_BMFF AND BROTLI_FOUND )
target_link_libraries( exiv2lib PRIVATE ${Brotli_LIBRARIES}) target_link_libraries( exiv2lib PRIVATE ${Brotli_LIBRARIES})
target_include_directories(exiv2lib PRIVATE ${Brotli_INCLUDE_DIRS}) target_include_directories(exiv2lib PRIVATE ${Brotli_INCLUDE_DIRS})
list(APPEND requires_private_list "libbrotlidec")
endif() endif()
if( EXIV2_ENABLE_NLS ) if( EXIV2_ENABLE_NLS )
target_link_libraries(exiv2lib PRIVATE ${Intl_LIBRARIES}) target_link_libraries(exiv2lib PRIVATE ${Intl_LIBRARIES})
target_include_directories(exiv2lib PRIVATE ${Intl_INCLUDE_DIRS}) target_include_directories(exiv2lib PRIVATE ${Intl_INCLUDE_DIRS})
target_include_directories(exiv2lib_int PRIVATE ${Intl_INCLUDE_DIRS}) target_include_directories(exiv2lib_int PRIVATE ${Intl_INCLUDE_DIRS})
if( Intl_LIBRARIES )
list(APPEND libs_private_list "intl")
endif()
# Definition needed for translations # Definition needed for translations
join_paths(EXV_LOCALEDIR ".." "${CMAKE_INSTALL_LOCALEDIR}") join_paths(EXV_LOCALEDIR ".." "${CMAKE_INSTALL_LOCALEDIR}")
target_compile_definitions(exiv2lib PUBLIC EXV_LOCALEDIR="${EXV_LOCALEDIR}") target_compile_definitions(exiv2lib PUBLIC EXV_LOCALEDIR="${EXV_LOCALEDIR}")
endif() endif()
if( ICONV_FOUND ) if( Iconv_FOUND AND Iconv_LIBRARIES )
target_link_libraries( exiv2lib PRIVATE Iconv::Iconv ) target_link_libraries( exiv2lib PRIVATE Iconv::Iconv )
list(APPEND libs_private_list "iconv")
endif() endif()
if( EXIV2_ENABLE_INIH ) if( EXIV2_ENABLE_INIH )
@ -265,7 +267,20 @@ if( EXIV2_ENABLE_INIH )
target_link_libraries( exiv2lib_int PRIVATE inih::inireader ) target_link_libraries( exiv2lib_int PRIVATE inih::inireader )
target_link_libraries( exiv2lib PRIVATE inih::libinih ) target_link_libraries( exiv2lib PRIVATE inih::libinih )
target_link_libraries( exiv2lib PRIVATE inih::inireader ) target_link_libraries( exiv2lib PRIVATE inih::inireader )
list(APPEND requires_private_list "INIReader")
endif()
# Convert private lists to delimited strings
list(SORT libs_private_list)
string(REPLACE ";" " -l" libs_private_string "${libs_private_list}")
if(libs_private_string)
string(PREPEND libs_private_string "-l")
endif() endif()
list(SORT requires_private_list)
string(REPLACE ";" ", " requires_private_string "${requires_private_list}")
set(libs_private_for_pc_file "${libs_private_string}" PARENT_SCOPE)
set(requires_private_for_pc_file "${requires_private_string}" PARENT_SCOPE)
write_basic_package_version_file(exiv2ConfigVersion.cmake COMPATIBILITY ExactVersion) write_basic_package_version_file(exiv2ConfigVersion.cmake COMPATIBILITY ExactVersion)

@ -118,6 +118,7 @@ const std::map<std::string, std::string> GUIDReferenceTags = {
parsed into a character array GUID. parsed into a character array GUID.
https://fr.wikipedia.org/wiki/Globally_unique_identifier https://fr.wikipedia.org/wiki/Globally_unique_identifier
*/ */
std::string getGUID(DataBuf& buf) { std::string getGUID(DataBuf& buf) {
std::string GUID(36, '-'); std::string GUID(36, '-');
if (buf.size() >= 16) { if (buf.size() >= 16) {

@ -11,26 +11,25 @@
#include "image_int.hpp" #include "image_int.hpp"
#include "types.hpp" #include "types.hpp"
// + standard includes
#include <fcntl.h> // _O_BINARY in FileIo::FileIo
#include <sys/stat.h> // for stat, chmod
#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 <cstring> // std::memcpy
#include <ctime> // timestamp for the name of temporary file #include <ctime> // timestamp for the name of temporary file
#include <filesystem>
#include <fstream> // write the temporary file #include <fstream> // write the temporary file
#include <iostream> #include <iostream>
#ifdef EXV_HAVE_SYS_MMAN_H // + standard includes
#include <fcntl.h> // _O_BINARY in FileIo::FileIo
#include <sys/stat.h> // for stat, chmod
#if __has_include(<sys/mman.h>)
#include <sys/mman.h> // for mmap and munmap #include <sys/mman.h> // for mmap and munmap
#endif #endif
#ifdef EXV_HAVE_PROCESS_H #if __has_include(<process.h>)
#include <process.h> #include <process.h>
#endif #endif
#ifdef EXV_HAVE_UNISTD_H #if __has_include(<unistd.h>)
#include <unistd.h> // for getpid, stat #include <unistd.h>
#endif #endif
#ifdef EXV_USE_CURL #ifdef EXV_USE_CURL
@ -43,7 +42,13 @@
#include <windows.h> #include <windows.h>
#endif #endif
#if __has_include(<filesystem>)
#include <filesystem>
namespace fs = std::filesystem; namespace fs = std::filesystem;
#else
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#endif
// ***************************************************************************** // *****************************************************************************
// class member definitions // class member definitions
@ -61,13 +66,13 @@ void ReplaceStringInPlace(std::string& subject, std::string_view search, std::st
namespace Exiv2 { namespace Exiv2 {
void BasicIo::readOrThrow(byte* buf, size_t rcount, ErrorCode err) { void BasicIo::readOrThrow(byte* buf, size_t rcount, ErrorCode err) {
const size_t nread = read(buf, rcount); const size_t nread = read(buf, rcount);
enforce(nread == rcount, err); Internal::enforce(nread == rcount, err);
enforce(!error(), err); Internal::enforce(!error(), err);
} }
void BasicIo::seekOrThrow(int64_t offset, Position pos, ErrorCode err) { void BasicIo::seekOrThrow(int64_t offset, Position pos, ErrorCode err) {
const int r = seek(offset, pos); const int r = seek(offset, pos);
enforce(r == 0, err); Internal::enforce(r == 0, err);
} }
//! Internal Pimpl structure of class FileIo. //! Internal Pimpl structure of class FileIo.
@ -465,7 +470,7 @@ int FileIo::seek(int64_t offset, Position pos) {
size_t FileIo::tell() const { size_t FileIo::tell() const {
const long pos = std::ftell(p_->fp_); const long pos = std::ftell(p_->fp_);
enforce(pos >= 0, ErrorCode::kerInputDataReadFailed); Internal::enforce(pos >= 0, ErrorCode::kerInputDataReadFailed);
return static_cast<size_t>(pos); return static_cast<size_t>(pos);
} }

@ -249,7 +249,7 @@ uint64_t BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintS
byte hdrbuf[2 * sizeof(uint32_t)]; byte hdrbuf[2 * sizeof(uint32_t)];
size_t hdrsize = sizeof(hdrbuf); size_t hdrsize = sizeof(hdrbuf);
enforce(hdrsize <= static_cast<size_t>(pbox_end - address), Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(hdrsize <= static_cast<size_t>(pbox_end - address), Exiv2::ErrorCode::kerCorruptedMetadata);
if (io_->read(reinterpret_cast<byte*>(&hdrbuf), sizeof(hdrbuf)) != sizeof(hdrbuf)) if (io_->read(reinterpret_cast<byte*>(&hdrbuf), sizeof(hdrbuf)) != sizeof(hdrbuf))
return pbox_end; return pbox_end;
@ -268,7 +268,7 @@ uint64_t BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintS
if (box_length == 1) { if (box_length == 1) {
// The box size is encoded as a uint64_t, so we need to read another 8 bytes. // The box size is encoded as a uint64_t, so we need to read another 8 bytes.
hdrsize += 8; hdrsize += 8;
enforce(hdrsize <= static_cast<size_t>(pbox_end - address), Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(hdrsize <= static_cast<size_t>(pbox_end - address), Exiv2::ErrorCode::kerCorruptedMetadata);
DataBuf data(8); DataBuf data(8);
io_->read(data.data(), data.size()); io_->read(data.data(), data.size());
box_length = data.read_uint64(0, endian_); box_length = data.read_uint64(0, endian_);
@ -276,8 +276,8 @@ uint64_t BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintS
// read data in box and restore file position // read data in box and restore file position
const size_t restore = io_->tell(); const size_t restore = io_->tell();
enforce(box_length >= hdrsize, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(box_length >= hdrsize, Exiv2::ErrorCode::kerCorruptedMetadata);
enforce(box_length - hdrsize <= pbox_end - restore, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(box_length - hdrsize <= pbox_end - restore, Exiv2::ErrorCode::kerCorruptedMetadata);
const auto buffer_size = box_length - hdrsize; const auto buffer_size = box_length - hdrsize;
if (skipBox(box_type)) { if (skipBox(box_type)) {
@ -299,7 +299,7 @@ uint64_t BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintS
uint32_t flags = 0; uint32_t flags = 0;
if (fullBox(box_type)) { if (fullBox(box_type)) {
enforce(data.size() - skip >= 4, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(data.size() - skip >= 4, Exiv2::ErrorCode::kerCorruptedMetadata);
flags = data.read_uint32(skip, endian_); // version/flags flags = data.read_uint32(skip, endian_); // version/flags
version = static_cast<uint8_t>(flags >> 24); version = static_cast<uint8_t>(flags >> 24);
flags &= 0x00ffffff; flags &= 0x00ffffff;
@ -309,7 +309,7 @@ uint64_t BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintS
switch (box_type) { switch (box_type) {
// See notes in skipBox() // See notes in skipBox()
case TAG_ftyp: { case TAG_ftyp: {
enforce(data.size() >= 4, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(data.size() >= 4, Exiv2::ErrorCode::kerCorruptedMetadata);
fileType_ = data.read_uint32(0, endian_); fileType_ = data.read_uint32(0, endian_);
if (bTrace) { if (bTrace) {
out << "brand: " << toAscii(fileType_); out << "brand: " << toAscii(fileType_);
@ -323,7 +323,7 @@ uint64_t BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintS
bLF = false; bLF = false;
} }
enforce(data.size() - skip >= 2, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(data.size() - skip >= 2, Exiv2::ErrorCode::kerCorruptedMetadata);
uint16_t n = data.read_uint16(skip, endian_); uint16_t n = data.read_uint16(skip, endian_);
skip += 2; skip += 2;
@ -335,7 +335,7 @@ uint64_t BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintS
// 8.11.6.2 // 8.11.6.2
case TAG_infe: { // .__._.__hvc1_ 2 0 0 1 0 1 0 0 104 118 99 49 0 case TAG_infe: { // .__._.__hvc1_ 2 0 0 1 0 1 0 0 104 118 99 49 0
enforce(data.size() - skip >= 8, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(data.size() - skip >= 8, Exiv2::ErrorCode::kerCorruptedMetadata);
/* getULong (data.pData_+skip,endian_) ; */ skip += 4; /* getULong (data.pData_+skip,endian_) ; */ skip += 4;
uint16_t ID = data.read_uint16(skip, endian_); uint16_t ID = data.read_uint16(skip, endian_);
skip += 2; skip += 2;
@ -344,7 +344,7 @@ uint64_t BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintS
// Check that the string has a '\0' terminator. // Check that the string has a '\0' terminator.
const char* str = data.c_str(skip); const char* str = data.c_str(skip);
const size_t maxlen = data.size() - skip; const size_t maxlen = data.size() - skip;
enforce(maxlen > 0 && strnlen(str, maxlen) < maxlen, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(maxlen > 0 && strnlen(str, maxlen) < maxlen, Exiv2::ErrorCode::kerCorruptedMetadata);
std::string name(str); std::string name(str);
if (name.find("Exif") != std::string::npos) { // "Exif" or "ExifExif" if (name.find("Exif") != std::string::npos) { // "Exif" or "ExifExif"
exifID_ = ID; exifID_ = ID;
@ -393,7 +393,7 @@ uint64_t BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintS
// 8.11.3.1 // 8.11.3.1
case TAG_iloc: { case TAG_iloc: {
enforce(data.size() - skip >= 2, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(data.size() - skip >= 2, Exiv2::ErrorCode::kerCorruptedMetadata);
uint8_t u = data.read_uint8(skip++); uint8_t u = data.read_uint8(skip++);
uint16_t offsetSize = u >> 4; uint16_t offsetSize = u >> 4;
uint16_t lengthSize = u & 0xF; uint16_t lengthSize = u & 0xF;
@ -406,7 +406,7 @@ uint64_t BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintS
#else #else
skip++; skip++;
#endif #endif
enforce(data.size() - skip >= (version < 2u ? 2u : 4u), Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(data.size() - skip >= (version < 2u ? 2u : 4u), Exiv2::ErrorCode::kerCorruptedMetadata);
uint32_t itemCount = version < 2 ? data.read_uint16(skip, endian_) : data.read_uint32(skip, endian_); uint32_t itemCount = version < 2 ? data.read_uint16(skip, endian_) : data.read_uint32(skip, endian_);
skip += version < 2 ? 2 : 4; skip += version < 2 ? 2 : 4;
if (itemCount && itemCount < box_length / 14 && offsetSize == 4 && lengthSize == 4 && if (itemCount && itemCount < box_length / 14 && offsetSize == 4 && lengthSize == 4 &&
@ -419,10 +419,10 @@ uint64_t BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintS
size_t base = skip; size_t base = skip;
for (uint32_t i = 0; i < itemCount; i++) { for (uint32_t i = 0; i < itemCount; i++) {
skip = base + i * step; // move in 14, 16 or 18 byte steps skip = base + i * step; // move in 14, 16 or 18 byte steps
enforce(data.size() - skip >= (version > 2u ? 4u : 2u), Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(data.size() - skip >= (version > 2u ? 4u : 2u), Exiv2::ErrorCode::kerCorruptedMetadata);
enforce(data.size() - skip >= step, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(data.size() - skip >= step, Exiv2::ErrorCode::kerCorruptedMetadata);
uint32_t ID = version > 2 ? data.read_uint32(skip, endian_) : data.read_uint16(skip, endian_); uint32_t ID = version > 2 ? data.read_uint32(skip, endian_) : data.read_uint16(skip, endian_);
auto offset = [=] { auto offset = [this, &data, skip, step] {
if (step == 14 || step == 16) if (step == 14 || step == 16)
return data.read_uint32(skip + step - 8, endian_); return data.read_uint32(skip + step - 8, endian_);
if (step == 18) if (step == 18)
@ -445,7 +445,7 @@ uint64_t BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintS
} break; } break;
case TAG_ispe: { case TAG_ispe: {
enforce(data.size() - skip >= 12, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(data.size() - skip >= 12, Exiv2::ErrorCode::kerCorruptedMetadata);
skip += 4; skip += 4;
uint32_t width = data.read_uint32(skip, endian_); uint32_t width = data.read_uint32(skip, endian_);
skip += 4; skip += 4;
@ -524,7 +524,7 @@ uint64_t BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintS
parseXmp(buffer_size, io_->tell()); parseXmp(buffer_size, io_->tell());
break; break;
case TAG_brob: { case TAG_brob: {
enforce(data.size() >= 4, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(data.size() >= 4, Exiv2::ErrorCode::kerCorruptedMetadata);
uint32_t realType = data.read_uint32(0, endian_); uint32_t realType = data.read_uint32(0, endian_);
if (bTrace) { if (bTrace) {
out << "type: " << toAscii(realType); out << "type: " << toAscii(realType);
@ -534,7 +534,7 @@ uint64_t BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintS
brotliUncompress(data.c_data(4), data.size() - 4, arr); brotliUncompress(data.c_data(4), data.size() - 4, arr);
if (realType == TAG_exif) { if (realType == TAG_exif) {
uint32_t offset = Safe::add(arr.read_uint32(0, endian_), 4u); uint32_t offset = Safe::add(arr.read_uint32(0, endian_), 4u);
enforce(Safe::add(offset, 4u) < arr.size(), Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(Safe::add(offset, 4u) < arr.size(), Exiv2::ErrorCode::kerCorruptedMetadata);
Internal::TiffParserWorker::decode(exifData(), iptcData(), xmpData(), arr.c_data(offset), arr.size() - offset, Internal::TiffParserWorker::decode(exifData(), iptcData(), xmpData(), arr.c_data(offset), arr.size() - offset,
Internal::Tag::root, Internal::TiffMapping::findDecoder); Internal::Tag::root, Internal::TiffMapping::findDecoder);
} else if (realType == TAG_xml) { } else if (realType == TAG_xml) {
@ -580,10 +580,11 @@ uint64_t BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintS
} }
void BmffImage::parseTiff(uint32_t root_tag, uint64_t length, uint64_t start) { void BmffImage::parseTiff(uint32_t root_tag, uint64_t length, uint64_t start) {
enforce(start <= io_->size(), ErrorCode::kerCorruptedMetadata); Internal::enforce(start <= io_->size(), ErrorCode::kerCorruptedMetadata);
enforce(length <= io_->size() - start, ErrorCode::kerCorruptedMetadata); Internal::enforce(length <= io_->size() - start, ErrorCode::kerCorruptedMetadata);
enforce(start <= static_cast<uint64_t>(std::numeric_limits<int64_t>::max()), ErrorCode::kerCorruptedMetadata); Internal::enforce(start <= static_cast<uint64_t>(std::numeric_limits<int64_t>::max()),
enforce(length <= std::numeric_limits<size_t>::max(), ErrorCode::kerCorruptedMetadata); ErrorCode::kerCorruptedMetadata);
Internal::enforce(length <= std::numeric_limits<size_t>::max(), ErrorCode::kerCorruptedMetadata);
// read and parse exif data // read and parse exif data
const size_t restore = io_->tell(); const size_t restore = io_->tell();
@ -608,8 +609,8 @@ void BmffImage::parseTiff(uint32_t root_tag, uint64_t length, uint64_t start) {
void BmffImage::parseTiff(uint32_t root_tag, uint64_t length) { void BmffImage::parseTiff(uint32_t root_tag, uint64_t length) {
if (length > 8) { if (length > 8) {
enforce(length - 8 <= io_->size() - io_->tell(), ErrorCode::kerCorruptedMetadata); Internal::enforce(length - 8 <= io_->size() - io_->tell(), ErrorCode::kerCorruptedMetadata);
enforce(length - 8 <= std::numeric_limits<size_t>::max(), ErrorCode::kerCorruptedMetadata); Internal::enforce(length - 8 <= std::numeric_limits<size_t>::max(), ErrorCode::kerCorruptedMetadata);
DataBuf data(static_cast<size_t>(length - 8u)); DataBuf data(static_cast<size_t>(length - 8u));
const size_t bufRead = io_->read(data.data(), data.size()); const size_t bufRead = io_->read(data.data(), data.size());
@ -624,8 +625,8 @@ void BmffImage::parseTiff(uint32_t root_tag, uint64_t length) {
} }
void BmffImage::parseXmp(uint64_t length, uint64_t start) { void BmffImage::parseXmp(uint64_t length, uint64_t start) {
enforce(start <= io_->size(), ErrorCode::kerCorruptedMetadata); Internal::enforce(start <= io_->size(), ErrorCode::kerCorruptedMetadata);
enforce(length <= io_->size() - start, ErrorCode::kerCorruptedMetadata); Internal::enforce(length <= io_->size() - start, ErrorCode::kerCorruptedMetadata);
const size_t restore = io_->tell(); const size_t restore = io_->tell();
io_->seek(static_cast<int64_t>(start), BasicIo::beg); io_->seek(static_cast<int64_t>(start), BasicIo::beg);
@ -651,7 +652,7 @@ void BmffImage::parseCr3Preview(DataBuf& data, std::ostream& out, bool bTrace, u
size_t height_offset, size_t size_offset, size_t relative_position) { size_t height_offset, size_t size_offset, size_t relative_position) {
// Derived from https://github.com/lclevy/canon_cr3 // Derived from https://github.com/lclevy/canon_cr3
const size_t here = io_->tell(); const size_t here = io_->tell();
enforce(here <= std::numeric_limits<size_t>::max() - relative_position, ErrorCode::kerCorruptedMetadata); Internal::enforce(here <= std::numeric_limits<size_t>::max() - relative_position, ErrorCode::kerCorruptedMetadata);
NativePreview nativePreview; NativePreview nativePreview;
nativePreview.position_ = here + relative_position; nativePreview.position_ = here + relative_position;
nativePreview.width_ = data.read_uint16(width_offset, endian_); nativePreview.width_ = data.read_uint16(width_offset, endian_);

@ -740,7 +740,7 @@ void Converter::cnvExifDate(const char* from, const char* to) {
} }
if (subsec.size() > 10) if (subsec.size() > 10)
subsec = subsec.substr(0, 10); subsec.resize(10);
snprintf(buf, sizeof(buf), "%4d-%02d-%02dT%02d:%02d:%02d%s", year, month, day, hour, min, sec, subsec.c_str()); snprintf(buf, sizeof(buf), "%4d-%02d-%02dT%02d:%02d:%02d%s", year, month, day, hour, min, sec, subsec.c_str());
buf[sizeof(buf) - 1] = 0; buf[sizeof(buf) - 1] = 0;
@ -1141,7 +1141,7 @@ void Converter::cnvXmpGPSCoord(const char* from, const char* to) {
double deg = 0.0; double deg = 0.0;
double min = 0.0; double min = 0.0;
double sec = 0.0; double sec = 0.0;
char ref = value[value.length() - 1]; char ref = value.back();
char sep1 = '\0'; char sep1 = '\0';
char sep2 = '\0'; char sep2 = '\0';
@ -1553,8 +1553,8 @@ const ConvFctList convFctList[] = {
[[maybe_unused]] bool convertStringCharsetWindows(std::string& str, const char* from, const char* to) { [[maybe_unused]] bool convertStringCharsetWindows(std::string& str, const char* from, const char* to) {
bool ret = false; bool ret = false;
const ConvFctList* p = find(convFctList, std::pair(from, to));
std::string tmpstr = str; std::string tmpstr = str;
auto p = Exiv2::find(convFctList, std::pair(from, to));
if (p) if (p)
ret = p->convFct_(tmpstr); ret = p->convFct_(tmpstr);
#ifndef SUPPRESS_WARNINGS #ifndef SUPPRESS_WARNINGS

@ -22,6 +22,7 @@
#include "error.hpp" #include "error.hpp"
namespace Exiv2::Internal {
/*! /*!
* @brief Ensure that condition is true, otherwise throw an exception of the * @brief Ensure that condition is true, otherwise throw an exception of the
* type exception_t * type exception_t
@ -81,3 +82,4 @@ inline void enforce(bool condition, Exiv2::ErrorCode err_code, const T& arg1, co
throw Exiv2::Error(err_code, arg1, arg2, arg3); throw Exiv2::Error(err_code, arg1, arg2, arg3);
} }
} }
} // namespace Exiv2::Internal

@ -36,7 +36,7 @@ using namespace Exiv2::Internal;
constexpr auto dosEpsSignature = std::string_view("\xC5\xD0\xD3\xC6"); constexpr auto dosEpsSignature = std::string_view("\xC5\xD0\xD3\xC6");
// first line of EPS // first line of EPS
constexpr auto epsFirstLine = std::array<std::string_view, 3>{ constexpr std::string_view epsFirstLine[] = {
"%!PS-Adobe-3.0 EPSF-3.0", "%!PS-Adobe-3.0 EPSF-3.0",
"%!PS-Adobe-3.0 EPSF-3.0 ", // OpenOffice "%!PS-Adobe-3.0 EPSF-3.0 ", // OpenOffice
"%!PS-Adobe-3.1 EPSF-3.0", // Illustrator "%!PS-Adobe-3.1 EPSF-3.0", // Illustrator
@ -317,7 +317,7 @@ void readWriteEpsMetadata(BasicIo& io, std::string& xmpPacket, NativePreviewList
#ifdef DEBUG #ifdef DEBUG
EXV_DEBUG << "readWriteEpsMetadata: First line: " << firstLine << "\n"; EXV_DEBUG << "readWriteEpsMetadata: First line: " << firstLine << "\n";
#endif #endif
bool matched = std::find(epsFirstLine.begin(), epsFirstLine.end(), firstLine) != epsFirstLine.end(); auto matched = Exiv2::find(epsFirstLine, firstLine);
if (!matched) { if (!matched) {
throw Error(ErrorCode::kerNotAnImage, "EPS"); throw Error(ErrorCode::kerNotAnImage, "EPS");
} }

@ -241,7 +241,7 @@ std::ostream& printFujiDriveSetting(std::ostream& os, const Value& value, const
auto byte3 = (value.toInt64() >> 16) & 0xff; auto byte3 = (value.toInt64() >> 16) & 0xff;
auto fps = value.toInt64() >> 24; auto fps = value.toInt64() >> 24;
auto setting = find(fujiDriveSettingByte1, byte1); auto setting = Exiv2::find(fujiDriveSettingByte1, byte1);
if (setting) { if (setting) {
os << exvGettext(setting->label_); os << exvGettext(setting->label_);
} else { } else {
@ -347,7 +347,7 @@ std::ostream& printFujiFaceElementTypes(std::ostream& os, const Value& value, co
longValue -= '0'; longValue -= '0';
} }
auto td = find(fujiFaceElementType, longValue); auto td = Exiv2::find(fujiFaceElementType, longValue);
if (n != 0) { if (n != 0) {
os << " "; os << " ";
} }

@ -12,15 +12,16 @@
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <cstring> #include <cstring>
#include <filesystem>
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>
#ifdef EXV_HAVE_UNISTD_H #if __has_include(<filesystem>)
#include <unistd.h> // for stat() #include <filesystem>
#endif
namespace fs = std::filesystem; namespace fs = std::filesystem;
#else
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#endif
#if defined(_WIN32) #if defined(_WIN32)
// clang-format off // clang-format off
@ -29,10 +30,14 @@ namespace fs = std::filesystem;
// clang-format on // clang-format on
#endif #endif
#if defined(__APPLE__) && defined(EXV_HAVE_LIBPROC_H) #if __has_include(<libproc.h>)
#include <libproc.h> #include <libproc.h>
#endif #endif
#if __has_include(<unistd.h>)
#include <unistd.h> // for stat()
#endif
#if defined(__FreeBSD__) #if defined(__FreeBSD__)
#include <libprocstat.h> #include <libprocstat.h>
#include <sys/mount.h> #include <sys/mount.h>
@ -42,7 +47,6 @@ namespace fs = std::filesystem;
#include <sys/sysctl.h> #include <sys/sysctl.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/un.h> #include <sys/un.h>
#include <unistd.h>
#endif #endif
#ifndef _MAX_PATH #ifndef _MAX_PATH
@ -195,7 +199,7 @@ size_t base64decode(const char* in, char* out, size_t out_size) {
Protocol fileProtocol(const std::string& path) { Protocol fileProtocol(const std::string& path) {
Protocol result = pFile; Protocol result = pFile;
struct { const struct {
std::string name; std::string name;
Protocol prot; Protocol prot;
bool isUrl; // path.size() > name.size() bool isUrl; // path.size() > name.size()
@ -234,7 +238,7 @@ std::string strError() {
#else #else
char buf[n] = {}; char buf[n] = {};
const int ret = strerror_r(error, buf, n); const int ret = strerror_r(error, buf, n);
enforce(ret != ERANGE, Exiv2::ErrorCode::kerCallFailed); Internal::enforce(ret != ERANGE, Exiv2::ErrorCode::kerCallFailed);
#endif #endif
os << buf; os << buf;
// Issue# 908. // Issue# 908.
@ -342,14 +346,12 @@ std::string getProcessPath() {
} }
CloseHandle(processHandle); CloseHandle(processHandle);
} }
#elif defined(__APPLE__) #elif __has_include(<libproc.h>)
#ifdef EXV_HAVE_LIBPROC_H
const int pid = getpid(); const int pid = getpid();
char pathbuf[PROC_PIDPATHINFO_MAXSIZE]; char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
if (proc_pidpath(pid, pathbuf, sizeof(pathbuf)) > 0) { if (proc_pidpath(pid, pathbuf, sizeof(pathbuf)) > 0) {
ret = pathbuf; ret = pathbuf;
} }
#endif
#elif defined(__FreeBSD__) #elif defined(__FreeBSD__)
unsigned int n; unsigned int n;
char buffer[PATH_MAX] = {}; char buffer[PATH_MAX] = {};
@ -374,7 +376,7 @@ std::string getProcessPath() {
ret = path; ret = path;
} }
#elif defined(__unix__) #elif defined(__unix__)
ret = std::filesystem::read_symlink("/proc/self/exe"); ret = fs::read_symlink("/proc/self/exe");
#endif #endif
const size_t idxLastSeparator = ret.find_last_of(EXV_SEPARATOR_CHR); const size_t idxLastSeparator = ret.find_last_of(EXV_SEPARATOR_CHR);

@ -38,31 +38,31 @@ std::string toString16(Exiv2::DataBuf& buf) {
} }
uint64_t readQWORDTag(BasicIo::UniquePtr& io) { uint64_t readQWORDTag(BasicIo::UniquePtr& io) {
enforce(QWORD <= io->size() - io->tell(), Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(QWORD <= io->size() - io->tell(), Exiv2::ErrorCode::kerCorruptedMetadata);
DataBuf FieldBuf = io->read(QWORD); DataBuf FieldBuf = io->read(QWORD);
return FieldBuf.read_uint64(0, littleEndian); return FieldBuf.read_uint64(0, littleEndian);
} }
uint32_t readDWORDTag(BasicIo::UniquePtr& io) { uint32_t readDWORDTag(BasicIo::UniquePtr& io) {
enforce(DWORD <= io->size() - io->tell(), Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(DWORD <= io->size() - io->tell(), Exiv2::ErrorCode::kerCorruptedMetadata);
DataBuf FieldBuf = io->read(DWORD); DataBuf FieldBuf = io->read(DWORD);
return FieldBuf.read_uint32(0, littleEndian); return FieldBuf.read_uint32(0, littleEndian);
} }
uint16_t readWORDTag(BasicIo::UniquePtr& io) { uint16_t readWORDTag(BasicIo::UniquePtr& io) {
enforce(WORD <= io->size() - io->tell(), Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(WORD <= io->size() - io->tell(), Exiv2::ErrorCode::kerCorruptedMetadata);
DataBuf FieldBuf = io->read(WORD); DataBuf FieldBuf = io->read(WORD);
return FieldBuf.read_uint16(0, littleEndian); return FieldBuf.read_uint16(0, littleEndian);
} }
std::string readStringWcharTag(BasicIo::UniquePtr& io, uint16_t length) { std::string readStringWcharTag(BasicIo::UniquePtr& io, uint16_t length) {
enforce(length <= io->size() - io->tell(), Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(length <= io->size() - io->tell(), Exiv2::ErrorCode::kerCorruptedMetadata);
DataBuf FieldBuf = io->read(length); DataBuf FieldBuf = io->read(length);
return toString16(FieldBuf); return toString16(FieldBuf);
} }
std::string readStringTag(BasicIo::UniquePtr& io, uint16_t length) { std::string readStringTag(BasicIo::UniquePtr& io, uint16_t length) {
enforce(length <= io->size() - io->tell(), Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(length <= io->size() - io->tell(), Exiv2::ErrorCode::kerCorruptedMetadata);
DataBuf FieldBuf = io->read(length); DataBuf FieldBuf = io->read(length);
return Exiv2::toString(FieldBuf.data()); return Exiv2::toString(FieldBuf.data());
} }

@ -131,13 +131,13 @@ static int makeNonBlocking(int sockfd) {
} }
int Exiv2::http(Exiv2::Dictionary& request, Exiv2::Dictionary& response, std::string& errors) { int Exiv2::http(Exiv2::Dictionary& request, Exiv2::Dictionary& response, std::string& errors) {
if (!request.count("verb")) if (request.find("verb") == request.end())
request["verb"] = "GET"; request["verb"] = "GET";
if (!request.count("header")) if (request.find("header") == request.end())
request["header"] = ""; request["header"] = "";
if (!request.count("version")) if (request.find("version") == request.end())
request["version"] = "1.0"; request["version"] = "1.0";
if (!request.count("port")) if (request.find("port") == request.end())
request["port"] = ""; request["port"] = "";
std::string file; std::string file;
@ -305,8 +305,8 @@ int Exiv2::http(Exiv2::Dictionary& request, Exiv2::Dictionary& response, std::st
while (c && first_newline && c < first_newline && h < buffer + body) { while (c && first_newline && c < first_newline && h < buffer + body) {
std::string key(h); std::string key(h);
std::string value(c + 1); std::string value(c + 1);
key = key.substr(0, c - h); key.resize(c - h);
value = value.substr(0, first_newline - c - 1); value.resize(first_newline - c - 1);
response[key] = value; response[key] = value;
h = first_newline + 1; h = first_newline + 1;
c = strchr(h, C); c = strchr(h, C);

@ -308,7 +308,7 @@ void Image::printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStruct
io.readOrThrow(dir.data(), 2, ErrorCode::kerCorruptedMetadata); io.readOrThrow(dir.data(), 2, ErrorCode::kerCorruptedMetadata);
uint16_t dirLength = byteSwap2(dir, 0, bSwap); uint16_t dirLength = byteSwap2(dir, 0, bSwap);
// Prevent infinite loops. (GHSA-m479-7frc-gqqg) // Prevent infinite loops. (GHSA-m479-7frc-gqqg)
enforce(dirLength > 0, ErrorCode::kerCorruptedMetadata); Internal::enforce(dirLength > 0, ErrorCode::kerCorruptedMetadata);
if (dirLength > 500) // tooBig if (dirLength > 500) // tooBig
throw Error(ErrorCode::kerTiffDirectoryTooLarge); throw Error(ErrorCode::kerTiffDirectoryTooLarge);
@ -384,7 +384,7 @@ void Image::printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStruct
throw Error(ErrorCode::kerInvalidMalloc); throw Error(ErrorCode::kerInvalidMalloc);
} }
// Overflow check // Overflow check
enforce(allocate64 <= std::numeric_limits<size_t>::max(), ErrorCode::kerCorruptedMetadata); Internal::enforce(allocate64 <= std::numeric_limits<size_t>::max(), ErrorCode::kerCorruptedMetadata);
DataBuf buf(allocate64); // allocate a buffer DataBuf buf(allocate64); // allocate a buffer
std::copy_n(dir.c_data(8), 4, buf.begin()); // copy dir[8:11] into buffer (short strings) std::copy_n(dir.c_data(8), 4, buf.begin()); // copy dir[8:11] into buffer (short strings)

@ -12,7 +12,9 @@
#include <ostream> // for ostream, basic_ostream::put #include <ostream> // for ostream, basic_ostream::put
#include <string> #include <string>
#if (defined(__GNUG__) || defined(__GNUC__)) || defined(__clang__) #if defined(__MINGW32__)
#define ATTRIBUTE_FORMAT_PRINTF __attribute__((format(__MINGW_PRINTF_FORMAT, 1, 0)))
#elif defined(__GNUC__)
#define ATTRIBUTE_FORMAT_PRINTF __attribute__((format(printf, 1, 0))) #define ATTRIBUTE_FORMAT_PRINTF __attribute__((format(printf, 1, 0)))
#else #else
#define ATTRIBUTE_FORMAT_PRINTF #define ATTRIBUTE_FORMAT_PRINTF

@ -290,12 +290,12 @@ void IptcData::printStructure(std::ostream& out, const Slice<byte*>& bytes, size
char buff[100]; char buff[100];
uint16_t record = bytes.at(i + 1); uint16_t record = bytes.at(i + 1);
uint16_t dataset = bytes.at(i + 2); uint16_t dataset = bytes.at(i + 2);
enforce(bytes.size() - i >= 5, ErrorCode::kerCorruptedMetadata); Internal::enforce(bytes.size() - i >= 5, ErrorCode::kerCorruptedMetadata);
uint16_t len = getUShort(bytes.subSlice(i + 3, bytes.size()), bigEndian); uint16_t len = getUShort(bytes.subSlice(i + 3, bytes.size()), bigEndian);
snprintf(buff, sizeof(buff), " %6d | %7d | %-24s | %6d | ", record, dataset, snprintf(buff, sizeof(buff), " %6d | %7d | %-24s | %6d | ", record, dataset,
Exiv2::IptcDataSets::dataSetName(dataset, record).c_str(), len); Exiv2::IptcDataSets::dataSetName(dataset, record).c_str(), len);
enforce(bytes.size() - i >= 5 + static_cast<size_t>(len), ErrorCode::kerCorruptedMetadata); Internal::enforce(bytes.size() - i >= 5 + static_cast<size_t>(len), ErrorCode::kerCorruptedMetadata);
out << buff << Internal::binaryToString(makeSlice(bytes, i + 5, i + 5 + (len > 40 ? 40 : len))) out << buff << Internal::binaryToString(makeSlice(bytes, i + 5, i + 5 + (len > 40 ? 40 : len)))
<< (len > 40 ? "..." : "") << std::endl; << (len > 40 ? "..." : "") << std::endl;
i += 5 + len; i += 5 + len;

@ -157,7 +157,7 @@ void Jp2Image::readMetadata() {
<< "Position: " << position << " box type: " << toAscii(box.type) << " length: " << box.length << "Position: " << position << " box type: " << toAscii(box.type) << " length: " << box.length
<< std::endl; << std::endl;
#endif #endif
enforce(box.length <= boxHSize + io_->size() - io_->tell(), ErrorCode::kerCorruptedMetadata); Internal::enforce(box.length <= boxHSize + io_->size() - io_->tell(), ErrorCode::kerCorruptedMetadata);
if (box.length == 0) if (box.length == 0)
return; return;
@ -245,7 +245,7 @@ void Jp2Image::readMetadata() {
ihdr.imageHeight = getULong(reinterpret_cast<byte*>(&ihdr.imageHeight), bigEndian); ihdr.imageHeight = getULong(reinterpret_cast<byte*>(&ihdr.imageHeight), bigEndian);
ihdr.imageWidth = getULong(reinterpret_cast<byte*>(&ihdr.imageWidth), bigEndian); ihdr.imageWidth = getULong(reinterpret_cast<byte*>(&ihdr.imageWidth), bigEndian);
ihdr.componentCount = getShort(reinterpret_cast<byte*>(&ihdr.componentCount), bigEndian); ihdr.componentCount = getShort(reinterpret_cast<byte*>(&ihdr.componentCount), bigEndian);
enforce(ihdr.c == 7, ErrorCode::kerCorruptedMetadata); Internal::enforce(ihdr.c == 7, ErrorCode::kerCorruptedMetadata);
pixelWidth_ = ihdr.imageWidth; pixelWidth_ = ihdr.imageWidth;
pixelHeight_ = ihdr.imageHeight; pixelHeight_ = ihdr.imageHeight;
@ -276,7 +276,7 @@ void Jp2Image::readMetadata() {
#ifdef EXIV2_DEBUG_MESSAGES #ifdef EXIV2_DEBUG_MESSAGES
std::cout << "Exiv2::Jp2Image::readMetadata: Exif data found" << std::endl; std::cout << "Exiv2::Jp2Image::readMetadata: Exif data found" << std::endl;
#endif #endif
enforce(box.length >= boxHSize + sizeof(uuid), ErrorCode::kerCorruptedMetadata); Internal::enforce(box.length >= boxHSize + sizeof(uuid), ErrorCode::kerCorruptedMetadata);
rawData.alloc(box.length - (boxHSize + sizeof(uuid))); rawData.alloc(box.length - (boxHSize + sizeof(uuid)));
bufRead = io_->read(rawData.data(), rawData.size()); bufRead = io_->read(rawData.data(), rawData.size());
if (io_->error()) if (io_->error())
@ -324,7 +324,7 @@ void Jp2Image::readMetadata() {
#ifdef EXIV2_DEBUG_MESSAGES #ifdef EXIV2_DEBUG_MESSAGES
std::cout << "Exiv2::Jp2Image::readMetadata: Iptc data found" << std::endl; std::cout << "Exiv2::Jp2Image::readMetadata: Iptc data found" << std::endl;
#endif #endif
enforce(box.length >= boxHSize + sizeof(uuid), ErrorCode::kerCorruptedMetadata); Internal::enforce(box.length >= boxHSize + sizeof(uuid), ErrorCode::kerCorruptedMetadata);
rawData.alloc(box.length - (boxHSize + sizeof(uuid))); rawData.alloc(box.length - (boxHSize + sizeof(uuid)));
bufRead = io_->read(rawData.data(), rawData.size()); bufRead = io_->read(rawData.data(), rawData.size());
if (io_->error()) if (io_->error())
@ -344,7 +344,7 @@ void Jp2Image::readMetadata() {
#ifdef EXIV2_DEBUG_MESSAGES #ifdef EXIV2_DEBUG_MESSAGES
std::cout << "Exiv2::Jp2Image::readMetadata: Xmp data found" << std::endl; std::cout << "Exiv2::Jp2Image::readMetadata: Xmp data found" << std::endl;
#endif #endif
enforce(box.length >= boxHSize + sizeof(uuid), ErrorCode::kerCorruptedMetadata); Internal::enforce(box.length >= boxHSize + sizeof(uuid), ErrorCode::kerCorruptedMetadata);
rawData.alloc(box.length - (boxHSize + sizeof(uuid))); rawData.alloc(box.length - (boxHSize + sizeof(uuid)));
bufRead = io_->read(rawData.data(), rawData.size()); bufRead = io_->read(rawData.data(), rawData.size());
if (io_->error()) if (io_->error())
@ -420,7 +420,7 @@ void Jp2Image::printStructure(std::ostream& out, PrintStructureOption option, si
const size_t position = io_->tell(); const size_t position = io_->tell();
box.length = getULong(reinterpret_cast<byte*>(&box.length), bigEndian); box.length = getULong(reinterpret_cast<byte*>(&box.length), bigEndian);
box.type = getULong(reinterpret_cast<byte*>(&box.type), bigEndian); box.type = getULong(reinterpret_cast<byte*>(&box.type), bigEndian);
enforce(box.length <= boxHSize + io_->size() - io_->tell(), ErrorCode::kerCorruptedMetadata); Internal::enforce(box.length <= boxHSize + io_->size() - io_->tell(), ErrorCode::kerCorruptedMetadata);
if (bPrint) { if (bPrint) {
out << Internal::stringFormat("%8ld | %8ld | ", position - boxHSize, static_cast<size_t>(box.length)) out << Internal::stringFormat("%8ld | %8ld | ", position - boxHSize, static_cast<size_t>(box.length))
@ -473,7 +473,7 @@ void Jp2Image::printStructure(std::ostream& out, PrintStructureOption option, si
} }
if (subBox.type == kJp2BoxTypeImageHeader) { if (subBox.type == kJp2BoxTypeImageHeader) {
enforce(subBox.length == 22, ErrorCode::kerCorruptedMetadata); Internal::enforce(subBox.length == 22, ErrorCode::kerCorruptedMetadata);
// height (4), width (4), componentsCount (2), bpc (1) // height (4), width (4), componentsCount (2), bpc (1)
auto compressionType = data.read_uint8(11); auto compressionType = data.read_uint8(11);
auto unkC = data.read_uint8(12); auto unkC = data.read_uint8(12);
@ -485,7 +485,7 @@ void Jp2Image::printStructure(std::ostream& out, PrintStructureOption option, si
const size_t pad = 3; // don't know why there are 3 padding bytes const size_t pad = 3; // don't know why there are 3 padding bytes
// Bounds-check for the `getULong()` below, which reads 4 bytes, starting at `pad`. // Bounds-check for the `getULong()` below, which reads 4 bytes, starting at `pad`.
enforce(data.size() >= pad + 4, ErrorCode::kerCorruptedMetadata); Internal::enforce(data.size() >= pad + 4, ErrorCode::kerCorruptedMetadata);
/// \todo A conforming JP2 reader shall ignore all Colour Specification boxes after the first. /// \todo A conforming JP2 reader shall ignore all Colour Specification boxes after the first.
auto METH = data.read_uint8(0); auto METH = data.read_uint8(0);
@ -502,7 +502,7 @@ void Jp2Image::printStructure(std::ostream& out, PrintStructureOption option, si
if (bPrint) { if (bPrint) {
out << " | iccLength:" << iccLength; out << " | iccLength:" << iccLength;
} }
enforce(iccLength <= data.size() - pad, ErrorCode::kerCorruptedMetadata); Internal::enforce(iccLength <= data.size() - pad, ErrorCode::kerCorruptedMetadata);
if (bICC) { if (bICC) {
out.write(data.c_str(pad), iccLength); out.write(data.c_str(pad), iccLength);
} }
@ -532,7 +532,7 @@ void Jp2Image::printStructure(std::ostream& out, PrintStructureOption option, si
} }
DataBuf rawData; DataBuf rawData;
enforce(box.length >= sizeof(uuid) + boxHSize, ErrorCode::kerCorruptedMetadata); Internal::enforce(box.length >= sizeof(uuid) + boxHSize, ErrorCode::kerCorruptedMetadata);
rawData.alloc(box.length - sizeof(uuid) - boxHSize); rawData.alloc(box.length - sizeof(uuid) - boxHSize);
const size_t bufRead = io_->read(rawData.data(), rawData.size()); const size_t bufRead = io_->read(rawData.data(), rawData.size());
if (io_->error()) if (io_->error())
@ -602,14 +602,14 @@ void Jp2Image::encodeJp2Header(const DataBuf& boxBuf, DataBuf& outBuf) {
DataBuf output(boxBuf.size() + iccProfile_.size() + 100); // allocate sufficient space DataBuf output(boxBuf.size() + iccProfile_.size() + 100); // allocate sufficient space
size_t outlen = boxHSize; // now many bytes have we written to output? size_t outlen = boxHSize; // now many bytes have we written to output?
size_t inlen = boxHSize; // how many bytes have we read from boxBuf? size_t inlen = boxHSize; // how many bytes have we read from boxBuf?
enforce(boxHSize <= output.size(), ErrorCode::kerCorruptedMetadata); Internal::enforce(boxHSize <= output.size(), ErrorCode::kerCorruptedMetadata);
uint32_t length = getULong(boxBuf.c_data(0), bigEndian); uint32_t length = getULong(boxBuf.c_data(0), bigEndian);
enforce(length <= output.size(), ErrorCode::kerCorruptedMetadata); Internal::enforce(length <= output.size(), ErrorCode::kerCorruptedMetadata);
uint32_t count = boxHSize; uint32_t count = boxHSize;
bool bWroteColor = false; bool bWroteColor = false;
while (count < length && !bWroteColor) { while (count < length && !bWroteColor) {
enforce(boxHSize <= length - count, ErrorCode::kerCorruptedMetadata); Internal::enforce(boxHSize <= length - count, ErrorCode::kerCorruptedMetadata);
Internal::Jp2BoxHeader subBox; Internal::Jp2BoxHeader subBox;
memcpy(&subBox, boxBuf.c_data(count), boxHSize); memcpy(&subBox, boxBuf.c_data(count), boxHSize);
Internal::Jp2BoxHeader newBox = subBox; Internal::Jp2BoxHeader newBox = subBox;
@ -621,8 +621,8 @@ void Jp2Image::encodeJp2Header(const DataBuf& boxBuf, DataBuf& outBuf) {
std::cout << "Jp2Image::encodeJp2Header subbox: " << toAscii(subBox.type) << " length = " << subBox.length std::cout << "Jp2Image::encodeJp2Header subbox: " << toAscii(subBox.type) << " length = " << subBox.length
<< std::endl; << std::endl;
#endif #endif
enforce(subBox.length > 0, ErrorCode::kerCorruptedMetadata); Internal::enforce(subBox.length > 0, ErrorCode::kerCorruptedMetadata);
enforce(subBox.length <= length - count, ErrorCode::kerCorruptedMetadata); Internal::enforce(subBox.length <= length - count, ErrorCode::kerCorruptedMetadata);
count += subBox.length; count += subBox.length;
newBox.type = subBox.type; newBox.type = subBox.type;
} else { } else {
@ -637,7 +637,7 @@ void Jp2Image::encodeJp2Header(const DataBuf& boxBuf, DataBuf& outBuf) {
if (!iccProfileDefined()) { if (!iccProfileDefined()) {
const char* pad = "\x01\x00\x00\x00\x00\x00\x10\x00\x00\x05\x1cuuid"; const char* pad = "\x01\x00\x00\x00\x00\x00\x10\x00\x00\x05\x1cuuid";
uint32_t psize = 15; uint32_t psize = 15;
enforce(newlen <= output.size() - outlen, ErrorCode::kerCorruptedMetadata); Internal::enforce(newlen <= output.size() - outlen, ErrorCode::kerCorruptedMetadata);
ul2Data(reinterpret_cast<byte*>(&newBox.length), psize, bigEndian); ul2Data(reinterpret_cast<byte*>(&newBox.length), psize, bigEndian);
ul2Data(reinterpret_cast<byte*>(&newBox.type), newBox.type, bigEndian); ul2Data(reinterpret_cast<byte*>(&newBox.type), newBox.type, bigEndian);
std::copy_n(reinterpret_cast<char*>(&newBox), sizeof(newBox), output.begin() + outlen); std::copy_n(reinterpret_cast<char*>(&newBox), sizeof(newBox), output.begin() + outlen);
@ -646,7 +646,7 @@ void Jp2Image::encodeJp2Header(const DataBuf& boxBuf, DataBuf& outBuf) {
const char* pad = "\x02\x00\x00"; const char* pad = "\x02\x00\x00";
uint32_t psize = 3; uint32_t psize = 3;
newlen = sizeof(newBox) + psize + iccProfile_.size(); newlen = sizeof(newBox) + psize + iccProfile_.size();
enforce(newlen <= output.size() - outlen, ErrorCode::kerCorruptedMetadata); Internal::enforce(newlen <= output.size() - outlen, ErrorCode::kerCorruptedMetadata);
ul2Data(reinterpret_cast<byte*>(&newBox.length), static_cast<uint32_t>(newlen), bigEndian); ul2Data(reinterpret_cast<byte*>(&newBox.length), static_cast<uint32_t>(newlen), bigEndian);
ul2Data(reinterpret_cast<byte*>(&newBox.type), newBox.type, bigEndian); ul2Data(reinterpret_cast<byte*>(&newBox.type), newBox.type, bigEndian);
std::copy_n(reinterpret_cast<char*>(&newBox), sizeof(newBox), output.begin() + outlen); std::copy_n(reinterpret_cast<char*>(&newBox), sizeof(newBox), output.begin() + outlen);
@ -654,7 +654,7 @@ void Jp2Image::encodeJp2Header(const DataBuf& boxBuf, DataBuf& outBuf) {
std::copy(iccProfile_.begin(), iccProfile_.end(), output.begin() + outlen + sizeof(newBox) + psize); std::copy(iccProfile_.begin(), iccProfile_.end(), output.begin() + outlen + sizeof(newBox) + psize);
} }
} else { } else {
enforce(newlen <= output.size() - outlen, ErrorCode::kerCorruptedMetadata); Internal::enforce(newlen <= output.size() - outlen, ErrorCode::kerCorruptedMetadata);
std::copy_n(boxBuf.c_data(inlen), subBox.length, output.begin() + outlen); std::copy_n(boxBuf.c_data(inlen), subBox.length, output.begin() + outlen);
} }
@ -734,7 +734,8 @@ void Jp2Image::doWriteMetadata(BasicIo& outIo) {
} }
// Prevent a malicious file from causing a large memory allocation. // Prevent a malicious file from causing a large memory allocation.
enforce(box.length - 8 <= static_cast<size_t>(io_->size() - io_->tell()), ErrorCode::kerCorruptedMetadata); Internal::enforce(box.length - 8 <= static_cast<size_t>(io_->size() - io_->tell()),
ErrorCode::kerCorruptedMetadata);
// Read whole box : Box header + Box data (not fixed size - can be null). // Read whole box : Box header + Box data (not fixed size - can be null).
DataBuf boxBuf(box.length); // Box header (8 bytes) + box data. DataBuf boxBuf(box.length); // Box header (8 bytes) + box data.
@ -831,7 +832,7 @@ void Jp2Image::doWriteMetadata(BasicIo& outIo) {
} }
case kJp2BoxTypeUuid: { case kJp2BoxTypeUuid: {
enforce(boxBuf.size() >= 24, ErrorCode::kerCorruptedMetadata); Internal::enforce(boxBuf.size() >= 24, ErrorCode::kerCorruptedMetadata);
if (boxBuf.cmpBytes(8, kJp2UuidExif, 16) == 0) { if (boxBuf.cmpBytes(8, kJp2UuidExif, 16) == 0) {
#ifdef EXIV2_DEBUG_MESSAGES #ifdef EXIV2_DEBUG_MESSAGES
std::cout << "Exiv2::Jp2Image::doWriteMetadata: strip Exif Uuid box" << std::endl; std::cout << "Exiv2::Jp2Image::doWriteMetadata: strip Exif Uuid box" << std::endl;

@ -31,6 +31,7 @@
namespace Exiv2 { namespace Exiv2 {
using Exiv2::Internal::enforce;
using Exiv2::Internal::startsWith; using Exiv2::Internal::startsWith;
namespace { namespace {
// JPEG Segment markers (The first byte is always 0xFF, the value of these constants correspond to the 2nd byte) // JPEG Segment markers (The first byte is always 0xFF, the value of these constants correspond to the 2nd byte)
@ -61,11 +62,11 @@ constexpr auto exifId_ = "Exif\0\0"; //!< Exif identifier
constexpr auto xmpId_ = "http://ns.adobe.com/xap/1.0/\0"; //!< XMP packet identifier constexpr auto xmpId_ = "http://ns.adobe.com/xap/1.0/\0"; //!< XMP packet identifier
constexpr auto iccId_ = "ICC_PROFILE\0"; //!< ICC profile identifier constexpr auto iccId_ = "ICC_PROFILE\0"; //!< ICC profile identifier
inline bool inRange(int lo, int value, int hi) { constexpr bool inRange(int lo, int value, int hi) {
return lo <= value && value <= hi; return lo <= value && value <= hi;
} }
inline bool inRange2(int value, int lo1, int hi1, int lo2, int hi2) { constexpr bool inRange2(int value, int lo1, int hi1, int lo2, int hi2) {
return inRange(lo1, value, hi1) || inRange(lo2, value, hi2); return inRange(lo1, value, hi1) || inRange(lo2, value, hi2);
} }

@ -15,14 +15,16 @@
#include "utils.hpp" #include "utils.hpp"
// + standard includes // + standard includes
#ifdef EXV_ENABLE_INIH
#include <INIReader.h>
#endif
#include <array> #include <array>
#include <filesystem>
#include <iostream> #include <iostream>
#if __has_include(<filesystem>)
#include <filesystem>
namespace fs = std::filesystem; namespace fs = std::filesystem;
#else
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#endif
#if !defined(_WIN32) #if !defined(_WIN32)
#include <pwd.h> #include <pwd.h>
@ -33,7 +35,10 @@ namespace fs = std::filesystem;
#define CSIDL_PROFILE 40 #define CSIDL_PROFILE 40
#endif #endif
#include <process.h> #include <process.h>
#endif
#ifdef EXV_ENABLE_INIH
#include <INIReader.h>
#endif #endif
// ***************************************************************************** // *****************************************************************************
@ -137,16 +142,16 @@ bool TiffMnRegistry::operator==(IfdId key) const {
TiffComponent* TiffMnCreator::create(uint16_t tag, IfdId group, const std::string& make, const byte* pData, size_t size, TiffComponent* TiffMnCreator::create(uint16_t tag, IfdId group, const std::string& make, const byte* pData, size_t size,
ByteOrder byteOrder) { ByteOrder byteOrder) {
auto tmr = std::find(std::begin(registry_), std::end(registry_), make); auto tmr = Exiv2::find(registry_, make);
if (tmr != std::end(registry_)) { if (!tmr) {
return tmr->newMnFct_(tag, group, tmr->mnGroup_, pData, size, byteOrder);
}
return nullptr; return nullptr;
}
return tmr->newMnFct_(tag, group, tmr->mnGroup_, pData, size, byteOrder);
} // TiffMnCreator::create } // TiffMnCreator::create
TiffComponent* TiffMnCreator::create(uint16_t tag, IfdId group, IfdId mnGroup) { TiffComponent* TiffMnCreator::create(uint16_t tag, IfdId group, IfdId mnGroup) {
auto tmr = std::find(std::begin(registry_), std::end(registry_), mnGroup); auto tmr = Exiv2::find(registry_, mnGroup);
if (tmr != std::end(registry_)) { if (tmr) {
if (tmr->newMnFct2_) { if (tmr->newMnFct2_) {
return tmr->newMnFct2_(tag, group, mnGroup); return tmr->newMnFct2_(tag, group, mnGroup);
} }
@ -859,35 +864,46 @@ struct NikonArrayIdx {
#define NA ((uint32_t)-1) #define NA ((uint32_t)-1)
//! Nikon binary array version lookup table //! Nikon binary array version lookup table
constexpr auto nikonArrayIdx = std::array{ constexpr NikonArrayIdx nikonArrayIdx[] = {
// NikonSi // NikonSi
NikonArrayIdx{0x0091, "0208", 0, 0, 4}, // D80 {0x0091, "0208", 0, 0, 4}, // D80
NikonArrayIdx{0x0091, "0209", 0, 1, 4}, // D40 {0x0091, "0209", 0, 1, 4}, // D40
NikonArrayIdx{0x0091, "0210", 5291, 2, 4}, // D300 {0x0091, "0210", 5291, 2, 4}, // D300
NikonArrayIdx{0x0091, "0210", 5303, 3, 4}, // D300, firmware version 1.10 {0x0091, "0210", 5303, 3, 4}, // D300, firmware version 1.10
NikonArrayIdx{0x0091, "02", 0, 4, 4}, // Other v2.* (encrypted) {0x0091, "02", 0, 4, 4}, // Other v2.* (encrypted)
NikonArrayIdx{0x0091, "01", 0, 5, NA}, // Other v1.* (not encrypted) {0x0091, "01", 0, 5, NA}, // Other v1.* (not encrypted)
// NikonCb // NikonCb
NikonArrayIdx{0x0097, "0100", 0, 0, NA}, NikonArrayIdx{0x0097, "0102", 0, 1, NA}, {0x0097, "0100", 0, 0, NA},
NikonArrayIdx{0x0097, "0103", 0, 4, NA}, NikonArrayIdx{0x0097, "0205", 0, 2, 4}, {0x0097, "0102", 0, 1, NA},
NikonArrayIdx{0x0097, "0209", 0, 5, 284}, NikonArrayIdx{0x0097, "0212", 0, 5, 284}, {0x0097, "0103", 0, 4, NA},
NikonArrayIdx{0x0097, "0214", 0, 5, 284}, NikonArrayIdx{0x0097, "02", 0, 3, 284}, {0x0097, "0205", 0, 2, 4},
{0x0097, "0209", 0, 5, 284},
{0x0097, "0212", 0, 5, 284},
{0x0097, "0214", 0, 5, 284},
{0x0097, "02", 0, 3, 284},
// NikonLd // NikonLd
NikonArrayIdx{0x0098, "0100", 0, 0, NA}, NikonArrayIdx{0x0098, "0101", 0, 1, NA}, {0x0098, "0100", 0, 0, NA},
NikonArrayIdx{0x0098, "0201", 0, 1, 4}, NikonArrayIdx{0x0098, "0202", 0, 1, 4}, {0x0098, "0101", 0, 1, NA},
NikonArrayIdx{0x0098, "0203", 0, 1, 4}, NikonArrayIdx{0x0098, "0204", 0, 2, 4}, {0x0098, "0201", 0, 1, 4},
NikonArrayIdx{0x0098, "0800", 0, 3, 4}, // for e.g. Z6/7 {0x0098, "0202", 0, 1, 4},
NikonArrayIdx{0x0098, "0801", 0, 3, 4}, // for e.g. Z6/7 {0x0098, "0203", 0, 1, 4},
NikonArrayIdx{0x0098, "0802", 0, 3, 4}, // for e.g. Z9 {0x0098, "0204", 0, 2, 4},
{0x0098, "0800", 0, 3, 4}, // for e.g. Z6/7
{0x0098, "0801", 0, 3, 4}, // for e.g. Z6/7
{0x0098, "0802", 0, 3, 4}, // for e.g. Z9
// NikonFl // NikonFl
NikonArrayIdx{0x00a8, "0100", 0, 0, NA}, NikonArrayIdx{0x00a8, "0101", 0, 0, NA}, {0x00a8, "0100", 0, 0, NA},
NikonArrayIdx{0x00a8, "0102", 0, 1, NA}, NikonArrayIdx{0x00a8, "0103", 0, 2, NA}, {0x00a8, "0101", 0, 0, NA},
NikonArrayIdx{0x00a8, "0104", 0, 2, NA}, NikonArrayIdx{0x00a8, "0105", 0, 2, NA}, {0x00a8, "0102", 0, 1, NA},
NikonArrayIdx{0x00a8, "0106", 0, 3, NA}, NikonArrayIdx{0x00a8, "0107", 0, 4, NA}, {0x00a8, "0103", 0, 2, NA},
NikonArrayIdx{0x00a8, "0108", 0, 4, NA}, {0x00a8, "0104", 0, 2, NA},
{0x00a8, "0105", 0, 2, NA},
{0x00a8, "0106", 0, 3, NA},
{0x00a8, "0107", 0, 4, NA},
{0x00a8, "0108", 0, 4, NA},
// NikonAf // NikonAf
NikonArrayIdx{0x00b7, "0100", 30, 0, NA}, // These sizes have been found in tiff headers of MN {0x00b7, "0100", 30, 0, NA}, // These sizes have been found in tiff headers of MN
NikonArrayIdx{0x00b7, "0101", 84, 1, NA}, // tag 0xb7 in sample image metadata for each version {0x00b7, "0101", 84, 1, NA}, // tag 0xb7 in sample image metadata for each version
}; };
int nikonSelector(uint16_t tag, const byte* pData, size_t size, TiffComponent* /*pRoot*/) { int nikonSelector(uint16_t tag, const byte* pData, size_t size, TiffComponent* /*pRoot*/) {
@ -895,8 +911,8 @@ int nikonSelector(uint16_t tag, const byte* pData, size_t size, TiffComponent* /
return -1; return -1;
auto ix = NikonArrayIdx::Key(tag, reinterpret_cast<const char*>(pData), size); auto ix = NikonArrayIdx::Key(tag, reinterpret_cast<const char*>(pData), size);
auto it = std::find(nikonArrayIdx.begin(), nikonArrayIdx.end(), ix); auto it = Exiv2::find(nikonArrayIdx, ix);
if (it == nikonArrayIdx.end()) if (!it)
return -1; return -1;
return it->idx_; return it->idx_;
@ -907,9 +923,8 @@ DataBuf nikonCrypt(uint16_t tag, const byte* pData, size_t size, TiffComponent*
if (size < 4) if (size < 4)
return buf; return buf;
auto nci = std::find(nikonArrayIdx.begin(), nikonArrayIdx.end(), auto nci = Exiv2::find(nikonArrayIdx, NikonArrayIdx::Key(tag, reinterpret_cast<const char*>(pData), size));
NikonArrayIdx::Key(tag, reinterpret_cast<const char*>(pData), size)); if (!nci || nci->start_ == NA || size <= nci->start_)
if (nci == nikonArrayIdx.end() || nci->start_ == NA || size <= nci->start_)
return buf; return buf;
// Find Exif.Nikon3.ShutterCount // Find Exif.Nikon3.ShutterCount
@ -955,12 +970,12 @@ int sonyCsSelector(uint16_t /*tag*/, const byte* /*pData*/, size_t /*size*/, Tif
return idx; return idx;
} }
int sony2010eSelector(uint16_t /*tag*/, const byte* /*pData*/, size_t /*size*/, TiffComponent* pRoot) { int sony2010eSelector(uint16_t /*tag*/, const byte* /*pData*/, size_t /*size*/, TiffComponent* pRoot) {
static constexpr auto models = std::array{ static constexpr const char* models[] = {
"SLT-A58", "SLT-A99", "ILCE-3000", "ILCE-3500", "NEX-3N", "NEX-5R", "NEX-5T", "SLT-A58", "SLT-A99", "ILCE-3000", "ILCE-3500", "NEX-3N", "NEX-5R", "NEX-5T",
"NEX-6", "VG30E", "VG900", "DSC-RX100", "DSC-RX1", "DSC-RX1R", "DSC-HX300", "NEX-6", "VG30E", "VG900", "DSC-RX100", "DSC-RX1", "DSC-RX1R", "DSC-HX300",
"DSC-HX50V", "DSC-TX30", "DSC-WX60", "DSC-WX200", "DSC-WX300", "DSC-HX50V", "DSC-TX30", "DSC-WX60", "DSC-WX200", "DSC-WX300",
}; };
return std::find(models.begin(), models.end(), getExifModel(pRoot)) != models.end() ? 0 : -1; return Exiv2::find(models, getExifModel(pRoot)) ? 0 : -1;
} }
int sony2FpSelector(uint16_t /*tag*/, const byte* /*pData*/, size_t /*size*/, TiffComponent* pRoot) { int sony2FpSelector(uint16_t /*tag*/, const byte* /*pData*/, size_t /*size*/, TiffComponent* pRoot) {

@ -1446,19 +1446,19 @@ static long getKeyLong(const std::string& key, const ExifData* metadata, int whi
/*! http://stackoverflow.com/questions/1798112/removing-leading-and-trailing-spaces-from-a-string /*! http://stackoverflow.com/questions/1798112/removing-leading-and-trailing-spaces-from-a-string
trim from left trim from left
*/ */
inline std::string& ltrim(std::string& s, const char* t = " \t\n\r\f\v") { static std::string& ltrim(std::string& s, const char* t = " \t\n\r\f\v") {
s.erase(0, s.find_first_not_of(t)); s.erase(0, s.find_first_not_of(t));
return s; return s;
} }
//! trim from right //! trim from right
inline std::string& rtrim(std::string& s, const char* t = " \t\n\r\f\v") { static std::string& rtrim(std::string& s, const char* t = " \t\n\r\f\v") {
s.erase(s.find_last_not_of(t) + 1); s.erase(s.find_last_not_of(t) + 1);
return s; return s;
} }
//! trim from left & right //! trim from left & right
inline std::string& trim(std::string& s, const char* t = " \t\n\r\f\v") { static std::string& trim(std::string& s, const char* t = " \t\n\r\f\v") {
return ltrim(rtrim(s, t), t); return ltrim(rtrim(s, t), t);
} }
@ -1483,7 +1483,7 @@ static bool inRange(long value, long min, long max) {
} }
static std::ostream& resolvedLens(std::ostream& os, long lensID, long index) { static std::ostream& resolvedLens(std::ostream& os, long lensID, long index) {
const TagDetails* td = find(minoltaSonyLensID, lensID); auto td = Exiv2::find(minoltaSonyLensID, lensID);
std::vector<std::string> tokens = split(td[0].label_, "|"); std::vector<std::string> tokens = split(td[0].label_, "|");
return os << exvGettext(trim(tokens.at(index - 1)).c_str()); return os << exvGettext(trim(tokens.at(index - 1)).c_str());
} }
@ -1606,7 +1606,7 @@ static std::ostream& resolveLens0xffff(std::ostream& os, const Value& value, con
std::string maxAperture = getKeyString("Exif.Photo.MaxApertureValue", metadata); std::string maxAperture = getKeyString("Exif.Photo.MaxApertureValue", metadata);
std::string F1_8 = "434/256"; std::string F1_8 = "434/256";
static constexpr auto maxApertures = std::array{ static constexpr const char* maxApertures[] = {
"926/256", // F3.5 "926/256", // F3.5
"1024/256", // F4 "1024/256", // F4
"1110/256", // F4.5 "1110/256", // F4.5
@ -1626,7 +1626,7 @@ static std::ostream& resolveLens0xffff(std::ostream& os, const Value& value, con
} catch (...) { } catch (...) {
} }
if (model == "ILCE-6000" && std::find(maxApertures.begin(), maxApertures.end(), maxAperture) != maxApertures.end()) if (model == "ILCE-6000" && Exiv2::find(maxApertures, maxAperture))
try { try {
long focalLength = getKeyLong("Exif.Photo.FocalLength", metadata); long focalLength = getKeyLong("Exif.Photo.FocalLength", metadata);
if (focalLength > 0) { if (focalLength > 0) {

@ -77,22 +77,22 @@ void MrwImage::readMetadata() {
uint32_t const end = getULong(tmp + 4, bigEndian); uint32_t const end = getULong(tmp + 4, bigEndian);
pos += len; pos += len;
enforce(pos <= end, ErrorCode::kerFailedToReadImageData); Internal::enforce(pos <= end, ErrorCode::kerFailedToReadImageData);
io_->read(tmp, len); io_->read(tmp, len);
if (io_->error() || io_->eof()) if (io_->error() || io_->eof())
throw Error(ErrorCode::kerFailedToReadImageData); throw Error(ErrorCode::kerFailedToReadImageData);
while (memcmp(tmp + 1, "TTW", 3) != 0) { while (memcmp(tmp + 1, "TTW", 3) != 0) {
uint32_t const siz = getULong(tmp + 4, bigEndian); uint32_t const siz = getULong(tmp + 4, bigEndian);
enforce(siz <= end - pos, ErrorCode::kerFailedToReadImageData); Internal::enforce(siz <= end - pos, ErrorCode::kerFailedToReadImageData);
pos += siz; pos += siz;
io_->seek(siz, BasicIo::cur); io_->seek(siz, BasicIo::cur);
enforce(!io_->error() && !io_->eof(), ErrorCode::kerFailedToReadImageData); Internal::enforce(!io_->error() && !io_->eof(), ErrorCode::kerFailedToReadImageData);
enforce(len <= end - pos, ErrorCode::kerFailedToReadImageData); Internal::enforce(len <= end - pos, ErrorCode::kerFailedToReadImageData);
pos += len; pos += len;
io_->read(tmp, len); io_->read(tmp, len);
enforce(!io_->error() && !io_->eof(), ErrorCode::kerFailedToReadImageData); Internal::enforce(!io_->error() && !io_->eof(), ErrorCode::kerFailedToReadImageData);
} }
const uint32_t siz = getULong(tmp + 4, bigEndian); const uint32_t siz = getULong(tmp + 4, bigEndian);
@ -101,10 +101,10 @@ void MrwImage::readMetadata() {
// greater than io_->size() then it is definitely invalid. But the // greater than io_->size() then it is definitely invalid. But the
// exact bounds checking is done by the call to io_->read, which // exact bounds checking is done by the call to io_->read, which
// will fail if there are fewer than siz bytes left to read. // will fail if there are fewer than siz bytes left to read.
enforce(siz <= io_->size(), ErrorCode::kerFailedToReadImageData); Internal::enforce(siz <= io_->size(), ErrorCode::kerFailedToReadImageData);
DataBuf buf(siz); DataBuf buf(siz);
io_->read(buf.data(), buf.size()); io_->read(buf.data(), buf.size());
enforce(!io_->error() && !io_->eof(), ErrorCode::kerFailedToReadImageData); Internal::enforce(!io_->error() && !io_->eof(), ErrorCode::kerFailedToReadImageData);
ByteOrder bo = TiffParser::decode(exifData_, iptcData_, xmpData_, buf.c_data(), buf.size()); ByteOrder bo = TiffParser::decode(exifData_, iptcData_, xmpData_, buf.c_data(), buf.size());
setByteOrder(bo); setByteOrder(bo);

@ -3791,7 +3791,7 @@ std::ostream& Nikon3MakerNote::print0x009e(std::ostream& os, const Value& value,
if (l != 0) if (l != 0)
trim = false; trim = false;
std::string d = s.empty() ? "" : "; "; std::string d = s.empty() ? "" : "; ";
const TagDetails* td = find(nikonRetouchHistory, l); auto td = Exiv2::find(nikonRetouchHistory, l);
if (td) { if (td) {
s = std::string(exvGettext(td->label_)).append(d).append(s); s = std::string(exvGettext(td->label_)).append(d).append(s);
} else { } else {

@ -1243,7 +1243,7 @@ std::ostream& OlympusMakerNote::print0x0201(std::ostream& os, const Value& value
// 6 numbers: 0. Make, 1. Unknown, 2. Model, 3. Sub-model, 4-5. Unknown. // 6 numbers: 0. Make, 1. Unknown, 2. Model, 3. Sub-model, 4-5. Unknown.
// Only the Make, Model and Sub-model are used to determine the lens model // Only the Make, Model and Sub-model are used to determine the lens model
static struct { static const struct {
byte val[3]; byte val[3];
const char* label; const char* label;
} lensTypes[] = { } lensTypes[] = {
@ -1397,7 +1397,7 @@ std::ostream& OlympusMakerNote::print0x0209(std::ostream& os, const Value& value
std::ostream& OlympusMakerNote::printEq0x0301(std::ostream& os, const Value& value, const ExifData*) { std::ostream& OlympusMakerNote::printEq0x0301(std::ostream& os, const Value& value, const ExifData*) {
// 6 numbers: 0. Make, 1. Unknown, 2. Model, 3. Sub-model, 4-5. Unknown. // 6 numbers: 0. Make, 1. Unknown, 2. Model, 3. Sub-model, 4-5. Unknown.
// Only the Make and Model are used to determine the extender model // Only the Make and Model are used to determine the extender model
static struct { static const struct {
byte val[2]; byte val[2];
const char* label; const char* label;
} extenderModels[] = { } extenderModels[] = {

@ -1096,7 +1096,7 @@ std::ostream& resolveLens0x32c(std::ostream& os, const Value& value, const ExifD
if (index > 0) { if (index > 0) {
const unsigned long lensID = 0x32c; const unsigned long lensID = 0x32c;
const TagDetails* td = find(pentaxLensType, lensID); auto td = Exiv2::find(pentaxLensType, lensID);
os << exvGettext(td[index].label_); os << exvGettext(td[index].label_);
return os; return os;
} }
@ -1160,7 +1160,7 @@ std::ostream& resolveLens0x3ff(std::ostream& os, const Value& value, const ExifD
if (index > 0) { if (index > 0) {
const unsigned long lensID = 0x3ff; const unsigned long lensID = 0x3ff;
const TagDetails* td = find(pentaxLensType, lensID); auto td = Exiv2::find(pentaxLensType, lensID);
os << exvGettext(td[index].label_); os << exvGettext(td[index].label_);
return os; return os;
} }
@ -1187,7 +1187,7 @@ std::ostream& resolveLens0x8ff(std::ostream& os, const Value& value, const ExifD
if (index > 0) { if (index > 0) {
const unsigned long lensID = 0x8ff; const unsigned long lensID = 0x8ff;
const TagDetails* td = find(pentaxLensType, lensID); auto td = Exiv2::find(pentaxLensType, lensID);
os << exvGettext(td[index].label_); os << exvGettext(td[index].label_);
return os; return os;
} }
@ -1221,7 +1221,7 @@ std::ostream& resolveLens0x319(std::ostream& os, const Value& value, const ExifD
if (index > 0) { if (index > 0) {
const unsigned long lensID = 0x319; const unsigned long lensID = 0x319;
const TagDetails* td = find(pentaxLensType, lensID); auto td = Exiv2::find(pentaxLensType, lensID);
os << exvGettext(td[index].label_); os << exvGettext(td[index].label_);
return os; return os;
} }
@ -1245,12 +1245,11 @@ struct LensIdFct {
}; };
//! List of lens ids which require special treatment using resolveLensType //! List of lens ids which require special treatment using resolveLensType
constexpr auto lensIdFct = std::array{ constexpr LensIdFct lensIdFct[] = {
LensIdFct{0x0317, resolveLensType}, LensIdFct{0x0319, resolveLens0x319}, LensIdFct{0x031b, resolveLensType}, {0x0317, resolveLensType}, {0x0319, resolveLens0x319}, {0x031b, resolveLensType}, {0x031c, resolveLensType},
LensIdFct{0x031c, resolveLensType}, LensIdFct{0x031d, resolveLensType}, LensIdFct{0x031f, resolveLensType}, {0x031d, resolveLensType}, {0x031f, resolveLensType}, {0x0329, resolveLensType}, {0x032c, resolveLens0x32c},
LensIdFct{0x0329, resolveLensType}, LensIdFct{0x032c, resolveLens0x32c}, LensIdFct{0x032e, resolveLensType}, {0x032e, resolveLensType}, {0x0334, resolveLensType}, {0x03ff, resolveLens0x3ff}, {0x041a, resolveLensType},
LensIdFct{0x0334, resolveLensType}, LensIdFct{0x03ff, resolveLens0x3ff}, LensIdFct{0x041a, resolveLensType}, {0x042d, resolveLensType}, {0x08ff, resolveLens0x8ff},
LensIdFct{0x042d, resolveLensType}, LensIdFct{0x08ff, resolveLens0x8ff},
}; };
//! A lens id and a pretty-print function for special treatment of the id. //! A lens id and a pretty-print function for special treatment of the id.
@ -1265,8 +1264,8 @@ std::ostream& printLensType(std::ostream& os, const Value& value, const ExifData
const auto index = value.toUint32(0) * 256 + value.toUint32(1); const auto index = value.toUint32(0) * 256 + value.toUint32(1);
// std::cout << std::endl << "printLensType value =" << value.toLong() << " index = " << index << std::endl; // std::cout << std::endl << "printLensType value =" << value.toLong() << " index = " << index << std::endl;
auto lif = std::find(lensIdFct.begin(), lensIdFct.end(), index); auto lif = Exiv2::find(lensIdFct, index);
if (lif == lensIdFct.end()) if (!lif)
return EXV_PRINT_COMBITAG_MULTI(pentaxLensType, 2, 1, 2)(os, value, metadata); return EXV_PRINT_COMBITAG_MULTI(pentaxLensType, 2, 1, 2)(os, value, metadata);
if (metadata && lif->fct_) if (metadata && lif->fct_)
return lif->fct_(os, value, metadata); return lif->fct_(os, value, metadata);

@ -70,7 +70,7 @@ std::ostream& printCombiTag(std::ostream& os, const Value& value, const ExifData
} }
l += (value.toUint32(c) << ((count - c - 1) * 8)); l += (value.toUint32(c) << ((count - c - 1) * 8));
} }
const TagDetails* td = find(array, l); auto td = Exiv2::find(array, l);
if (td) { if (td) {
os << exvGettext(td->label_); os << exvGettext(td->label_);
} else { } else {

@ -87,7 +87,7 @@ void PgfImage::readMetadata() {
// And now, the most interesting, the user data byte array where metadata are stored as small image. // And now, the most interesting, the user data byte array where metadata are stored as small image.
enforce(headerSize <= std::numeric_limits<size_t>::max() - 8, ErrorCode::kerCorruptedMetadata); Internal::enforce(headerSize <= std::numeric_limits<size_t>::max() - 8, ErrorCode::kerCorruptedMetadata);
size_t size = headerSize + 8 - io_->tell(); size_t size = headerSize + 8 - io_->tell();
#ifdef EXIV2_DEBUG_MESSAGES #ifdef EXIV2_DEBUG_MESSAGES

@ -154,7 +154,7 @@ DataBuf Photoshop::setIptcIrb(const byte* pPsData, size_t sizePsData, const Iptc
// Write existing stuff after record, skip the current and all remaining IPTC blocks // Write existing stuff after record, skip the current and all remaining IPTC blocks
size_t pos = sizeFront; size_t pos = sizeFront;
auto nextSizeData = Safe::add<long>(static_cast<long>(sizePsData), -static_cast<long>(pos)); auto nextSizeData = Safe::add<long>(static_cast<long>(sizePsData), -static_cast<long>(pos));
enforce(nextSizeData >= 0, ErrorCode::kerCorruptedMetadata); Internal::enforce(nextSizeData >= 0, ErrorCode::kerCorruptedMetadata);
while (0 == Photoshop::locateIptcIrb(pPsData + pos, nextSizeData, &record, sizeHdr, sizeIptc)) { while (0 == Photoshop::locateIptcIrb(pPsData + pos, nextSizeData, &record, sizeHdr, sizeIptc)) {
const auto newPos = static_cast<size_t>(record - pPsData); const auto newPos = static_cast<size_t>(record - pPsData);
if (newPos > pos) { // Copy data up to the IPTC IRB if (newPos > pos) { // Copy data up to the IPTC IRB
@ -162,7 +162,7 @@ DataBuf Photoshop::setIptcIrb(const byte* pPsData, size_t sizePsData, const Iptc
} }
pos = newPos + sizeHdr + sizeIptc + (sizeIptc & 1); // Skip the IPTC IRB pos = newPos + sizeHdr + sizeIptc + (sizeIptc & 1); // Skip the IPTC IRB
nextSizeData = Safe::add<long>(static_cast<long>(sizePsData), -static_cast<long>(pos)); nextSizeData = Safe::add<long>(static_cast<long>(sizePsData), -static_cast<long>(pos));
enforce(nextSizeData >= 0, ErrorCode::kerCorruptedMetadata); Internal::enforce(nextSizeData >= 0, ErrorCode::kerCorruptedMetadata);
} }
if (pos < sizePsData) { if (pos < sizePsData) {
append(psBlob, pPsData + pos, sizePsData - pos); append(psBlob, pPsData + pos, sizePsData - pos);

@ -41,7 +41,7 @@ constexpr unsigned char pngBlank[] = {
const auto nullComp = reinterpret_cast<const Exiv2::byte*>("\0\0"); const auto nullComp = reinterpret_cast<const Exiv2::byte*>("\0\0");
const auto typeExif = reinterpret_cast<const Exiv2::byte*>("eXIf"); const auto typeExif = reinterpret_cast<const Exiv2::byte*>("eXIf");
const auto typeICCP = reinterpret_cast<const Exiv2::byte*>("iCCP"); const auto typeICCP = reinterpret_cast<const Exiv2::byte*>("iCCP");
inline bool compare(std::string_view str, const Exiv2::DataBuf& buf) { bool compare(std::string_view str, const Exiv2::DataBuf& buf) {
const auto minlen = std::min(str.size(), buf.size()); const auto minlen = std::min(str.size(), buf.size());
return buf.cmpBytes(0, str.data(), minlen) == 0; return buf.cmpBytes(0, str.data(), minlen) == 0;
} }
@ -247,7 +247,7 @@ void PngImage::printStructure(std::ostream& out, PrintStructureOption option, si
} }
while (dataString.size() < iMax) while (dataString.size() < iMax)
dataString += ' '; dataString += ' ';
dataString = dataString.substr(0, iMax); dataString.resize(iMax);
if (bPrint) { if (bPrint) {
io_->seek(dataOffset, BasicIo::cur); // jump to checksum io_->seek(dataOffset, BasicIo::cur); // jump to checksum

@ -731,7 +731,7 @@ DataBuf LoaderTiff::getData() const {
dataValue.setDataArea(base + offset, size); dataValue.setDataArea(base + offset, size);
} else { } else {
// FIXME: the buffer is probably copied twice, it should be optimized // FIXME: the buffer is probably copied twice, it should be optimized
enforce(size_ <= io.size(), ErrorCode::kerCorruptedMetadata); Internal::enforce(size_ <= io.size(), ErrorCode::kerCorruptedMetadata);
DataBuf buf(size_); DataBuf buf(size_);
uint32_t idxBuf = 0; uint32_t idxBuf = 0;
for (size_t i = 0; i < sizes.count(); i++) { for (size_t i = 0; i < sizes.count(); i++) {
@ -742,7 +742,7 @@ DataBuf LoaderTiff::getData() const {
// see the constructor of LoaderTiff // see the constructor of LoaderTiff
// But e.g in malicious files some of these values could be negative // But e.g in malicious files some of these values could be negative
// That's why we check again for each step here to really make sure we don't overstep // That's why we check again for each step here to really make sure we don't overstep
enforce(Safe::add(idxBuf, size) <= size_, ErrorCode::kerCorruptedMetadata); Internal::enforce(Safe::add(idxBuf, size) <= size_, ErrorCode::kerCorruptedMetadata);
if (size != 0 && Safe::add(offset, size) <= static_cast<uint32_t>(io.size())) { if (size != 0 && Safe::add(offset, size) <= static_cast<uint32_t>(io.size())) {
std::copy_n(base + offset, size, buf.begin() + idxBuf); std::copy_n(base + offset, size, buf.begin() + idxBuf);
} }

@ -4942,8 +4942,8 @@ const XmpNsInfo* XmpProperties::lookupNsRegistryUnsafe(const XmpNsInfo::Prefix&
void XmpProperties::registerNs(const std::string& ns, const std::string& prefix) { void XmpProperties::registerNs(const std::string& ns, const std::string& prefix) {
auto scopedWriteLock = std::scoped_lock(mutex_); auto scopedWriteLock = std::scoped_lock(mutex_);
std::string ns2 = ns; std::string ns2 = ns;
if (ns2.substr(ns2.size() - 1, 1) != "/" && ns2.substr(ns2.size() - 1, 1) != "#") if (ns2.back() != '/' && ns2.back() != '#')
ns2 += "/"; ns2 += '/';
// Check if there is already a registered namespace with this prefix // Check if there is already a registered namespace with this prefix
const XmpNsInfo* xnp = lookupNsRegistryUnsafe(XmpNsInfo::Prefix(prefix)); const XmpNsInfo* xnp = lookupNsRegistryUnsafe(XmpNsInfo::Prefix(prefix));
if (xnp) { if (xnp) {
@ -4995,15 +4995,15 @@ void XmpProperties::unregisterNs() {
std::string XmpProperties::prefix(const std::string& ns) { std::string XmpProperties::prefix(const std::string& ns) {
auto scoped_read_lock = std::scoped_lock(mutex_); auto scoped_read_lock = std::scoped_lock(mutex_);
std::string ns2 = ns; std::string ns2 = ns;
if (ns2.substr(ns2.size() - 1, 1) != "/" && ns2.substr(ns2.size() - 1, 1) != "#") if (ns2.back() != '/' && ns2.back() != '#')
ns2 += "/"; ns2 += '/';
auto i = nsRegistry_.find(ns2); auto i = nsRegistry_.find(ns2);
std::string p; std::string p;
if (i != nsRegistry_.end()) { if (i != nsRegistry_.end()) {
p = i->second.prefix_; p = i->second.prefix_;
} else { } else {
const XmpNsInfo* xn = find(xmpNsInfo, XmpNsInfo::Ns(ns2)); auto xn = Exiv2::find(xmpNsInfo, XmpNsInfo::Ns(ns2));
if (xn) if (xn)
p = std::string(xn->prefix_); p = std::string(xn->prefix_);
} }
@ -5082,7 +5082,7 @@ const XmpNsInfo* XmpProperties::nsInfoUnsafe(const std::string& prefix) {
const XmpNsInfo::Prefix pf(prefix); const XmpNsInfo::Prefix pf(prefix);
const XmpNsInfo* xn = lookupNsRegistryUnsafe(pf); const XmpNsInfo* xn = lookupNsRegistryUnsafe(pf);
if (!xn) if (!xn)
xn = find(xmpNsInfo, pf); xn = Exiv2::find(xmpNsInfo, pf);
if (!xn) if (!xn)
throw Error(ErrorCode::kerNoNamespaceInfoForXmpPrefix, prefix); throw Error(ErrorCode::kerNoNamespaceInfoForXmpPrefix, prefix);
return xn; return xn;
@ -5108,7 +5108,7 @@ void XmpProperties::printProperties(std::ostream& os, const std::string& prefix)
std::ostream& XmpProperties::printProperty(std::ostream& os, const std::string& key, const Value& value) { std::ostream& XmpProperties::printProperty(std::ostream& os, const std::string& key, const Value& value) {
PrintFct fct = printValue; PrintFct fct = printValue;
if (value.count() != 0) { if (value.count() != 0) {
const XmpPrintInfo* info = find(xmpPrintInfo, key); auto info = Exiv2::find(xmpPrintInfo, key);
if (info) if (info)
fct = info->printFct_; fct = info->printFct_;
} }

@ -167,10 +167,10 @@ void PsdImage::readMetadata() {
throw Error(ErrorCode::kerNotAnImage, "Photoshop"); throw Error(ErrorCode::kerNotAnImage, "Photoshop");
} }
uint32_t resourcesLength = getULong(buf, bigEndian); uint32_t resourcesLength = getULong(buf, bigEndian);
enforce(resourcesLength < io_->size(), Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(resourcesLength < io_->size(), Exiv2::ErrorCode::kerCorruptedMetadata);
while (resourcesLength > 0) { while (resourcesLength > 0) {
enforce(resourcesLength >= 8, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(resourcesLength >= 8, Exiv2::ErrorCode::kerCorruptedMetadata);
resourcesLength -= 8; resourcesLength -= 8;
if (io_->read(buf, 8) != 8) { if (io_->read(buf, 8) != 8) {
throw Error(ErrorCode::kerNotAnImage, "Photoshop"); throw Error(ErrorCode::kerNotAnImage, "Photoshop");
@ -183,12 +183,12 @@ void PsdImage::readMetadata() {
uint32_t resourceNameLength = buf[6] & ~1; uint32_t resourceNameLength = buf[6] & ~1;
// skip the resource name, plus any padding // skip the resource name, plus any padding
enforce(resourceNameLength <= resourcesLength, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(resourceNameLength <= resourcesLength, Exiv2::ErrorCode::kerCorruptedMetadata);
resourcesLength -= resourceNameLength; resourcesLength -= resourceNameLength;
io_->seek(resourceNameLength, BasicIo::cur); io_->seek(resourceNameLength, BasicIo::cur);
// read resource size // read resource size
enforce(resourcesLength >= 4, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(resourcesLength >= 4, Exiv2::ErrorCode::kerCorruptedMetadata);
resourcesLength -= 4; resourcesLength -= 4;
if (io_->read(buf, 4) != 4) { if (io_->read(buf, 4) != 4) {
throw Error(ErrorCode::kerNotAnImage, "Photoshop"); throw Error(ErrorCode::kerNotAnImage, "Photoshop");
@ -201,10 +201,10 @@ void PsdImage::readMetadata() {
<< "\n"; << "\n";
#endif #endif
enforce(resourceSize <= resourcesLength, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(resourceSize <= resourcesLength, Exiv2::ErrorCode::kerCorruptedMetadata);
readResourceBlock(resourceId, resourceSize); readResourceBlock(resourceId, resourceSize);
resourceSize = (resourceSize + 1) & ~1; // pad to even resourceSize = (resourceSize + 1) & ~1; // pad to even
enforce(resourceSize <= resourcesLength, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(resourceSize <= resourcesLength, Exiv2::ErrorCode::kerCorruptedMetadata);
resourcesLength -= resourceSize; resourcesLength -= resourceSize;
io_->seek(curOffset + resourceSize, BasicIo::beg); io_->seek(curOffset + resourceSize, BasicIo::beg);
} }

@ -775,7 +775,7 @@ void QuickTimeVideo::CameraTagsDecoder(size_t size_external) {
buf.read_uint32(0, littleEndian) / static_cast<double>(buf2.read_uint32(0, littleEndian)); buf.read_uint32(0, littleEndian) / static_cast<double>(buf2.read_uint32(0, littleEndian));
io_->readOrThrow(buf.data(), 10); io_->readOrThrow(buf.data(), 10);
io_->readOrThrow(buf.data(), 4); io_->readOrThrow(buf.data(), 4);
td = find(whiteBalance, buf.read_uint32(0, littleEndian)); td = Exiv2::find(whiteBalance, buf.read_uint32(0, littleEndian));
if (td) if (td)
xmpData_["Xmp.video.WhiteBalance"] = exvGettext(td->label_); xmpData_["Xmp.video.WhiteBalance"] = exvGettext(td->label_);
io_->readOrThrow(buf.data(), 4); io_->readOrThrow(buf.data(), 4);
@ -814,9 +814,9 @@ void QuickTimeVideo::userDataDecoder(size_t size_external) {
if (buf.data()[0] == 169) if (buf.data()[0] == 169)
buf.data()[0] = ' '; buf.data()[0] = ' ';
td = find(userDatatags, Exiv2::toString(buf.data())); td = Exiv2::find(userDatatags, Exiv2::toString(buf.data()));
tv = find(userDataReferencetags, Exiv2::toString(buf.data())); tv = Exiv2::find(userDataReferencetags, Exiv2::toString(buf.data()));
if (size <= 12) if (size <= 12)
break; break;
@ -840,7 +840,7 @@ void QuickTimeVideo::userDataDecoder(size_t size_external) {
enforce(tv, Exiv2::ErrorCode::kerCorruptedMetadata); enforce(tv, Exiv2::ErrorCode::kerCorruptedMetadata);
io_->readOrThrow(buf.data(), 2); io_->readOrThrow(buf.data(), 2);
buf.data()[2] = '\0'; buf.data()[2] = '\0';
tv_internal = find(cameraByteOrderTags, Exiv2::toString(buf.data())); tv_internal = Exiv2::find(cameraByteOrderTags, Exiv2::toString(buf.data()));
if (tv_internal) if (tv_internal)
xmpData_[exvGettext(tv->label_)] = exvGettext(tv_internal->label_); xmpData_[exvGettext(tv->label_)] = exvGettext(tv_internal->label_);
@ -870,7 +870,7 @@ void QuickTimeVideo::NikonTagsDecoder(size_t size_external) {
for (int i = 0; i < 100; i++) { for (int i = 0; i < 100; i++) {
io_->readOrThrow(buf.data(), 4); io_->readOrThrow(buf.data(), 4);
TagID = buf.read_uint32(0, bigEndian); TagID = buf.read_uint32(0, bigEndian);
td = find(NikonNCTGTags, TagID); td = Exiv2::find(NikonNCTGTags, TagID);
io_->readOrThrow(buf.data(), 2); io_->readOrThrow(buf.data(), 2);
dataType = buf.read_uint16(0, bigEndian); dataType = buf.read_uint16(0, bigEndian);
@ -893,40 +893,40 @@ void QuickTimeVideo::NikonTagsDecoder(size_t size_external) {
std::memset(buf.data(), 0x0, buf.size()); std::memset(buf.data(), 0x0, buf.size());
io_->readOrThrow(buf.data(), 1); io_->readOrThrow(buf.data(), 1);
td2 = find(PictureControlAdjust, static_cast<int>(buf.data()[0]) & 7); td2 = Exiv2::find(PictureControlAdjust, static_cast<int>(buf.data()[0]) & 7);
if (td2) if (td2)
xmpData_["Xmp.video.PictureControlAdjust"] = exvGettext(td2->label_); xmpData_["Xmp.video.PictureControlAdjust"] = exvGettext(td2->label_);
else else
xmpData_["Xmp.video.PictureControlAdjust"] = static_cast<int>(buf.data()[0]) & 7; xmpData_["Xmp.video.PictureControlAdjust"] = static_cast<int>(buf.data()[0]) & 7;
io_->readOrThrow(buf.data(), 1); io_->readOrThrow(buf.data(), 1);
td2 = find(NormalSoftHard, static_cast<int>(buf.data()[0]) & 7); td2 = Exiv2::find(NormalSoftHard, static_cast<int>(buf.data()[0]) & 7);
if (td2) if (td2)
xmpData_["Xmp.video.PictureControlQuickAdjust"] = exvGettext(td2->label_); xmpData_["Xmp.video.PictureControlQuickAdjust"] = exvGettext(td2->label_);
io_->readOrThrow(buf.data(), 1); io_->readOrThrow(buf.data(), 1);
td2 = find(NormalSoftHard, static_cast<int>(buf.data()[0]) & 7); td2 = Exiv2::find(NormalSoftHard, static_cast<int>(buf.data()[0]) & 7);
if (td2) if (td2)
xmpData_["Xmp.video.Sharpness"] = exvGettext(td2->label_); xmpData_["Xmp.video.Sharpness"] = exvGettext(td2->label_);
else else
xmpData_["Xmp.video.Sharpness"] = static_cast<int>(buf.data()[0]) & 7; xmpData_["Xmp.video.Sharpness"] = static_cast<int>(buf.data()[0]) & 7;
io_->readOrThrow(buf.data(), 1); io_->readOrThrow(buf.data(), 1);
td2 = find(NormalSoftHard, static_cast<int>(buf.data()[0]) & 7); td2 = Exiv2::find(NormalSoftHard, static_cast<int>(buf.data()[0]) & 7);
if (td2) if (td2)
xmpData_["Xmp.video.Contrast"] = exvGettext(td2->label_); xmpData_["Xmp.video.Contrast"] = exvGettext(td2->label_);
else else
xmpData_["Xmp.video.Contrast"] = static_cast<int>(buf.data()[0]) & 7; xmpData_["Xmp.video.Contrast"] = static_cast<int>(buf.data()[0]) & 7;
io_->readOrThrow(buf.data(), 1); io_->readOrThrow(buf.data(), 1);
td2 = find(NormalSoftHard, static_cast<int>(buf.data()[0]) & 7); td2 = Exiv2::find(NormalSoftHard, static_cast<int>(buf.data()[0]) & 7);
if (td2) if (td2)
xmpData_["Xmp.video.Brightness"] = exvGettext(td2->label_); xmpData_["Xmp.video.Brightness"] = exvGettext(td2->label_);
else else
xmpData_["Xmp.video.Brightness"] = static_cast<int>(buf.data()[0]) & 7; xmpData_["Xmp.video.Brightness"] = static_cast<int>(buf.data()[0]) & 7;
io_->readOrThrow(buf.data(), 1); io_->readOrThrow(buf.data(), 1);
td2 = find(Saturation, static_cast<int>(buf.data()[0]) & 7); td2 = Exiv2::find(Saturation, static_cast<int>(buf.data()[0]) & 7);
if (td2) if (td2)
xmpData_["Xmp.video.Saturation"] = exvGettext(td2->label_); xmpData_["Xmp.video.Saturation"] = exvGettext(td2->label_);
else else
@ -936,14 +936,14 @@ void QuickTimeVideo::NikonTagsDecoder(size_t size_external) {
xmpData_["Xmp.video.HueAdjustment"] = static_cast<int>(buf.data()[0]) & 7; xmpData_["Xmp.video.HueAdjustment"] = static_cast<int>(buf.data()[0]) & 7;
io_->readOrThrow(buf.data(), 1); io_->readOrThrow(buf.data(), 1);
td2 = find(FilterEffect, static_cast<int>(buf.data()[0])); td2 = Exiv2::find(FilterEffect, static_cast<int>(buf.data()[0]));
if (td2) if (td2)
xmpData_["Xmp.video.FilterEffect"] = exvGettext(td2->label_); xmpData_["Xmp.video.FilterEffect"] = exvGettext(td2->label_);
else else
xmpData_["Xmp.video.FilterEffect"] = static_cast<int>(buf.data()[0]); xmpData_["Xmp.video.FilterEffect"] = static_cast<int>(buf.data()[0]);
io_->readOrThrow(buf.data(), 1); io_->readOrThrow(buf.data(), 1);
td2 = find(ToningEffect, static_cast<int>(buf.data()[0])); td2 = Exiv2::find(ToningEffect, static_cast<int>(buf.data()[0]));
if (td2) if (td2)
xmpData_["Xmp.video.ToningEffect"] = exvGettext(td2->label_); xmpData_["Xmp.video.ToningEffect"] = exvGettext(td2->label_);
else else
@ -963,12 +963,12 @@ void QuickTimeVideo::NikonTagsDecoder(size_t size_external) {
io_->readOrThrow(buf.data(), 2); io_->readOrThrow(buf.data(), 2);
xmpData_["Xmp.video.TimeZone"] = Exiv2::getShort(buf.data(), bigEndian); xmpData_["Xmp.video.TimeZone"] = Exiv2::getShort(buf.data(), bigEndian);
io_->readOrThrow(buf.data(), 1); io_->readOrThrow(buf.data(), 1);
td2 = find(YesNo, static_cast<int>(buf.data()[0])); td2 = Exiv2::find(YesNo, static_cast<int>(buf.data()[0]));
if (td2) if (td2)
xmpData_["Xmp.video.DayLightSavings"] = exvGettext(td2->label_); xmpData_["Xmp.video.DayLightSavings"] = exvGettext(td2->label_);
io_->readOrThrow(buf.data(), 1); io_->readOrThrow(buf.data(), 1);
td2 = find(DateDisplayFormat, static_cast<int>(buf.data()[0])); td2 = Exiv2::find(DateDisplayFormat, static_cast<int>(buf.data()[0]));
if (td2) if (td2)
xmpData_["Xmp.video.DateDisplayFormat"] = exvGettext(td2->label_); xmpData_["Xmp.video.DateDisplayFormat"] = exvGettext(td2->label_);
@ -1143,14 +1143,14 @@ void QuickTimeVideo::audioDescDecoder() {
io_->readOrThrow(buf.data(), 4); io_->readOrThrow(buf.data(), 4);
switch (i) { switch (i) {
case AudioFormat: case AudioFormat:
td = find(qTimeFileType, Exiv2::toString(buf.data())); td = Exiv2::find(qTimeFileType, Exiv2::toString(buf.data()));
if (td) if (td)
xmpData_["Xmp.audio.Compressor"] = exvGettext(td->label_); xmpData_["Xmp.audio.Compressor"] = exvGettext(td->label_);
else else
xmpData_["Xmp.audio.Compressor"] = Exiv2::toString(buf.data()); xmpData_["Xmp.audio.Compressor"] = Exiv2::toString(buf.data());
break; break;
case AudioVendorID: case AudioVendorID:
td = find(vendorIDTags, Exiv2::toString(buf.data())); td = Exiv2::find(vendorIDTags, Exiv2::toString(buf.data()));
if (td) if (td)
xmpData_["Xmp.audio.VendorID"] = exvGettext(td->label_); xmpData_["Xmp.audio.VendorID"] = exvGettext(td->label_);
break; break;
@ -1183,14 +1183,14 @@ void QuickTimeVideo::imageDescDecoder() {
switch (i) { switch (i) {
case codec: case codec:
td = find(qTimeFileType, Exiv2::toString(buf.data())); td = Exiv2::find(qTimeFileType, Exiv2::toString(buf.data()));
if (td) if (td)
xmpData_["Xmp.video.Codec"] = exvGettext(td->label_); xmpData_["Xmp.video.Codec"] = exvGettext(td->label_);
else else
xmpData_["Xmp.video.Codec"] = Exiv2::toString(buf.data()); xmpData_["Xmp.video.Codec"] = Exiv2::toString(buf.data());
break; break;
case VendorID: case VendorID:
td = find(vendorIDTags, Exiv2::toString(buf.data())); td = Exiv2::find(vendorIDTags, Exiv2::toString(buf.data()));
if (td) if (td)
xmpData_["Xmp.video.VendorID"] = exvGettext(td->label_); xmpData_["Xmp.video.VendorID"] = exvGettext(td->label_);
break; break;
@ -1247,7 +1247,7 @@ void QuickTimeVideo::videoHeaderDecoder(size_t size) {
switch (i) { switch (i) {
case GraphicsMode: case GraphicsMode:
td = find(graphicsModetags, buf.read_uint16(0, bigEndian)); td = Exiv2::find(graphicsModetags, buf.read_uint16(0, bigEndian));
if (td) if (td)
xmpData_["Xmp.video.GraphicsMode"] = exvGettext(td->label_); xmpData_["Xmp.video.GraphicsMode"] = exvGettext(td->label_);
break; break;
@ -1274,7 +1274,7 @@ void QuickTimeVideo::handlerDecoder(size_t size) {
switch (i) { switch (i) {
case HandlerClass: case HandlerClass:
tv = find(handlerClassTags, Exiv2::toString(buf.data())); tv = Exiv2::find(handlerClassTags, Exiv2::toString(buf.data()));
if (tv) { if (tv) {
if (currentStream_ == Video) if (currentStream_ == Video)
xmpData_["Xmp.video.HandlerClass"] = exvGettext(tv->label_); xmpData_["Xmp.video.HandlerClass"] = exvGettext(tv->label_);
@ -1283,7 +1283,7 @@ void QuickTimeVideo::handlerDecoder(size_t size) {
} }
break; break;
case HandlerType: case HandlerType:
tv = find(handlerTypeTags, Exiv2::toString(buf.data())); tv = Exiv2::find(handlerTypeTags, Exiv2::toString(buf.data()));
if (tv) { if (tv) {
if (currentStream_ == Video) if (currentStream_ == Video)
xmpData_["Xmp.video.HandlerType"] = exvGettext(tv->label_); xmpData_["Xmp.video.HandlerType"] = exvGettext(tv->label_);
@ -1292,7 +1292,7 @@ void QuickTimeVideo::handlerDecoder(size_t size) {
} }
break; break;
case HandlerVendorID: case HandlerVendorID:
tv = find(vendorIDTags, Exiv2::toString(buf.data())); tv = Exiv2::find(vendorIDTags, Exiv2::toString(buf.data()));
if (tv) { if (tv) {
if (currentStream_ == Video) if (currentStream_ == Video)
xmpData_["Xmp.video.HandlerVendorID"] = exvGettext(tv->label_); xmpData_["Xmp.video.HandlerVendorID"] = exvGettext(tv->label_);
@ -1314,7 +1314,7 @@ void QuickTimeVideo::fileTypeDecoder(size_t size) {
for (int i = 0; size / 4 != 0; size -= 4, i++) { for (int i = 0; size / 4 != 0; size -= 4, i++) {
io_->readOrThrow(buf.data(), 4); io_->readOrThrow(buf.data(), 4);
td = find(qTimeFileType, Exiv2::toString(buf.data())); td = Exiv2::find(qTimeFileType, Exiv2::toString(buf.data()));
switch (i) { switch (i) {
case 0: case 0:
@ -1598,7 +1598,7 @@ bool isQTimeType(BasicIo& iIo, bool advance) {
// we only match if we actually know the video type. This is done // we only match if we actually know the video type. This is done
// to avoid matching just on ftyp because bmffimage also has that // to avoid matching just on ftyp because bmffimage also has that
// header. // header.
auto td = find(qTimeFileType, std::string{buf.c_str(8), 4}); auto td = Exiv2::find(qTimeFileType, std::string{buf.c_str(8), 4});
if (td) { if (td) {
matched = true; matched = true;
} }

@ -243,17 +243,17 @@ void RafImage::readMetadata() {
uint32_t jpg_img_off_u32 = Exiv2::getULong(jpg_img_offset, bigEndian); uint32_t jpg_img_off_u32 = Exiv2::getULong(jpg_img_offset, bigEndian);
uint32_t jpg_img_len_u32 = Exiv2::getULong(jpg_img_length, bigEndian); uint32_t jpg_img_len_u32 = Exiv2::getULong(jpg_img_length, bigEndian);
enforce(Safe::add(jpg_img_off_u32, jpg_img_len_u32) <= io_->size(), ErrorCode::kerCorruptedMetadata); Internal::enforce(Safe::add(jpg_img_off_u32, jpg_img_len_u32) <= io_->size(), ErrorCode::kerCorruptedMetadata);
#if LONG_MAX < UINT_MAX #if LONG_MAX < UINT_MAX
enforce(jpg_img_off_u32 <= std::numeric_limits<uint32_t>::max(), ErrorCode::kerCorruptedMetadata); Internal::enforce(jpg_img_off_u32 <= std::numeric_limits<uint32_t>::max(), ErrorCode::kerCorruptedMetadata);
enforce(jpg_img_len_u32 <= std::numeric_limits<uint32_t>::max(), ErrorCode::kerCorruptedMetadata); Internal::enforce(jpg_img_len_u32 <= std::numeric_limits<uint32_t>::max(), ErrorCode::kerCorruptedMetadata);
#endif #endif
auto jpg_img_off = static_cast<long>(jpg_img_off_u32); auto jpg_img_off = static_cast<long>(jpg_img_off_u32);
auto jpg_img_len = static_cast<long>(jpg_img_len_u32); auto jpg_img_len = static_cast<long>(jpg_img_len_u32);
enforce(jpg_img_len >= 12, ErrorCode::kerCorruptedMetadata); Internal::enforce(jpg_img_len >= 12, ErrorCode::kerCorruptedMetadata);
DataBuf buf(jpg_img_len - 12); DataBuf buf(jpg_img_len - 12);
if (io_->seek(jpg_img_off + 12, BasicIo::beg) != 0) if (io_->seek(jpg_img_off + 12, BasicIo::beg) != 0)
@ -285,7 +285,7 @@ void RafImage::readMetadata() {
uint32_t tiffLength = Exiv2::getULong(readBuff, bigEndian); uint32_t tiffLength = Exiv2::getULong(readBuff, bigEndian);
// sanity check. Does tiff lie inside the file? // sanity check. Does tiff lie inside the file?
enforce(Safe::add(tiffOffset, tiffLength) <= io_->size(), ErrorCode::kerCorruptedMetadata); Internal::enforce(Safe::add(tiffOffset, tiffLength) <= io_->size(), ErrorCode::kerCorruptedMetadata);
if (io_->seek(tiffOffset, BasicIo::beg) != 0) if (io_->seek(tiffOffset, BasicIo::beg) != 0)
throw Error(ErrorCode::kerFailedToReadImageData); throw Error(ErrorCode::kerFailedToReadImageData);

@ -359,12 +359,6 @@ std::string RiffVideo::mimeType() const {
return "video/riff"; return "video/riff";
} }
void RiffVideo::printStructure(std::ostream& out, PrintStructureOption option, size_t depth) {
if (io_->open() != 0) {
throw Error(ErrorCode::kerDataSourceOpenFailed, io_->path(), strError());
}
} // RiffVideo::printStructure
void RiffVideo::writeMetadata() { void RiffVideo::writeMetadata() {
} // RiffVideo::writeMetadata } // RiffVideo::writeMetadata

@ -56,8 +56,8 @@ namespace Internal {
* https://wiki.sei.cmu.edu/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow * https://wiki.sei.cmu.edu/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
*/ */
template <typename T> template <typename T>
typename std::enable_if<std::is_signed<T>::value && sizeof(T) >= sizeof(int), bool>::type fallback_add_overflow( std::enable_if_t<std::is_signed_v<T> && sizeof(T) >= sizeof(int), bool> fallback_add_overflow(T summand_1, T summand_2,
T summand_1, T summand_2, T& result) { T& result) {
if (((summand_2 >= 0) && (summand_1 > std::numeric_limits<T>::max() - summand_2)) || if (((summand_2 >= 0) && (summand_1 > std::numeric_limits<T>::max() - summand_2)) ||
((summand_2 < 0) && (summand_1 < std::numeric_limits<T>::min() - summand_2))) { ((summand_2 < 0) && (summand_1 < std::numeric_limits<T>::min() - summand_2))) {
return true; return true;
@ -86,8 +86,8 @@ typename std::enable_if<std::is_signed<T>::value && sizeof(T) >= sizeof(int), bo
* https://wiki.sei.cmu.edu/confluence/display/c/INT02-C.+Understand+integer+conversion+rules * https://wiki.sei.cmu.edu/confluence/display/c/INT02-C.+Understand+integer+conversion+rules
*/ */
template <typename T> template <typename T>
typename std::enable_if<std::is_signed<T>::value && sizeof(T) < sizeof(int), bool>::type fallback_add_overflow( std::enable_if_t<std::is_signed_v<T> && sizeof(T) < sizeof(int), bool> fallback_add_overflow(T summand_1, T summand_2,
T summand_1, T summand_2, T& result) { T& result) {
const int res = summand_1 + summand_2; const int res = summand_1 + summand_2;
if ((res > std::numeric_limits<T>::max()) || (res < std::numeric_limits<T>::min())) { if ((res > std::numeric_limits<T>::max()) || (res < std::numeric_limits<T>::min())) {
return true; return true;
@ -113,8 +113,7 @@ typename std::enable_if<std::is_signed<T>::value && sizeof(T) < sizeof(int), boo
* https://wiki.sei.cmu.edu/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap * https://wiki.sei.cmu.edu/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap
*/ */
template <typename T> template <typename T>
typename std::enable_if<!std::is_signed<T>::value, bool>::type fallback_add_overflow(T summand_1, T summand_2, std::enable_if_t<!std::is_signed_v<T>, bool> fallback_add_overflow(T summand_1, T summand_2, T& result) {
T& result) {
result = summand_1 + summand_2; result = summand_1 + summand_2;
return result < summand_1; return result < summand_1;
} }
@ -224,7 +223,7 @@ T add(T summand_1, T summand_2) {
* when `num == std::numeric_limits<T>::min()`. * when `num == std::numeric_limits<T>::min()`.
*/ */
template <typename T> template <typename T>
typename std::enable_if<std::is_signed<T>::value, T>::type abs(T num) throw() { std::enable_if_t<std::is_signed_v<T>, T> abs(T num) throw() {
if (num == std::numeric_limits<T>::min()) { if (num == std::numeric_limits<T>::min()) {
return std::numeric_limits<T>::max(); return std::numeric_limits<T>::max();
} }

@ -1864,7 +1864,7 @@ std::ostream& SonyMakerNote::printSony2FpFocusPosition2(std::ostream& os, const
} }
// Ranges of models that do not support this tag // Ranges of models that do not support this tag
for (auto& m : {"DSC-", "Stellar"}) { for (const auto& m : {"DSC-", "Stellar"}) {
if (startsWith(model, m)) { if (startsWith(model, m)) {
os << N_("n/a"); os << N_("n/a");
return os; return os;
@ -2077,7 +2077,7 @@ std::ostream& SonyMakerNote::printSonyMisc3cShotNumberSincePowerUp(std::ostream&
// Tag only valid for certain camera models. See // Tag only valid for certain camera models. See
// https://github.com/exiftool/exiftool/blob/7368629751669ba170511419b3d1e05bf0076d0e/lib/Image/ExifTool/Sony.pm#L8170 // https://github.com/exiftool/exiftool/blob/7368629751669ba170511419b3d1e05bf0076d0e/lib/Image/ExifTool/Sony.pm#L8170
static constexpr auto models = std::array{ static constexpr const char* models[] = {
"ILCA-68", "ILCA-77M2", "ILCA-99M2", "ILCE-5000", "ILCE-5100", "ILCE-6000", "ILCE-6300", "ILCA-68", "ILCA-77M2", "ILCA-99M2", "ILCE-5000", "ILCE-5100", "ILCE-6000", "ILCE-6300",
"ILCE-6500", "ILCE-7", "ILCE-7M2", "ILCE-7R", "ILCE-7RM2", "ILCE-7S", "ILCE-7SM2", "ILCE-6500", "ILCE-7", "ILCE-7M2", "ILCE-7R", "ILCE-7RM2", "ILCE-7S", "ILCE-7SM2",
"ILCE-7SM5", "ILCE-QX1", "DSC-HX350", "DSC-HX400V", "DSC-HX60V", "DSC-HX80", "DSC-HX90", "ILCE-7SM5", "ILCE-QX1", "DSC-HX350", "DSC-HX400V", "DSC-HX60V", "DSC-HX80", "DSC-HX90",
@ -2085,7 +2085,7 @@ std::ostream& SonyMakerNote::printSonyMisc3cShotNumberSincePowerUp(std::ostream&
"DSC-RX100M3", "DSC-RX100M4", "DSC-RX100M5", "DSC-WX220", "DSC-WX350", "DSC-WX500", "DSC-RX100M3", "DSC-RX100M4", "DSC-RX100M5", "DSC-WX220", "DSC-WX350", "DSC-WX500",
}; };
if (std::find(models.begin(), models.end(), model) != models.end()) { if (Exiv2::find(models, model)) {
return os << value.toInt64(); return os << value.toInt64();
} }
return os << N_("n/a"); return os << N_("n/a");
@ -2110,9 +2110,9 @@ std::ostream& SonyMakerNote::printSonyMisc3cQuality2(std::ostream& os, const Val
// Tag only valid for certain camera models. See // Tag only valid for certain camera models. See
// https://github.com/exiftool/exiftool/blob/7368629751669ba170511419b3d1e05bf0076d0e/lib/Image/ExifTool/Sony.pm#L8219 // https://github.com/exiftool/exiftool/blob/7368629751669ba170511419b3d1e05bf0076d0e/lib/Image/ExifTool/Sony.pm#L8219
constexpr std::array models{"ILCE-1", "ILCE-7M4", "ILCE-7RM5", "ILCE-7SM3", "ILME-FX3"}; constexpr const char* models[] = {"ILCE-1", "ILCE-7M4", "ILCE-7RM5", "ILCE-7SM3", "ILME-FX3"};
if (std::find(models.begin(), models.end(), model) != models.end()) { if (Exiv2::find(models, model)) {
EXV_PRINT_TAG(sonyMisc3cQuality2a)(os, val, metadata); EXV_PRINT_TAG(sonyMisc3cQuality2a)(os, val, metadata);
return os; return os;
} }
@ -2133,9 +2133,9 @@ std::ostream& SonyMakerNote::printSonyMisc3cSonyImageHeight(std::ostream& os, co
// Tag only valid for certain camera models. See // Tag only valid for certain camera models. See
// https://github.com/exiftool/exiftool/blob/7368629751669ba170511419b3d1e05bf0076d0e/lib/Image/ExifTool/Sony.pm#L8239 // https://github.com/exiftool/exiftool/blob/7368629751669ba170511419b3d1e05bf0076d0e/lib/Image/ExifTool/Sony.pm#L8239
constexpr std::array models{"ILCE-1", "ILCE-7M4", "ILCE-7RM5", "ILCE-7SM3", "ILME-FX3"}; constexpr const char* models[] = {"ILCE-1", "ILCE-7M4", "ILCE-7RM5", "ILCE-7SM3", "ILME-FX3"};
if (std::find(models.begin(), models.end(), model) != models.end()) { if (Exiv2::find(models, model)) {
return os << N_("n/a"); return os << N_("n/a");
} }
const auto val = value.toInt64(); const auto val = value.toInt64();
@ -2156,9 +2156,9 @@ std::ostream& SonyMakerNote::printSonyMisc3cModelReleaseYear(std::ostream& os, c
// Tag only valid for certain camera models. See // Tag only valid for certain camera models. See
// https://github.com/exiftool/exiftool/blob/7368629751669ba170511419b3d1e05bf0076d0e/lib/Image/ExifTool/Sony.pm#L8245 // https://github.com/exiftool/exiftool/blob/7368629751669ba170511419b3d1e05bf0076d0e/lib/Image/ExifTool/Sony.pm#L8245
constexpr std::array models{"ILCE-1", "ILCE-7M4", "ILCE-7RM5", "ILCE-7SM3", "ILME-FX3"}; constexpr const char* models[] = {"ILCE-1", "ILCE-7M4", "ILCE-7RM5", "ILCE-7SM3", "ILME-FX3"};
if (std::find(models.begin(), models.end(), model) != models.end()) { if (Exiv2::find(models, model)) {
return os << N_("n/a"); return os << N_("n/a");
} }

@ -2320,7 +2320,7 @@ const TagInfo* mnTagList() {
bool isMakerIfd(IfdId ifdId) { bool isMakerIfd(IfdId ifdId) {
bool rc = false; bool rc = false;
const GroupInfo* ii = find(groupInfo, ifdId); auto ii = Exiv2::find(groupInfo, ifdId);
if (ii && 0 == strcmp(ii->ifdName_, "Makernote")) { if (ii && 0 == strcmp(ii->ifdName_, "Makernote")) {
rc = true; rc = true;
} }
@ -2364,7 +2364,7 @@ void taglist(std::ostream& os, IfdId ifdId) {
} // taglist } // taglist
const TagInfo* tagList(IfdId ifdId) { const TagInfo* tagList(IfdId ifdId) {
const GroupInfo* ii = find(groupInfo, ifdId); auto ii = Exiv2::find(groupInfo, ifdId);
if (!ii || !ii->tagList_) if (!ii || !ii->tagList_)
return nullptr; return nullptr;
return ii->tagList_(); return ii->tagList_();
@ -2399,21 +2399,21 @@ const TagInfo* tagInfo(const std::string& tagName, IfdId ifdId) {
IfdId groupId(const std::string& groupName) { IfdId groupId(const std::string& groupName) {
IfdId ifdId = IfdId::ifdIdNotSet; IfdId ifdId = IfdId::ifdIdNotSet;
const GroupInfo* ii = find(groupInfo, GroupInfo::GroupName(groupName)); auto ii = Exiv2::find(groupInfo, GroupInfo::GroupName(groupName));
if (ii) if (ii)
ifdId = static_cast<IfdId>(ii->ifdId_); ifdId = static_cast<IfdId>(ii->ifdId_);
return ifdId; return ifdId;
} }
const char* ifdName(IfdId ifdId) { const char* ifdName(IfdId ifdId) {
const GroupInfo* ii = find(groupInfo, ifdId); auto ii = Exiv2::find(groupInfo, ifdId);
if (!ii) if (!ii)
return groupInfo[0].ifdName_; return groupInfo[0].ifdName_;
return ii->ifdName_; return ii->ifdName_;
} }
const char* groupName(IfdId ifdId) { const char* groupName(IfdId ifdId) {
const GroupInfo* ii = find(groupInfo, ifdId); auto ii = Exiv2::find(groupInfo, ifdId);
if (!ii) if (!ii)
return groupInfo[0].groupName_; return groupInfo[0].groupName_;
return ii->groupName_; return ii->groupName_;
@ -3047,7 +3047,7 @@ const GroupInfo* groupList() {
} }
const TagInfo* tagList(const std::string& groupName) { const TagInfo* tagList(const std::string& groupName) {
const GroupInfo* ii = find(groupInfo, GroupInfo::GroupName(groupName)); auto ii = Exiv2::find(groupInfo, GroupInfo::GroupName(groupName));
if (!ii || !ii->tagList_) { if (!ii || !ii->tagList_) {
return nullptr; return nullptr;
} }

@ -95,7 +95,7 @@ struct TagVocabulary {
*/ */
template <size_t N, const StringTagDetails (&array)[N]> template <size_t N, const StringTagDetails (&array)[N]>
std::ostream& printTagString(std::ostream& os, const std::string value, const ExifData*) { std::ostream& printTagString(std::ostream& os, const std::string value, const ExifData*) {
const StringTagDetails* td = find(array, value); auto td = Exiv2::find(array, value);
if (td) { if (td) {
os << exvGettext(td->label_); os << exvGettext(td->label_);
} else { } else {
@ -152,7 +152,7 @@ std::ostream& printTagString4(std::ostream& os, const Value& value, const ExifDa
*/ */
template <size_t N, const TagDetails (&array)[N]> template <size_t N, const TagDetails (&array)[N]>
std::ostream& printTagNoError(std::ostream& os, const int64_t value, const ExifData*) { std::ostream& printTagNoError(std::ostream& os, const int64_t value, const ExifData*) {
const TagDetails* td = find(array, value); auto td = Exiv2::find(array, value);
if (td) { if (td) {
os << exvGettext(td->label_); os << exvGettext(td->label_);
} else { } else {
@ -179,7 +179,7 @@ std::ostream& printTagNoError(std::ostream& os, const Value& value, const ExifDa
*/ */
template <size_t N, const TagDetails (&array)[N]> template <size_t N, const TagDetails (&array)[N]>
std::ostream& printTag(std::ostream& os, const int64_t value, const ExifData*) { std::ostream& printTag(std::ostream& os, const int64_t value, const ExifData*) {
const TagDetails* td = find(array, value); auto td = Exiv2::find(array, value);
if (td) { if (td) {
os << exvGettext(td->label_); os << exvGettext(td->label_);
} else { } else {
@ -300,7 +300,7 @@ std::ostream& printTagBitlistAllLE(std::ostream& os, const Value& value, const E
*/ */
template <size_t N, const TagVocabulary (&array)[N]> template <size_t N, const TagVocabulary (&array)[N]>
std::ostream& printTagVocabulary(std::ostream& os, const Value& value, const ExifData*) { std::ostream& printTagVocabulary(std::ostream& os, const Value& value, const ExifData*) {
const TagVocabulary* td = find(array, value.toString()); auto td = Exiv2::find(array, value.toString());
if (td) { if (td) {
os << exvGettext(td->label_); os << exvGettext(td->label_);
} else { } else {
@ -322,7 +322,7 @@ std::ostream& printTagVocabularyMulti(std::ostream& os, const Value& value, cons
for (size_t i = 0; i < value.count(); i++) { for (size_t i = 0; i < value.count(); i++) {
if (i != 0) if (i != 0)
os << ", "; os << ", ";
const TagVocabulary* td = find(array, value.toString(i)); auto td = Exiv2::find(array, value.toString(i));
if (td) { if (td) {
os << exvGettext(td->label_); os << exvGettext(td->label_);
} else { } else {

@ -141,25 +141,6 @@ TiffEntryBase::TiffEntryBase(const TiffEntryBase& rhs) :
storage_(rhs.storage_) { storage_(rhs.storage_) {
} }
TiffDirectory::TiffDirectory(const TiffDirectory& rhs) : TiffComponent(rhs), hasNext_(rhs.hasNext_) {
}
TiffSubIfd::TiffSubIfd(const TiffSubIfd& rhs) : TiffEntryBase(rhs), newGroup_(rhs.newGroup_) {
}
TiffBinaryArray::TiffBinaryArray(const TiffBinaryArray& rhs) :
TiffEntryBase(rhs),
cfgSelFct_(rhs.cfgSelFct_),
arraySet_(rhs.arraySet_),
arrayCfg_(rhs.arrayCfg_),
arrayDef_(rhs.arrayDef_),
defSize_(rhs.defSize_),
setSize_(rhs.setSize_),
origData_(rhs.origData_),
origSize_(rhs.origSize_),
pRoot_(rhs.pRoot_) {
}
TiffComponent::UniquePtr TiffComponent::clone() const { TiffComponent::UniquePtr TiffComponent::clone() const {
return UniquePtr(doClone()); return UniquePtr(doClone());
} }

@ -864,7 +864,7 @@ class TiffDirectory : public TiffComponent {
//! @name Protected Creators //! @name Protected Creators
//@{ //@{
//! Copy constructor (used to implement clone()). //! Copy constructor (used to implement clone()).
TiffDirectory(const TiffDirectory& rhs); TiffDirectory(const TiffDirectory&) = default;
//@} //@}
//! @name Protected Manipulators //! @name Protected Manipulators
@ -958,7 +958,7 @@ class TiffSubIfd : public TiffEntryBase {
//! @name Protected Creators //! @name Protected Creators
//@{ //@{
//! Copy constructor (used to implement clone()). //! Copy constructor (used to implement clone()).
TiffSubIfd(const TiffSubIfd& rhs); TiffSubIfd(const TiffSubIfd&) = default;
TiffSubIfd& operator=(const TiffSubIfd&) = delete; TiffSubIfd& operator=(const TiffSubIfd&) = delete;
//@} //@}
@ -1360,7 +1360,7 @@ class TiffBinaryArray : public TiffEntryBase {
//! @name Protected Creators //! @name Protected Creators
//@{ //@{
//! Copy constructor (used to implement clone()). //! Copy constructor (used to implement clone()).
TiffBinaryArray(const TiffBinaryArray& rhs); TiffBinaryArray(const TiffBinaryArray&) = default;
//@} //@}
//! @name Protected Manipulators //! @name Protected Manipulators

@ -1967,7 +1967,7 @@ const TiffMappingInfo TiffMapping::tiffMappingInfo_[] = {
DecoderFct TiffMapping::findDecoder(const std::string& make, uint32_t extendedTag, IfdId group) { DecoderFct TiffMapping::findDecoder(const std::string& make, uint32_t extendedTag, IfdId group) {
DecoderFct decoderFct = &TiffDecoder::decodeStdTiffEntry; DecoderFct decoderFct = &TiffDecoder::decodeStdTiffEntry;
const TiffMappingInfo* td = find(tiffMappingInfo_, TiffMappingInfo::Key(make, extendedTag, group)); auto td = Exiv2::find(tiffMappingInfo_, TiffMappingInfo::Key(make, extendedTag, group));
if (td) { if (td) {
// This may set decoderFct to 0, meaning that the tag should not be decoded // This may set decoderFct to 0, meaning that the tag should not be decoded
decoderFct = td->decoderFct_; decoderFct = td->decoderFct_;
@ -1977,7 +1977,7 @@ DecoderFct TiffMapping::findDecoder(const std::string& make, uint32_t extendedTa
EncoderFct TiffMapping::findEncoder(const std::string& make, uint32_t extendedTag, IfdId group) { EncoderFct TiffMapping::findEncoder(const std::string& make, uint32_t extendedTag, IfdId group) {
EncoderFct encoderFct = nullptr; EncoderFct encoderFct = nullptr;
const TiffMappingInfo* td = find(tiffMappingInfo_, TiffMappingInfo::Key(make, extendedTag, group)); auto td = Exiv2::find(tiffMappingInfo_, TiffMappingInfo::Key(make, extendedTag, group));
if (td) { if (td) {
// Returns 0 if no special encoder function is found // Returns 0 if no special encoder function is found
encoderFct = td->encoderFct_; encoderFct = td->encoderFct_;

@ -22,7 +22,7 @@
// ***************************************************************************** // *****************************************************************************
namespace { namespace {
//! Information pertaining to the defined %Exiv2 value type identifiers. //! Information pertaining to the defined %Exiv2 value type identifiers.
struct TypeInfoTable { constexpr struct TypeInfoTable {
Exiv2::TypeId typeId_; //!< Type id Exiv2::TypeId typeId_; //!< Type id
const char* name_; //!< Name of the type const char* name_; //!< Name of the type
size_t size_; //!< Bytes per data entry size_t size_; //!< Bytes per data entry
@ -34,34 +34,32 @@ struct TypeInfoTable {
bool operator==(const std::string& name) const { bool operator==(const std::string& name) const {
return name == name_; return name == name_;
} }
}; // struct TypeInfoTable } typeInfoTable[] = {
//! Lookup list with information of Exiv2 types
//! Lookup list with information of Exiv2 types {Exiv2::invalidTypeId, "Invalid", 0},
constexpr auto typeInfoTable = std::array{ {Exiv2::unsignedByte, "Byte", 1},
TypeInfoTable{Exiv2::invalidTypeId, "Invalid", 0}, {Exiv2::asciiString, "Ascii", 1},
TypeInfoTable{Exiv2::unsignedByte, "Byte", 1}, {Exiv2::unsignedShort, "Short", 2},
TypeInfoTable{Exiv2::asciiString, "Ascii", 1}, {Exiv2::unsignedLong, "Long", 4},
TypeInfoTable{Exiv2::unsignedShort, "Short", 2}, {Exiv2::unsignedRational, "Rational", 8},
TypeInfoTable{Exiv2::unsignedLong, "Long", 4}, {Exiv2::signedByte, "SByte", 1},
TypeInfoTable{Exiv2::unsignedRational, "Rational", 8}, {Exiv2::undefined, "Undefined", 1},
TypeInfoTable{Exiv2::signedByte, "SByte", 1}, {Exiv2::signedShort, "SShort", 2},
TypeInfoTable{Exiv2::undefined, "Undefined", 1}, {Exiv2::signedLong, "SLong", 4},
TypeInfoTable{Exiv2::signedShort, "SShort", 2}, {Exiv2::signedRational, "SRational", 8},
TypeInfoTable{Exiv2::signedLong, "SLong", 4}, {Exiv2::tiffFloat, "Float", 4},
TypeInfoTable{Exiv2::signedRational, "SRational", 8}, {Exiv2::tiffDouble, "Double", 8},
TypeInfoTable{Exiv2::tiffFloat, "Float", 4}, {Exiv2::tiffIfd, "Ifd", 4},
TypeInfoTable{Exiv2::tiffDouble, "Double", 8}, {Exiv2::string, "String", 1},
TypeInfoTable{Exiv2::tiffIfd, "Ifd", 4}, {Exiv2::date, "Date", 8},
TypeInfoTable{Exiv2::string, "String", 1}, {Exiv2::time, "Time", 11},
TypeInfoTable{Exiv2::date, "Date", 8}, {Exiv2::comment, "Comment", 1},
TypeInfoTable{Exiv2::time, "Time", 11}, {Exiv2::directory, "Directory", 1},
TypeInfoTable{Exiv2::comment, "Comment", 1}, {Exiv2::xmpText, "XmpText", 1},
TypeInfoTable{Exiv2::directory, "Directory", 1}, {Exiv2::xmpAlt, "XmpAlt", 1},
TypeInfoTable{Exiv2::xmpText, "XmpText", 1}, {Exiv2::xmpBag, "XmpBag", 1},
TypeInfoTable{Exiv2::xmpAlt, "XmpAlt", 1}, {Exiv2::xmpSeq, "XmpSeq", 1},
TypeInfoTable{Exiv2::xmpBag, "XmpBag", 1}, {Exiv2::langAlt, "LangAlt", 1},
TypeInfoTable{Exiv2::xmpSeq, "XmpSeq", 1},
TypeInfoTable{Exiv2::langAlt, "LangAlt", 1},
}; };
} // namespace } // namespace
@ -70,22 +68,22 @@ constexpr auto typeInfoTable = std::array{
// class member definitions // class member definitions
namespace Exiv2 { namespace Exiv2 {
const char* TypeInfo::typeName(TypeId typeId) { const char* TypeInfo::typeName(TypeId typeId) {
auto tit = std::find(typeInfoTable.begin(), typeInfoTable.end(), typeId); auto tit = Exiv2::find(typeInfoTable, typeId);
if (tit == typeInfoTable.end()) if (!tit)
return nullptr; return nullptr;
return tit->name_; return tit->name_;
} }
TypeId TypeInfo::typeId(const std::string& typeName) { TypeId TypeInfo::typeId(const std::string& typeName) {
auto tit = std::find(typeInfoTable.begin(), typeInfoTable.end(), typeName); auto tit = Exiv2::find(typeInfoTable, typeName);
if (tit == typeInfoTable.end()) if (!tit)
return invalidTypeId; return invalidTypeId;
return tit->typeId_; return tit->typeId_;
} }
size_t TypeInfo::typeSize(TypeId typeId) { size_t TypeInfo::typeSize(TypeId typeId) {
auto tit = std::find(typeInfoTable.begin(), typeInfoTable.end(), typeId); auto tit = Exiv2::find(typeInfoTable, typeId);
if (tit == typeInfoTable.end()) if (!tit)
return 0; return 0;
return tit->size_; return tit->size_;
} }
@ -194,9 +192,9 @@ const char* Exiv2::DataBuf::c_str(size_t offset) const {
// free functions // free functions
static void checkDataBufBounds(const DataBuf& buf, size_t end) { static void checkDataBufBounds(const DataBuf& buf, size_t end) {
enforce<std::invalid_argument>(end <= static_cast<size_t>(std::numeric_limits<long>::max()), Internal::enforce<std::invalid_argument>(end <= static_cast<size_t>(std::numeric_limits<long>::max()),
"end of slice too large to be compared with DataBuf bounds."); "end of slice too large to be compared with DataBuf bounds.");
enforce<std::out_of_range>(end <= buf.size(), "Invalid slice bounds specified"); Internal::enforce<std::out_of_range>(end <= buf.size(), "Invalid slice bounds specified");
} }
Slice<byte*> makeSlice(DataBuf& buf, size_t begin, size_t end) { Slice<byte*> makeSlice(DataBuf& buf, size_t begin, size_t end) {

@ -255,7 +255,7 @@ AsciiValue::AsciiValue(const std::string& buf) : StringValueBase(asciiString, bu
int AsciiValue::read(const std::string& buf) { int AsciiValue::read(const std::string& buf) {
value_ = buf; value_ = buf;
// ensure count>0 and nul terminated # https://github.com/Exiv2/exiv2/issues/1484 // ensure count>0 and nul terminated # https://github.com/Exiv2/exiv2/issues/1484
if (value_.empty() || value_.at(value_.size() - 1) != '\0') { if (value_.empty() || value_.back() != '\0') {
value_ += '\0'; value_ += '\0';
} }
return 0; return 0;
@ -325,8 +325,8 @@ int CommentValue::read(const std::string& comment) {
// Strip quotes (so you can also specify the charset without quotes) // Strip quotes (so you can also specify the charset without quotes)
if (!name.empty() && name.front() == '"') if (!name.empty() && name.front() == '"')
name = name.substr(1); name = name.substr(1);
if (!name.empty() && name[name.length() - 1] == '"') if (!name.empty() && name.back() == '"')
name = name.substr(0, name.length() - 1); name.pop_back();
charsetId = CharsetInfo::charsetIdByName(name); charsetId = CharsetInfo::charsetIdByName(name);
if (charsetId == invalidCharsetId) { if (charsetId == invalidCharsetId) {
#ifndef SUPPRESS_WARNINGS #ifndef SUPPRESS_WARNINGS
@ -391,7 +391,7 @@ std::string CommentValue::comment(const char* encoding) const {
bool bAscii = charsetId() == undefined || charsetId() == ascii; bool bAscii = charsetId() == undefined || charsetId() == ascii;
// # 1266 Remove trailing nulls // # 1266 Remove trailing nulls
if (bAscii && c.find('\0') != std::string::npos) { if (bAscii && c.find('\0') != std::string::npos) {
c = c.substr(0, c.find('\0')); c.resize(c.find('\0'));
} }
return c; return c;
} }
@ -503,8 +503,8 @@ int XmpTextValue::read(const std::string& buf) {
// Strip quotes (so you can also specify the type without quotes) // Strip quotes (so you can also specify the type without quotes)
if (!type.empty() && type.front() == '"') if (!type.empty() && type.front() == '"')
type = type.substr(1); type = type.substr(1);
if (!type.empty() && type[type.length() - 1] == '"') if (!type.empty() && type.back() == '"')
type = type.substr(0, type.length() - 1); type.pop_back();
b.clear(); b.clear();
if (pos != std::string::npos) if (pos != std::string::npos)
b = buf.substr(pos + 1); b = buf.substr(pos + 1);
@ -670,7 +670,7 @@ int LangAltValue::read(const std::string& buf) {
if (lang.empty() || lang.find('"') != lang.length() - 1) if (lang.empty() || lang.find('"') != lang.length() - 1)
throw Error(ErrorCode::kerInvalidLangAltValue, buf); throw Error(ErrorCode::kerInvalidLangAltValue, buf);
lang = lang.substr(0, lang.length() - 1); lang.pop_back();
} }
if (lang.empty()) if (lang.empty())
@ -954,7 +954,7 @@ size_t TimeValue::copy(byte* buf, ByteOrder /*byteOrder*/) const {
"%02d%02d%02d%1c%02d%02d", time_.hour, time_.minute, time_.second, "%02d%02d%02d%1c%02d%02d", time_.hour, time_.minute, time_.second,
plusMinus, abs(time_.tzHour), abs(time_.tzMinute))); plusMinus, abs(time_.tzHour), abs(time_.tzMinute)));
enforce(wrote == 11, Exiv2::ErrorCode::kerUnsupportedTimeFormat); Internal::enforce(wrote == 11, Exiv2::ErrorCode::kerUnsupportedTimeFormat);
std::memcpy(buf, temp, wrote); std::memcpy(buf, temp, wrote);
return wrote; return wrote;
} }

@ -312,7 +312,7 @@ void Exiv2::dumpLibraryInfo(std::ostream& os, const std::vector<std::regex>& key
int enable_video = 0; int enable_video = 0;
int use_curl = 0; int use_curl = 0;
#ifdef EXV_HAVE_INTTYPES_H #if __has_include(<inttypes.h>)
have_inttypes = 1; have_inttypes = 1;
#endif #endif
@ -324,21 +324,23 @@ void Exiv2::dumpLibraryInfo(std::ostream& os, const std::vector<std::regex>& key
have_iconv = 1; have_iconv = 1;
#endif #endif
#ifdef EXV_HAVE_LIBINTL_H #if __has_include(<libintl.h>)
have_libintl = 1; have_libintl = 1;
#endif #endif
#ifdef EXV_HAVE_MEMORY_H #if __has_include(<memory.h>)
have_memory = 1; have_memory = 1;
#endif #endif
#ifdef EXV_HAVE_STDBOOL_H #if __has_include(<stdbool.h>)
have_stdbool = 1; have_stdbool = 1;
#endif #endif
#if __has_include(<stdint.h>)
have_stdint = 1; have_stdint = 1;
#endif
#ifdef EXV_HAVE_STDLIB_H #if __has_include(<stdlib.h>)
have_stdlib = 1; have_stdlib = 1;
#endif #endif
@ -346,7 +348,7 @@ void Exiv2::dumpLibraryInfo(std::ostream& os, const std::vector<std::regex>& key
have_strerror_r = 1; have_strerror_r = 1;
#endif #endif
#ifdef EXV_HAVE_STRINGS_H #if __has_include(<strings.h>)
have_strings = 1; have_strings = 1;
#endif #endif
@ -358,19 +360,19 @@ void Exiv2::dumpLibraryInfo(std::ostream& os, const std::vector<std::regex>& key
have_munmap = 1; have_munmap = 1;
#endif #endif
#ifdef EXV_HAVE_SYS_STAT_H #if __has_include(<sys/stat.h>)
have_sys_stat = 1; have_sys_stat = 1;
#endif #endif
#ifdef EXV_HAVE_SYS_TYPES_H #if __has_include(<sys/types.h>)
have_sys_types = 1; have_sys_types = 1;
#endif #endif
#ifdef EXV_HAVE_UNISTD_H #if __has_include(<unistd.h>)
have_unistd = 1; have_unistd = 1;
#endif #endif
#ifdef EXV_HAVE_SYS_MMAN_H #if __has_include(<sys/mman.h>)
have_sys_mman = 1; have_sys_mman = 1;
#endif #endif
@ -390,22 +392,6 @@ void Exiv2::dumpLibraryInfo(std::ostream& os, const std::vector<std::regex>& key
adobe_xmpsdk = EXV_ADOBE_XMPSDK; adobe_xmpsdk = EXV_ADOBE_XMPSDK;
#endif #endif
#ifdef EXV_HAVE_BOOL
have_bool = 1;
#endif
#ifdef EXV_HAVE_STRINGS
have_strings = 1;
#endif
#ifdef EXV_SYS_TYPES
have_sys_types = 1;
#endif
#ifdef EXV_HAVE_UNISTD
have_unistd = 1;
#endif
#ifdef EXV_ENABLE_BMFF #ifdef EXV_ENABLE_BMFF
enable_bmff = 1; enable_bmff = 1;
#endif #endif

@ -173,7 +173,7 @@ void WebPImage::doWriteMetadata(BasicIo& outIo) {
has_vp8x = true; has_vp8x = true;
} }
if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8X) && !has_size) { if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8X) && !has_size) {
enforce(size_u32 >= 10, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(size_u32 >= 10, Exiv2::ErrorCode::kerCorruptedMetadata);
has_size = true; has_size = true;
byte size_buf[WEBP_TAG_SIZE]; byte size_buf[WEBP_TAG_SIZE];
@ -202,7 +202,7 @@ void WebPImage::doWriteMetadata(BasicIo& outIo) {
} }
#endif #endif
if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8) && !has_size) { if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8) && !has_size) {
enforce(size_u32 >= 10, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(size_u32 >= 10, Exiv2::ErrorCode::kerCorruptedMetadata);
has_size = true; has_size = true;
byte size_buf[2]; byte size_buf[2];
@ -220,13 +220,13 @@ void WebPImage::doWriteMetadata(BasicIo& outIo) {
/* Chunk with lossless image data. */ /* Chunk with lossless image data. */
if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8L) && !has_alpha) { if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8L) && !has_alpha) {
enforce(size_u32 >= 5, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(size_u32 >= 5, Exiv2::ErrorCode::kerCorruptedMetadata);
if ((payload.read_uint8(4) & WEBP_VP8X_ALPHA_BIT) == WEBP_VP8X_ALPHA_BIT) { if ((payload.read_uint8(4) & WEBP_VP8X_ALPHA_BIT) == WEBP_VP8X_ALPHA_BIT) {
has_alpha = true; has_alpha = true;
} }
} }
if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8L) && !has_size) { if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8L) && !has_size) {
enforce(size_u32 >= 5, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(size_u32 >= 5, Exiv2::ErrorCode::kerCorruptedMetadata);
has_size = true; has_size = true;
byte size_buf_w[2]; byte size_buf_w[2];
byte size_buf_h[3]; byte size_buf_h[3];
@ -250,13 +250,13 @@ void WebPImage::doWriteMetadata(BasicIo& outIo) {
/* Chunk with animation frame. */ /* Chunk with animation frame. */
if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_ANMF) && !has_alpha) { if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_ANMF) && !has_alpha) {
enforce(size_u32 >= 6, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(size_u32 >= 6, Exiv2::ErrorCode::kerCorruptedMetadata);
if ((payload.read_uint8(5) & 0x2) == 0x2) { if ((payload.read_uint8(5) & 0x2) == 0x2) {
has_alpha = true; has_alpha = true;
} }
} }
if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_ANMF) && !has_size) { if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_ANMF) && !has_size) {
enforce(size_u32 >= 12, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(size_u32 >= 12, Exiv2::ErrorCode::kerCorruptedMetadata);
has_size = true; has_size = true;
byte size_buf[WEBP_TAG_SIZE]; byte size_buf[WEBP_TAG_SIZE];
@ -294,7 +294,7 @@ void WebPImage::doWriteMetadata(BasicIo& outIo) {
io_->seek(+1, BasicIo::cur); // skip pad io_->seek(+1, BasicIo::cur); // skip pad
if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8X)) { if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8X)) {
enforce(size_u32 >= 1, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(size_u32 >= 1, Exiv2::ErrorCode::kerCorruptedMetadata);
if (has_icc) { if (has_icc) {
const uint8_t x = payload.read_uint8(0); const uint8_t x = payload.read_uint8(0);
payload.write_uint8(0, x | WEBP_VP8X_ICC_BIT); payload.write_uint8(0, x | WEBP_VP8X_ICC_BIT);
@ -477,7 +477,7 @@ void WebPImage::readMetadata() {
io_->readOrThrow(data, WEBP_TAG_SIZE * 3, Exiv2::ErrorCode::kerCorruptedMetadata); io_->readOrThrow(data, WEBP_TAG_SIZE * 3, Exiv2::ErrorCode::kerCorruptedMetadata);
const uint32_t filesize = Safe::add(Exiv2::getULong(data + WEBP_TAG_SIZE, littleEndian), 8U); const uint32_t filesize = Safe::add(Exiv2::getULong(data + WEBP_TAG_SIZE, littleEndian), 8U);
enforce(filesize <= io_->size(), Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(filesize <= io_->size(), Exiv2::ErrorCode::kerCorruptedMetadata);
WebPImage::decodeChunks(filesize); WebPImage::decodeChunks(filesize);
@ -500,15 +500,15 @@ void WebPImage::decodeChunks(uint32_t filesize) {
const uint32_t size = Exiv2::getULong(size_buff, littleEndian); const uint32_t size = Exiv2::getULong(size_buff, littleEndian);
// Check that `size` is within bounds. // Check that `size` is within bounds.
enforce(io_->tell() <= filesize, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(io_->tell() <= filesize, Exiv2::ErrorCode::kerCorruptedMetadata);
enforce(size <= (filesize - io_->tell()), Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(size <= (filesize - io_->tell()), Exiv2::ErrorCode::kerCorruptedMetadata);
DataBuf payload(size); DataBuf payload(size);
if (payload.empty()) { if (payload.empty()) {
io_->seek(size, BasicIo::cur); io_->seek(size, BasicIo::cur);
} else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8X) && !has_canvas_data) { } else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8X) && !has_canvas_data) {
enforce(size >= 10, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(size >= 10, Exiv2::ErrorCode::kerCorruptedMetadata);
has_canvas_data = true; has_canvas_data = true;
byte size_buf[WEBP_TAG_SIZE]; byte size_buf[WEBP_TAG_SIZE];
@ -525,7 +525,7 @@ void WebPImage::decodeChunks(uint32_t filesize) {
size_buf[3] = 0; size_buf[3] = 0;
pixelHeight_ = Exiv2::getULong(size_buf, littleEndian) + 1; pixelHeight_ = Exiv2::getULong(size_buf, littleEndian) + 1;
} else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8) && !has_canvas_data) { } else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8) && !has_canvas_data) {
enforce(size >= 10, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(size >= 10, Exiv2::ErrorCode::kerCorruptedMetadata);
has_canvas_data = true; has_canvas_data = true;
io_->readOrThrow(payload.data(), payload.size(), Exiv2::ErrorCode::kerCorruptedMetadata); io_->readOrThrow(payload.data(), payload.size(), Exiv2::ErrorCode::kerCorruptedMetadata);
@ -543,7 +543,7 @@ void WebPImage::decodeChunks(uint32_t filesize) {
size_buf[3] = 0; size_buf[3] = 0;
pixelHeight_ = Exiv2::getULong(size_buf, littleEndian) & 0x3fff; pixelHeight_ = Exiv2::getULong(size_buf, littleEndian) & 0x3fff;
} else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8L) && !has_canvas_data) { } else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8L) && !has_canvas_data) {
enforce(size >= 5, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(size >= 5, Exiv2::ErrorCode::kerCorruptedMetadata);
has_canvas_data = true; has_canvas_data = true;
byte size_buf_w[2]; byte size_buf_w[2];
@ -562,7 +562,7 @@ void WebPImage::decodeChunks(uint32_t filesize) {
size_buf_h[1] = ((size_buf_h[1] >> 6) & 0x3) | ((size_buf_h[2] & 0xFU) << 0x2); size_buf_h[1] = ((size_buf_h[1] >> 6) & 0x3) | ((size_buf_h[2] & 0xFU) << 0x2);
pixelHeight_ = Exiv2::getUShort(size_buf_h, littleEndian) + 1; pixelHeight_ = Exiv2::getUShort(size_buf_h, littleEndian) + 1;
} else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_ANMF) && !has_canvas_data) { } else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_ANMF) && !has_canvas_data) {
enforce(size >= 12, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(size >= 12, Exiv2::ErrorCode::kerCorruptedMetadata);
has_canvas_data = true; has_canvas_data = true;
byte size_buf[WEBP_TAG_SIZE]; byte size_buf[WEBP_TAG_SIZE];
@ -752,14 +752,14 @@ void WebPImage::inject_VP8X(BasicIo& iIo, bool has_xmp, bool has_exif, bool has_
} }
/* set width - stored in 24bits*/ /* set width - stored in 24bits*/
enforce(width > 0, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(width > 0, Exiv2::ErrorCode::kerCorruptedMetadata);
uint32_t w = width - 1; uint32_t w = width - 1;
data[4] = w & 0xFF; data[4] = w & 0xFF;
data[5] = (w >> 8) & 0xFF; data[5] = (w >> 8) & 0xFF;
data[6] = (w >> 16) & 0xFF; data[6] = (w >> 16) & 0xFF;
/* set height - stored in 24bits */ /* set height - stored in 24bits */
enforce(width > 0, Exiv2::ErrorCode::kerCorruptedMetadata); Internal::enforce(width > 0, Exiv2::ErrorCode::kerCorruptedMetadata);
uint32_t h = height - 1; uint32_t h = height - 1;
data[7] = h & 0xFF; data[7] = h & 0xFF;
data[8] = (h >> 8) & 0xFF; data[8] = (h >> 8) & 0xFF;

@ -585,11 +585,8 @@ static XMP_Status nsDumper(void* refCon, XMP_StringPtr buffer, XMP_StringLen buf
bool bNS = out.find(':') != std::string::npos && !bURI; bool bNS = out.find(':') != std::string::npos && !bURI;
// pop trailing ':' on a namespace // pop trailing ':' on a namespace
if (bNS && !out.empty()) { if (bNS && !out.empty() && out.back() == ':')
std::size_t length = out.length(); out.pop_back();
if (out[length - 1] == ':')
out = out.substr(0, length - 1);
}
if (bURI || bNS) { if (bURI || bNS) {
auto p = static_cast<std::map<std::string, std::string>*>(refCon); auto p = static_cast<std::map<std::string, std::string>*>(refCon);
@ -706,7 +703,7 @@ int XmpParser::decode(XmpData& xmpData, const std::string& xmpPacket) {
bool ret = SXMPMeta::GetNamespacePrefix(schemaNs.c_str(), &prefix); bool ret = SXMPMeta::GetNamespacePrefix(schemaNs.c_str(), &prefix);
if (!ret) if (!ret)
throw Error(ErrorCode::kerSchemaNamespaceNotRegistered, schemaNs); throw Error(ErrorCode::kerSchemaNamespaceNotRegistered, schemaNs);
prefix = prefix.substr(0, prefix.size() - 1); prefix.pop_back();
XmpProperties::registerNs(schemaNs, prefix); XmpProperties::registerNs(schemaNs, prefix);
} }
continue; continue;

@ -5,10 +5,16 @@
#include <error.hpp> // Need to include this header for the Exiv2::Error exception #include <error.hpp> // Need to include this header for the Exiv2::Error exception
#include <gtest/gtest.h> #include <gtest/gtest.h>
#if __has_include(<filesystem>)
#include <filesystem> #include <filesystem>
namespace fs = std::filesystem;
#else
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#endif
using namespace Exiv2; using namespace Exiv2;
namespace fs = std::filesystem;
TEST(TheImageFactory, createsInstancesForFewSupportedTypesInMemory) { TEST(TheImageFactory, createsInstancesForFewSupportedTypesInMemory) {
// Note that the constructor of these Image classes take an 'create' argument // Note that the constructor of these Image classes take an 'create' argument

@ -9,21 +9,23 @@
TEST(enforce, errMessageCanBeRetrievedFromErrorException) { TEST(enforce, errMessageCanBeRetrievedFromErrorException) {
try { try {
enforce(false, Exiv2::ErrorCode::kerErrorMessage, "an error occurred"); Exiv2::Internal::enforce(false, Exiv2::ErrorCode::kerErrorMessage, "an error occurred");
} catch (const Exiv2::Error& e) { } catch (const Exiv2::Error& e) {
ASSERT_STREQ(e.what(), "an error occurred"); ASSERT_STREQ(e.what(), "an error occurred");
} }
} }
TEST(enforce, withTrueConditionDoesNotThrow) { TEST(enforce, withTrueConditionDoesNotThrow) {
ASSERT_NO_THROW(enforce(true, Exiv2::ErrorCode::kerErrorMessage)); ASSERT_NO_THROW(Exiv2::Internal::enforce(true, Exiv2::ErrorCode::kerErrorMessage));
} }
TEST(enforce, withFalseConditionThrows) { TEST(enforce, withFalseConditionThrows) {
ASSERT_THROW(enforce(false, Exiv2::ErrorCode::kerErrorMessage), Exiv2::Error); ASSERT_THROW(Exiv2::Internal::enforce(false, Exiv2::ErrorCode::kerErrorMessage), Exiv2::Error);
ASSERT_THROW(enforce(false, Exiv2::ErrorCode::kerErrorMessage, "error message"), Exiv2::Error); ASSERT_THROW(Exiv2::Internal::enforce(false, Exiv2::ErrorCode::kerErrorMessage, "error message"), Exiv2::Error);
ASSERT_THROW(enforce(false, Exiv2::ErrorCode::kerDataSourceOpenFailed, "path", "strerror"), Exiv2::Error); ASSERT_THROW(Exiv2::Internal::enforce(false, Exiv2::ErrorCode::kerDataSourceOpenFailed, "path", "strerror"),
ASSERT_THROW(enforce(false, Exiv2::ErrorCode::kerCallFailed, "path", "strerror", "function"), Exiv2::Error); Exiv2::Error);
ASSERT_THROW(enforce(false, Exiv2::ErrorCode::kerMallocFailed), Exiv2::Error); ASSERT_THROW(Exiv2::Internal::enforce(false, Exiv2::ErrorCode::kerCallFailed, "path", "strerror", "function"),
ASSERT_THROW(enforce<std::overflow_error>(false, "error message"), std::overflow_error); Exiv2::Error);
ASSERT_THROW(Exiv2::Internal::enforce(false, Exiv2::ErrorCode::kerMallocFailed), Exiv2::Error);
ASSERT_THROW(Exiv2::Internal::enforce<std::overflow_error>(false, "error message"), std::overflow_error);
} }

@ -7,13 +7,18 @@
// Auxiliary headers // Auxiliary headers
#include <cerrno> #include <cerrno>
#include <cstdio> #include <cstdio>
#include <filesystem>
#include <fstream> #include <fstream>
#include <stdexcept> #include <stdexcept>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#if __has_include(<filesystem>)
#include <filesystem>
namespace fs = std::filesystem; namespace fs = std::filesystem;
#else
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#endif
using namespace Exiv2; using namespace Exiv2;

@ -11,11 +11,8 @@
#include "XMP_Environment.h" #include "XMP_Environment.h"
#include <stddef.h> #include <stddef.h>
#include <stdint.h>
#if XMP_MacBuild // ! No stdint.h on Windows and some UNIXes.
#include <stdint.h>
#endif
#if __cplusplus #if __cplusplus
extern "C" { extern "C" {
@ -34,31 +31,15 @@ extern "C" {
// case only the declarations of the XMP_... types needs to change, not all of the uses. These // case only the declarations of the XMP_... types needs to change, not all of the uses. These
// types are used where fixed sizes are required in order to have a known ABI for a DLL build. // types are used where fixed sizes are required in order to have a known ABI for a DLL build.
#if XMP_MacBuild typedef int8_t XMP_Int8;
typedef int16_t XMP_Int16;
typedef int8_t XMP_Int8; typedef int32_t XMP_Int32;
typedef int16_t XMP_Int16; typedef int64_t XMP_Int64;
typedef int32_t XMP_Int32;
typedef int64_t XMP_Int64;
typedef uint8_t XMP_Uns8;
typedef uint16_t XMP_Uns16;
typedef uint32_t XMP_Uns32;
typedef uint64_t XMP_Uns64;
#else typedef uint8_t XMP_Uns8;
typedef uint16_t XMP_Uns16;
typedef signed char XMP_Int8; typedef uint32_t XMP_Uns32;
typedef signed short XMP_Int16; typedef uint64_t XMP_Uns64;
typedef signed long XMP_Int32;
typedef signed long long XMP_Int64;
typedef unsigned char XMP_Uns8;
typedef unsigned short XMP_Uns16;
typedef unsigned long XMP_Uns32;
typedef unsigned long long XMP_Uns64;
#endif
typedef XMP_Uns8 XMP_Bool; typedef XMP_Uns8 XMP_Bool;

@ -38,7 +38,7 @@
# define _WIN64 1 # define _WIN64 1
#endif #endif
#if defined WIN32 #if defined _WIN32
# define WIN_ENV 1 # define WIN_ENV 1
/* Todo: How to correctly recognize a Mac platform? */ /* Todo: How to correctly recognize a Mac platform? */
#elif defined macintosh || defined MACOS_CLASSIC || defined MACOS_X_UNIX || defined MACOS_X || defined MACOS || defined(__APPLE__) #elif defined macintosh || defined MACOS_CLASSIC || defined MACOS_X_UNIX || defined MACOS_X || defined MACOS || defined(__APPLE__)

@ -114,7 +114,7 @@ extern WXMP_Result void_wResult;
#define WtoXMPDocOps_Ref(docRef) *((const XMPDocOps *)(docRef)) #define WtoXMPDocOps_Ref(docRef) *((const XMPDocOps *)(docRef))
#define WtoXMPDocOps_Ptr(docRef) (((docRef) == 0) ? 0 : (XMPDocOps *)(docRef)) #define WtoXMPDocOps_Ptr(docRef) (((docRef) == 0) ? 0 : (XMPDocOps *)(docRef))
#define IgnoreParam(p) voidVoidPtr = (void*)&p #define IgnoreParam(p) (void)p
// ================================================================================================= // =================================================================================================
// Version info // Version info

Loading…
Cancel
Save