diff --git a/CMakeLists.txt b/CMakeLists.txt index 3083b3e0..020a429a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,39 +99,38 @@ if( EXIV2_BUILD_FUZZ_TESTS ) add_subdirectory ( fuzz ) endif() -if( EXIV2_BUILD_SAMPLES ) - add_subdirectory( samples ) - get_directory_property(SAMPLES DIRECTORY samples DEFINITION APPLICATIONS) - - if (Python3_Interpreter_FOUND) - add_test(NAME bashTests - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests - COMMAND cmake -E env EXIV2_BINDIR=${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${Python3_EXECUTABLE} runner.py --verbose bash_tests - ) - endif() -endif() +if(EXIV2_BUILD_EXIV2_COMMAND) + add_subdirectory ( app ) + + if( EXIV2_BUILD_SAMPLES ) + add_subdirectory( samples ) + get_directory_property(SAMPLES DIRECTORY samples DEFINITION APPLICATIONS) + + if (Python3_Interpreter_FOUND) + add_test(NAME bashTests + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests + COMMAND cmake -E env EXIV2_BINDIR=${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${Python3_EXECUTABLE} runner.py --verbose bash_tests) + endif() + endif() + + if (Python3_Interpreter_FOUND) + add_test(NAME bugfixTests + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests + COMMAND cmake -E env EXIV2_BINDIR=${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${Python3_EXECUTABLE} runner.py --verbose bugfixes) + add_test(NAME lensTests + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests + COMMAND cmake -E env EXIV2_BINDIR=${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${Python3_EXECUTABLE} runner.py --verbose lens_tests) + add_test(NAME tiffTests + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests + COMMAND cmake -E env EXIV2_BINDIR=${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${Python3_EXECUTABLE} runner.py --verbose tiff_test) + add_test(NAME versionTests + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests + COMMAND cmake -E env EXIV2_BINDIR=${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${Python3_EXECUTABLE} runner.py --verbose bash_tests/version_test.py ) + add_test(NAME regressionTests + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests + COMMAND cmake -E env EXIV2_BINDIR=${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${Python3_EXECUTABLE} runner.py --verbose regression_tests) + endif() -if (Python3_Interpreter_FOUND) - add_test(NAME bugfixTests - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests - COMMAND cmake -E env EXIV2_BINDIR=${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${Python3_EXECUTABLE} runner.py --verbose bugfixes - ) - add_test(NAME lensTests - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests - COMMAND cmake -E env EXIV2_BINDIR=${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${Python3_EXECUTABLE} runner.py --verbose lens_tests - ) - add_test(NAME tiffTests - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests - COMMAND cmake -E env EXIV2_BINDIR=${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${Python3_EXECUTABLE} runner.py --verbose tiff_test - ) - add_test(NAME versionTests - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests - COMMAND cmake -E env EXIV2_BINDIR=${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${Python3_EXECUTABLE} runner.py --verbose bash_tests/version_test.py - ) - add_test(NAME regressionTests - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests - COMMAND cmake -E env EXIV2_BINDIR=${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${Python3_EXECUTABLE} runner.py --verbose regression_tests - ) endif() if( EXIV2_ENABLE_NLS ) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt new file mode 100644 index 00000000..e3bbf0f3 --- /dev/null +++ b/app/CMakeLists.txt @@ -0,0 +1,57 @@ +add_executable( exiv2 + exiv2.cpp + exiv2app.hpp + actions.cpp actions.hpp + getopt.cpp getopt.hpp + app_utils.cpp app_utils.hpp +) + +target_include_directories(exiv2 PRIVATE ${CMAKE_SOURCE_DIR}/src) # To find i18n.hpp + +set_target_properties( exiv2 PROPERTIES + COMPILE_FLAGS ${EXTRA_COMPILE_FLAGS} + XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS[variant=Debug] "YES" +) +if (MSVC) + set_target_properties(exiv2 PROPERTIES LINK_FLAGS "/ignore:4099") # Ignore missing PDBs +endif() + +target_link_libraries( exiv2 PRIVATE exiv2lib ) + +if( EXIV2_ENABLE_NLS ) + target_link_libraries(exiv2 PRIVATE ${Intl_LIBRARIES}) + target_include_directories(exiv2 PRIVATE ${Intl_INCLUDE_DIRS}) +endif() + +target_link_libraries(exiv2 PRIVATE std::filesystem) + +if(MSVC OR MINGW) + # Trick to get properly UTF-8 encoded argv + # More info at: https://github.com/huangqinjin/wmain + add_library(wmain STATIC wmain.c) + target_link_libraries(exiv2 PRIVATE wmain) +endif() + +if (MSVC) + target_link_options(wmain INTERFACE /WHOLEARCHIVE:$) + target_link_options(exiv2 PRIVATE "/ENTRY:wWinMainCRTStartup") +endif() + +if (MINGW) + target_compile_options(exiv2 PRIVATE -municode) + target_link_options(exiv2 PRIVATE -municode) +endif() + +if (USING_CONAN AND WIN32 AND EXISTS ${PROJECT_BINARY_DIR}/conanDlls) + # In case of using conan recipes with their 'shared' option turned on, we will have dlls of + # the 3rd party dependencies in the conanDlls folder. + + # Copy 3rd party DLLs the bin folder. [build step] + add_custom_command(TARGET exiv2 POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_BINARY_DIR}/conanDlls ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + + # Copy 3rd party DLLs the bin folder. [install step] + install(DIRECTORY ${PROJECT_BINARY_DIR}/conanDlls/ DESTINATION bin) +endif() + +install(TARGETS exiv2 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/src/actions.cpp b/app/actions.cpp similarity index 96% rename from src/actions.cpp rename to app/actions.cpp index b75c74af..6175a982 100644 --- a/src/actions.cpp +++ b/app/actions.cpp @@ -24,12 +24,13 @@ // included header files #include "config.h" +#include "app_utils.hpp" #include "actions.hpp" #include "exiv2app.hpp" + #include "image.hpp" #include "jpgimage.hpp" #include "xmpsidecar.hpp" -#include "utils.hpp" #include "types.hpp" #include "exif.hpp" #include "easyaccess.hpp" @@ -1958,26 +1959,38 @@ namespace { } }; + void replace(std::string& text, const std::string& searchText, const std::string& replaceText) + { + std::string::size_type index = 0; + while ((index = text.find(searchText, index)) != std::string::npos) + { + text.replace(index, searchText.length(), replaceText.c_str(), replaceText.length()); + index++; + } + } + int renameFile(std::string& newPath, const struct tm* tm) { + auto p = fs::path(newPath); std::string path = newPath; + auto oldFsPath = fs::path(path); std::string format = Params::instance().format_; - Util::replace(format, ":basename:", Util::basename(path, true)); - Util::replace(format, ":dirname:", Util::basename(Util::dirname(path))); - Util::replace(format, ":parentname:", Util::basename(Util::dirname(Util::dirname(path)))); + replace(format, ":basename:", p.stem().string()); + replace(format, ":dirname:", p.parent_path().filename().string()); + replace(format, ":parentname:", p.parent_path().parent_path().filename().string()); const size_t max = 1024; char basename[max]; std::memset(basename, 0x0, max); if (strftime(basename, max, format.c_str(), tm) == 0) { - std::cerr << _("Filename format yields empty filename for the file") << " " - << path << "\n"; + std::cerr << _("Filename format yields empty filename for the file") << " " << path << "\n"; return 1; } - newPath = Util::dirname(path) + EXV_SEPARATOR_STR - + basename + Util::suffix(path); - if ( Util::dirname(newPath) == Util::dirname(path) - && Util::basename(newPath) == Util::basename(path)) { + + newPath = (p.parent_path() / (basename + p.extension().string())).string(); + p = fs::path(newPath); + + if (p.parent_path() == oldFsPath.parent_path() && p.filename() == oldFsPath.filename()) { if (Params::instance().verbose_) { std::cout << _("This file already has the correct name") << std::endl; } @@ -1987,46 +2000,40 @@ namespace { bool go = true; int seq = 1; std::string s; - Params::FileExistsPolicy fileExistsPolicy - = Params::instance().fileExistsPolicy_; + Params::FileExistsPolicy fileExistsPolicy = Params::instance().fileExistsPolicy_; while (go) { if (Exiv2::fileExists(newPath)) { switch (fileExistsPolicy) { - case Params::overwritePolicy: - go = false; - break; - case Params::renamePolicy: - newPath = Util::dirname(path) - + EXV_SEPARATOR_STR + basename - + "_" + Exiv2::toString(seq++) - + Util::suffix(path); - break; - case Params::askPolicy: - std::cout << Params::instance().progname() - << ": " << _("File") << " `" << newPath - << "' " << _("exists. [O]verwrite, [r]ename or [s]kip?") - << " "; - std::cin >> s; - switch (s.at(0)) { - case 'o': - case 'O': + case Params::overwritePolicy: go = false; break; - case 'r': - case 'R': - fileExistsPolicy = Params::renamePolicy; - newPath = Util::dirname(path) - + EXV_SEPARATOR_STR + basename - + "_" + Exiv2::toString(seq++) - + Util::suffix(path); - break; - default: // skip - return -1; + case Params::renamePolicy: + newPath = (p.parent_path() / + (std::string(basename) + "_" + Exiv2::toString(seq++) + p.extension().string())) + .string(); break; - } + case Params::askPolicy: + std::cout << Params::instance().progname() << ": " << _("File") << " `" << newPath << "' " + << _("exists. [O]verwrite, [r]ename or [s]kip?") << " "; + std::cin >> s; + switch (s.at(0)) { + case 'o': + case 'O': + go = false; + break; + case 'r': + case 'R': + fileExistsPolicy = Params::renamePolicy; + newPath = (p.parent_path() / (std::string(basename) + "_" + Exiv2::toString(seq++) + + p.extension().string())) + .string(); + break; + default: // skip + return -1; + break; + } } - } - else { + } else { go = false; } } @@ -2042,25 +2049,23 @@ namespace { // Workaround for MinGW rename which does not overwrite existing files remove(newPath.c_str()); if (std::rename(path.c_str(), newPath.c_str()) == -1) { - std::cerr << Params::instance().progname() - << ": " << _("Failed to rename") << " " - << path << " " << _("to") << " " << newPath << ": " - << Exiv2::strError() << "\n"; + std::cerr << Params::instance().progname() << ": " << _("Failed to rename") << " " << path << " " << _("to") + << " " << newPath << ": " << Exiv2::strError() << "\n"; return 1; } return 0; - } // renameFile + } std::string newFilePath(const std::string& path, const std::string& ext) { - std::string directory = Params::instance().directory_; - if (directory.empty()) directory = Util::dirname(path); - directory = Exiv2::fileProtocol(path) == Exiv2::pFile - ? directory + EXV_SEPARATOR_STR - : "" // use current directory for remote files - ; - return directory + Util::basename(path, true) + ext; + auto p = fs::path(path); + auto directory = fs::path(Params::instance().directory_); + if (directory.empty()) + directory = p.parent_path(); + if (Exiv2::fileProtocol(path) != Exiv2::pFile) + directory.clear(); // use current directory for remote files + return (directory / (p.stem().string() + ext)).string(); } int dontOverwrite(const std::string& path) diff --git a/src/actions.hpp b/app/actions.hpp similarity index 100% rename from src/actions.hpp rename to app/actions.hpp diff --git a/app/app_utils.cpp b/app/app_utils.cpp new file mode 100644 index 00000000..09aaf144 --- /dev/null +++ b/app/app_utils.cpp @@ -0,0 +1,20 @@ +#include +#include + +namespace Util +{ + bool strtol(const char* nptr, long& n) + { + if (!nptr || *nptr == '\0') + return false; + char* endptr = nullptr; + long tmp = std::strtol(nptr, &endptr, 10); + if (*endptr != '\0') + return false; + if (tmp == LONG_MAX || tmp == LONG_MIN) + return false; + n = tmp; + return true; + } + +} // namespace Util diff --git a/app/app_utils.hpp b/app/app_utils.hpp new file mode 100644 index 00000000..be8db686 --- /dev/null +++ b/app/app_utils.hpp @@ -0,0 +1,13 @@ +#ifndef APP_UTILS_HPP_ +#define APP_UTILS_HPP_ + +namespace Util { + /*! + @brief Convert a C string to a long value, which is returned in n. + Returns true if the conversion is successful, else false. + n is not modified if the conversion is unsuccessful. See strtol(2). + */ + bool strtol(const char* nptr, long& n); +} // namespace Util + +#endif // #ifndef UTILS_HPP_ diff --git a/src/exiv2.cpp b/app/exiv2.cpp similarity index 99% rename from src/exiv2.cpp rename to app/exiv2.cpp index fe97449d..182ab7ae 100644 --- a/src/exiv2.cpp +++ b/app/exiv2.cpp @@ -22,12 +22,13 @@ // include local header files which are not part of libexiv2 #include "actions.hpp" -#include "convert.hpp" +#include "app_utils.hpp" #include "exiv2app.hpp" + +#include "convert.hpp" #include "futils.hpp" #include "getopt.hpp" #include "i18n.h" // NLS support. -#include "utils.hpp" #include "xmp_exiv2.hpp" #include diff --git a/src/exiv2app.hpp b/app/exiv2app.hpp similarity index 99% rename from src/exiv2app.hpp rename to app/exiv2app.hpp index 35b22c1c..97230021 100644 --- a/src/exiv2app.hpp +++ b/app/exiv2app.hpp @@ -31,7 +31,6 @@ // included header files #include -#include "utils.hpp" #include "types.hpp" #include "getopt.hpp" diff --git a/src/getopt.cpp b/app/getopt.cpp similarity index 97% rename from src/getopt.cpp rename to app/getopt.cpp index b176971e..4fd54d2e 100644 --- a/src/getopt.cpp +++ b/app/getopt.cpp @@ -25,15 +25,17 @@ // included header files #include #include +#include +#include #include #include #include #include -#include -#include "utils.hpp" #include "getopt.hpp" +namespace fs = std::filesystem; + namespace Util { // https://raw.githubusercontent.com/skeeto/getopt/master/getopt.h @@ -113,7 +115,7 @@ namespace Util { int Getopt::getopt(int argc, char* const argv[], const std::string& optstring) { - progname_ = Util::basename(argv[0]); + progname_ = fs::path(argv[0]).filename().string(); Util::optind = 0; // reset the Util::Getopt scanner for (;!errcnt_;) { diff --git a/src/getopt.hpp b/app/getopt.hpp similarity index 100% rename from src/getopt.hpp rename to app/getopt.hpp diff --git a/src/wmain.c b/app/wmain.c similarity index 100% rename from src/wmain.c rename to app/wmain.c diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index a6e1e524..566f0ab2 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -52,18 +52,24 @@ if (MSVC) link_directories(${CMAKE_INSTALL_PREFIX}/lib) endif() -add_executable( getopt-test getopt-test.cpp ../src/utils.cpp ../src/getopt.cpp) +add_executable( getopt-test getopt-test.cpp ../app/getopt.cpp) list(APPEND APPLICATIONS getopt-test) -target_include_directories(getopt-test PRIVATE ${CMAKE_SOURCE_DIR}/src) # To find utils.hpp +target_include_directories(getopt-test PRIVATE + ${CMAKE_SOURCE_DIR}/app +) # To find getopt.hpp -add_executable( metacopy metacopy.cpp ../src/utils.cpp ../src/getopt.cpp) +add_executable( metacopy metacopy.cpp ../app/getopt.cpp) list(APPEND APPLICATIONS metacopy) -target_include_directories(metacopy PRIVATE ${CMAKE_SOURCE_DIR}/src) # To find utils.hpp +target_include_directories(metacopy PRIVATE + ${CMAKE_SOURCE_DIR}/app +) # To find getopt.hpp -add_executable( path-test path-test.cpp ../src/utils.cpp ../src/getopt.cpp) +add_executable( path-test path-test.cpp ../app/getopt.cpp) list(APPEND APPLICATIONS path-test) set_target_properties( path-test PROPERTIES OUTPUT_NAME path-test ) -target_include_directories(path-test PRIVATE ${CMAKE_SOURCE_DIR}/src) # To find utils.hpp +target_include_directories(path-test PRIVATE + ${CMAKE_SOURCE_DIR}/app +) # To find getopt.hpp add_executable( exiv2json exiv2json.cpp Jzon.cpp Jzon.h) list(APPEND APPLICATIONS exiv2json) diff --git a/samples/path-test.cpp b/samples/path-test.cpp index 7dd5abd5..4f7a8d4a 100644 --- a/samples/path-test.cpp +++ b/samples/path-test.cpp @@ -20,12 +20,13 @@ */ #include +#include #include #include #include #include -#include "utils.hpp" +namespace fs = std::filesystem; int main(int argc, char* const argv[]) { @@ -49,8 +50,9 @@ int main(int argc, char* const argv[]) std::string path, dir, base; std::istringstream is(line); is >> path >> dir >> base; - std::string d = Util::dirname(path); - std::string b = Util::basename(path); + auto p = fs::path(path); + std::string d = p.parent_path().string(); + std::string b = p.filename().string(); if (d != dir || b != base) { std::cout << path << "\t'" << d << "'\t '" << b diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d418f600..a4990b4e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,3 @@ -# CMakeLists.txt for exiv2 library and command-line program - # Note that this is a hack for testing the internals of the library. If EXIV2_BUILD_UNIT_TESTS==OFF # Then we only export the symbols that are explicitly exported if( EXIV2_BUILD_UNIT_TESTS ) @@ -38,7 +36,6 @@ add_library( exiv2lib_int OBJECT tifffwd_int.hpp timegm.h unused.h - utils.cpp utils.hpp ) set(PUBLIC_HEADERS @@ -261,66 +258,3 @@ install(EXPORT exiv2Config DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/exiv2") install(FILES ${CMAKE_CURRENT_BINARY_DIR}/exiv2ConfigVersion.cmake DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/exiv2") -# ****************************************************************************** -# exiv2 application - -if(EXIV2_BUILD_EXIV2_COMMAND) - add_executable( exiv2 - exiv2.cpp - exiv2app.hpp - actions.cpp actions.hpp - getopt.cpp getopt.hpp - utils.cpp utils.hpp - ) - - set_target_properties( exiv2 PROPERTIES - COMPILE_FLAGS ${EXTRA_COMPILE_FLAGS} - XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS[variant=Debug] "YES" - ) - if (MSVC) - set_target_properties(exiv2 PROPERTIES LINK_FLAGS "/ignore:4099") # Ignore missing PDBs - endif() - - target_link_libraries( exiv2 PRIVATE exiv2lib ) - - if( EXIV2_ENABLE_NLS ) - target_link_libraries(exiv2 PRIVATE ${Intl_LIBRARIES}) - target_include_directories(exiv2 PRIVATE ${Intl_INCLUDE_DIRS}) - endif() - - target_link_libraries(exiv2 PRIVATE std::filesystem) - - if(MSVC OR MINGW) - # Trick to get properly UTF-8 encoded argv - # More info at: https://github.com/huangqinjin/wmain - add_library(wmain STATIC wmain.c) - target_link_libraries(exiv2 PRIVATE wmain) - endif() - - if (MSVC) - target_link_options(wmain INTERFACE /WHOLEARCHIVE:$) - target_link_options(exiv2 PRIVATE "/ENTRY:wWinMainCRTStartup") - endif() - - if (MINGW) - target_compile_options(exiv2 PRIVATE -municode) - target_link_options(exiv2 PRIVATE -municode) - endif() - - if (USING_CONAN AND WIN32 AND EXISTS ${PROJECT_BINARY_DIR}/conanDlls) - # In case of using conan recipes with their 'shared' option turned on, we will have dlls of - # the 3rd party dependencies in the conanDlls folder. - - # Copy 3rd party DLLs the bin folder. [build step] - add_custom_command(TARGET exiv2 POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_BINARY_DIR}/conanDlls ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) - - # Copy 3rd party DLLs the bin folder. [install step] - install(DIRECTORY ${PROJECT_BINARY_DIR}/conanDlls/ DESTINATION bin) - endif() - - install(TARGETS exiv2 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) -endif() - -# That's all Folks! -## diff --git a/src/epsimage.cpp b/src/epsimage.cpp index 1358faea..eba0c7fe 100644 --- a/src/epsimage.cpp +++ b/src/epsimage.cpp @@ -33,7 +33,6 @@ #include "error.hpp" #include "futils.hpp" #include "version.hpp" -#include "utils.hpp" // + standard includes #include @@ -49,7 +48,6 @@ namespace { using namespace Exiv2; - using namespace Util; using Exiv2::byte; // signature of DOS EPS @@ -105,6 +103,11 @@ namespace { // closing part of all valid XMP trailers const std::string xmpTrailerEnd = "?>"; + constexpr bool startsWith(const std::string_view& s, const std::string_view& start) + { + return s.find(start) == 0; + } + //! Write data into temp file, taking care of errors void writeTemp(BasicIo& tempIo, const byte* data, size_t size) { diff --git a/src/ini.cpp b/src/ini.cpp index d946552c..827bd510 100755 --- a/src/ini.cpp +++ b/src/ini.cpp @@ -249,7 +249,7 @@ long INIReader::GetInteger(const string& section, const string& name, long defau const char* value = valstr.c_str(); char* end; // This parses "1234" (decimal) and also "0x4D2" (hex) - long n = strtol(value, &end, 0); + long n = std::strtol(value, &end, 0); return end > value ? n : default_value; } diff --git a/src/makernote_int.cpp b/src/makernote_int.cpp index 164b5bb8..5863eb01 100644 --- a/src/makernote_int.cpp +++ b/src/makernote_int.cpp @@ -32,7 +32,6 @@ #include "tiffvisitor_int.hpp" #include "tiffimage.hpp" #include "tiffimage_int.hpp" -#include "utils.hpp" // + standard includes #include @@ -1219,16 +1218,18 @@ namespace Exiv2 { }; return std::find(std::begin(models), std::end(models), getExifModel(pRoot)) != std::end(models) ? 0 : -1; } + int sony2FpSelector(uint16_t /*tag*/, const byte* /*pData*/, uint32_t /*size*/, TiffComponent* const pRoot) { // Not valid for models beginning std::string model = getExifModel(pRoot); for (auto& m : { "SLT-", "HV", "ILCA-" }) { - if (Util::startsWith(model, m)) + if (model.find(m) == 0) return -1; } return 0; } + int sonyMisc2bSelector(uint16_t /*tag*/, const byte* /*pData*/, uint32_t /*size*/, TiffComponent* const pRoot) { // From Exiftool: https://github.com/exiftool/exiftool/blob/master/lib/Image/ExifTool/Sony.pm diff --git a/src/sonymn_int.cpp b/src/sonymn_int.cpp index 0cc2f0bc..e59b5e99 100644 --- a/src/sonymn_int.cpp +++ b/src/sonymn_int.cpp @@ -27,7 +27,6 @@ #include "value.hpp" #include "exif.hpp" #include "i18n.h" // NLS support. -#include "utils.hpp" // + standard includes #include @@ -905,7 +904,7 @@ namespace Exiv2 { // Ranges of models that do not support this tag std::string model = pos->toString(); for (auto& m : { "DSC-", "Stellar" }) { - if (Util::startsWith(model, m)) { + if (model.find(m) == 0) { os << N_("n/a"); return os; } diff --git a/src/utils.cpp b/src/utils.cpp deleted file mode 100644 index 389e4710..00000000 --- a/src/utils.cpp +++ /dev/null @@ -1,128 +0,0 @@ -// ***************************************************************** -*- C++ -*- -/* - * Copyright (C) 2004-2021 Exiv2 authors - * This program is part of the Exiv2 distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. - */ -// ***************************************************************************** -// included header files -#include "config.h" - -#include "utils.hpp" - -#if defined(_MSC_VER) -# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) -#endif - -// + standard includes -#ifdef EXV_HAVE_UNISTD_H -# include // for stat() -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Util { - -// ***************************************************************************** -// free functions - - std::string dirname(const std::string& path) - { - if (path.empty()) - return "."; - // Strip trailing slashes or backslashes - std::string p = path; - while ( p.length() > 1 - && (p[p.length()-1] == '\\' || p[p.length()-1] == '/')) { - p = p.substr(0, p.length()-1); - } - if (p == "\\" || p == "/") return p; - if (p.length() == 2 && p[1] == ':') return p; // For Windows paths - std::string::size_type idx = p.find_last_of("\\/"); - if (idx == std::string::npos) return "."; - if (idx == 1 && p.at(0) == '\\' && p.at(1) == '\\') return p; // For Windows paths - p = p.substr(0, idx == 0 ? 1 : idx); - while ( p.length() > 1 - && (p[p.length()-1] == '\\' || p[p.length()-1] == '/')) { - p = p.substr(0, p.length()-1); - } - return p; - } - - std::string basename(const std::string& path, bool delsuffix) - { - if (path.empty()) - return "."; - // Strip trailing slashes or backslashes - std::string p = path; - while ( p.length() > 1 - && (p[p.length()-1] == '\\' || p[p.length()-1] == '/')) { - p = p.substr(0, p.length()-1); - } - if (p.length() == 2 && p[1] == ':') return ""; // For Windows paths - std::string::size_type idx = p.find_last_of("\\/"); - if (idx == 1 && p.at(0) == '\\' && p.at(1) == '\\') return ""; // For Windows paths - if (idx != std::string::npos) p = p.substr(idx+1); - if (delsuffix) p = p.substr(0, p.length() - suffix(p).length()); - return p; - } - - std::string suffix(const std::string& path) - { - std::string b = basename(path); - std::string::size_type idx = b.rfind('.'); - if (idx == std::string::npos || idx == 0 || idx == b.length()-1) { - return ""; - } - return b.substr(idx); - } - - bool strtol(const char* nptr, long& n) - { - if (!nptr || *nptr == '\0') return false; - char* endptr = nullptr; - long tmp = std::strtol(nptr, &endptr, 10); - if (*endptr != '\0') return false; - if (tmp == LONG_MAX || tmp == LONG_MIN) return false; - n = tmp; - return true; - } - - void replace(std::string& text, const std::string& searchText, const std::string& replaceText) - { - std::string::size_type index = 0; - while ((index = text.find(searchText, index)) != std::string::npos) - { - text.replace(index, searchText.length(), replaceText.c_str(), replaceText.length()); - index++; - } - } - - bool startsWith(const std::string& s, const std::string& start) - { - return s.size() >= start.size() && std::memcmp(s.data(), start.data(), start.size()) == 0; - } - - -} // namespace Util diff --git a/src/utils.hpp b/src/utils.hpp deleted file mode 100644 index 22beeb57..00000000 --- a/src/utils.hpp +++ /dev/null @@ -1,91 +0,0 @@ -// ***************************************************************** -*- C++ -*- -/* - * Copyright (C) 2004-2021 Exiv2 authors - * This program is part of the Exiv2 distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. - */ -#ifndef UTILS_HPP_ -#define UTILS_HPP_ - -// ********************************************************************* -// included header files - -// + standard includes -#include - -// ********************************************************************* -// namespace extensions -/*! - @brief Contains utility classes and functions. Most of these are - wrappers for common C functions that do not require pointers - and memory considerations. -*/ -namespace Util { - -// ********************************************************************* -// free functions - - /*! - @brief Get the directory component from the \em path string. - See %dirname(3). - - This function can handle Windows paths to some extent: c:\\bar should - be fine, \\\\bigsrv\\foo also, but \\\\bigsrv alone doesn't work. - */ - std::string dirname(const std::string& path); - - /*! - @brief Get the filename component from the \em path string. - See %basename(3). If the \em delsuffix parameter is true, - the suffix will be removed. - - This function can handle Windows paths to some extent: c:\\bar should - be fine, \\\\bigsrv\\foo also, but \\\\bigsrv alone doesn't work. - */ - std::string basename(const std::string& path, bool delsuffix =false); - - /*! - @brief Get the suffix from the path string. Normally, the suffix - is the substring of the basename of path from the last '.' - to the end of the string. - */ - std::string suffix(const std::string& path); - - /*! - @brief Convert a C string to a long value, which is returned in n. - Returns true if the conversion is successful, else false. - n is not modified if the conversion is unsuccessful. See strtol(2). - */ - bool strtol(const char* nptr, long& n); - - /*! - @brief Replaces all occurrences of \em searchText in the \em text string - by \em replaceText. - */ - void replace(std::string& text, const std::string& searchText, const std::string& replaceText); - - // TODO: When using C++20, replace with std::basic_string::starts_with() - // (suggested in https://github.com/Exiv2/exiv2/pull/1777). - /*! - @brief Tests if \em start occurs at the beginning of \em s. - Returns true if found, else false. - When Exiv2 uses C++20, this will be replaced with - std::basic_string::starts_with(). - */ - bool startsWith(const std::string& s, const std::string& start); -} // namespace Util - -#endif // #ifndef UTILS_HPP_ diff --git a/test/data/test_reference_files/exiv2-test.out b/test/data/test_reference_files/exiv2-test.out index 11d52471..6023f884 100644 --- a/test/data/test_reference_files/exiv2-test.out +++ b/test/data/test_reference_files/exiv2-test.out @@ -224,36 +224,36 @@ Rename ------------------------------------------------------------------- File 1/16: exiv2-empty.jpg exiv2-empty.jpg: No Exif data found in the file File 2/16: exiv2-canon-powershot-s40.jpg -Renaming file to ./20031214_000043.jpg +Renaming file to 20031214_000043.jpg File 3/16: exiv2-nikon-e990.jpg -Renaming file to ./20000506_020544.jpg +Renaming file to 20000506_020544.jpg File 4/16: exiv2-nikon-d70.jpg -Renaming file to ./20040329_224245.jpg +Renaming file to 20040329_224245.jpg File 5/16: exiv2-nikon-e950.jpg -Renaming file to ./20010405_235039.jpg +Renaming file to 20010405_235039.jpg File 6/16: exiv2-canon-eos-300d.jpg -Renaming file to ./20030925_201850.jpg +Renaming file to 20030925_201850.jpg File 7/16: exiv2-kodak-dc210.jpg -Renaming file to ./20001026_044550.jpg +Renaming file to 20001026_044550.jpg File 8/16: exiv2-fujifilm-finepix-s2pro.jpg -Renaming file to ./20030926_111535.jpg +Renaming file to 20030926_111535.jpg File 9/16: exiv2-sigma-d10.jpg -Renaming file to ./20040316_075137.jpg +Renaming file to 20040316_075137.jpg File 10/16: exiv2-olympus-c8080wz.jpg -Renaming file to ./20040208_093744.jpg +Renaming file to 20040208_093744.jpg File 11/16: exiv2-panasonic-dmc-fz5.jpg -Renaming file to ./20050218_212016.jpg +Renaming file to 20050218_212016.jpg File 12/16: exiv2-sony-dsc-w7.jpg -Renaming file to ./20050527_051833.jpg +Renaming file to 20050527_051833.jpg File 13/16: exiv2-canon-eos-20d.jpg Warning: Directory Canon has an unexpected next pointer; ignored. -Renaming file to ./20060802_095200.jpg +Renaming file to 20060802_095200.jpg File 14/16: exiv2-canon-eos-d30.jpg -Renaming file to ./20001004_015404.jpg +Renaming file to 20001004_015404.jpg File 15/16: exiv2-canon-powershot-a520.jpg -Renaming file to ./20060127_225027.jpg +Renaming file to 20060127_225027.jpg File 16/16: exiv2-photoshop.psd -Renaming file to ./20110627_094001.psd +Renaming file to 20110627_094001.psd Print -------------------------------------------------------------------- File 1/16: exiv2-empty.jpg @@ -2223,72 +2223,72 @@ Warning: Directory Canon has an unexpected next pointer; ignored. Extract Exif data -------------------------------------------------------- File 1/16: exiv2-empty.jpg File 2/16: 20031214_000043.jpg -Writing Exif data from 20031214_000043.jpg to ./20031214_000043.exv +Writing Exif data from 20031214_000043.jpg to 20031214_000043.exv File 3/16: 20000506_020544.jpg -Writing Exif data from 20000506_020544.jpg to ./20000506_020544.exv +Writing Exif data from 20000506_020544.jpg to 20000506_020544.exv File 4/16: 20040329_224245.jpg -Writing Exif data from 20040329_224245.jpg to ./20040329_224245.exv +Writing Exif data from 20040329_224245.jpg to 20040329_224245.exv File 5/16: 20010405_235039.jpg -Writing Exif data from 20010405_235039.jpg to ./20010405_235039.exv +Writing Exif data from 20010405_235039.jpg to 20010405_235039.exv File 6/16: 20030925_201850.jpg -Writing Exif data from 20030925_201850.jpg to ./20030925_201850.exv +Writing Exif data from 20030925_201850.jpg to 20030925_201850.exv File 7/16: 20001026_044550.jpg -Writing Exif data from 20001026_044550.jpg to ./20001026_044550.exv -Writing JPEG comment from 20001026_044550.jpg to ./20001026_044550.exv +Writing Exif data from 20001026_044550.jpg to 20001026_044550.exv +Writing JPEG comment from 20001026_044550.jpg to 20001026_044550.exv File 8/16: 20030926_111535.jpg -Writing Exif data from 20030926_111535.jpg to ./20030926_111535.exv +Writing Exif data from 20030926_111535.jpg to 20030926_111535.exv File 9/16: 20040316_075137.jpg -Writing Exif data from 20040316_075137.jpg to ./20040316_075137.exv +Writing Exif data from 20040316_075137.jpg to 20040316_075137.exv File 10/16: 20040208_093744.jpg -Writing Exif data from 20040208_093744.jpg to ./20040208_093744.exv +Writing Exif data from 20040208_093744.jpg to 20040208_093744.exv File 11/16: 20050218_212016.jpg -Writing Exif data from 20050218_212016.jpg to ./20050218_212016.exv +Writing Exif data from 20050218_212016.jpg to 20050218_212016.exv File 12/16: 20050527_051833.jpg -Writing Exif data from 20050527_051833.jpg to ./20050527_051833.exv +Writing Exif data from 20050527_051833.jpg to 20050527_051833.exv File 13/16: 20060802_095200.jpg Warning: Directory Canon has an unexpected next pointer; ignored. -Writing Exif data from 20060802_095200.jpg to ./20060802_095200.exv +Writing Exif data from 20060802_095200.jpg to 20060802_095200.exv File 14/16: 20001004_015404.jpg -Writing Exif data from 20001004_015404.jpg to ./20001004_015404.exv +Writing Exif data from 20001004_015404.jpg to 20001004_015404.exv File 15/16: 20060127_225027.jpg -Writing Exif data from 20060127_225027.jpg to ./20060127_225027.exv +Writing Exif data from 20060127_225027.jpg to 20060127_225027.exv File 16/16: 20110626_213900.psd -Writing Exif data from 20110626_213900.psd to ./20110626_213900.exv -Writing IPTC data from 20110626_213900.psd to ./20110626_213900.exv -Writing XMP data from 20110626_213900.psd to ./20110626_213900.exv +Writing Exif data from 20110626_213900.psd to 20110626_213900.exv +Writing IPTC data from 20110626_213900.psd to 20110626_213900.exv +Writing XMP data from 20110626_213900.psd to 20110626_213900.exv Extract Thumbnail -------------------------------------------------------- File 1/16: exiv2-empty.jpg exiv2-empty.jpg: No Exif data found in the file File 2/16: 20031214_000043.jpg -Writing thumbnail (image/jpeg, 5448 Bytes) to file ./20031214_000043-thumb.jpg +Writing thumbnail (image/jpeg, 5448 Bytes) to file 20031214_000043-thumb.jpg File 3/16: 20000506_020544.jpg -Writing thumbnail (image/jpeg, 7829 Bytes) to file ./20000506_020544-thumb.jpg +Writing thumbnail (image/jpeg, 7829 Bytes) to file 20000506_020544-thumb.jpg File 4/16: 20040329_224245.jpg -Writing thumbnail (image/jpeg, 8930 Bytes) to file ./20040329_224245-thumb.jpg +Writing thumbnail (image/jpeg, 8930 Bytes) to file 20040329_224245-thumb.jpg File 5/16: 20010405_235039.jpg -Writing thumbnail (image/jpeg, 4662 Bytes) to file ./20010405_235039-thumb.jpg +Writing thumbnail (image/jpeg, 4662 Bytes) to file 20010405_235039-thumb.jpg File 6/16: 20030925_201850.jpg -Writing thumbnail (image/jpeg, 9728 Bytes) to file ./20030925_201850-thumb.jpg +Writing thumbnail (image/jpeg, 9728 Bytes) to file 20030925_201850-thumb.jpg File 7/16: 20001026_044550.jpg -Writing thumbnail (image/tiff, 20916 Bytes) to file ./20001026_044550-thumb.tif +Writing thumbnail (image/tiff, 20916 Bytes) to file 20001026_044550-thumb.tif File 8/16: 20030926_111535.jpg -Writing thumbnail (image/jpeg, 9573 Bytes) to file ./20030926_111535-thumb.jpg +Writing thumbnail (image/jpeg, 9573 Bytes) to file 20030926_111535-thumb.jpg File 9/16: 20040316_075137.jpg -Writing thumbnail (image/jpeg, 11998 Bytes) to file ./20040316_075137-thumb.jpg +Writing thumbnail (image/jpeg, 11998 Bytes) to file 20040316_075137-thumb.jpg File 10/16: 20040208_093744.jpg -Writing thumbnail (image/jpeg, 7306 Bytes) to file ./20040208_093744-thumb.jpg +Writing thumbnail (image/jpeg, 7306 Bytes) to file 20040208_093744-thumb.jpg File 11/16: 20050218_212016.jpg -Writing thumbnail (image/jpeg, 10308 Bytes) to file ./20050218_212016-thumb.jpg +Writing thumbnail (image/jpeg, 10308 Bytes) to file 20050218_212016-thumb.jpg File 12/16: 20050527_051833.jpg -Writing thumbnail (image/jpeg, 15605 Bytes) to file ./20050527_051833-thumb.jpg +Writing thumbnail (image/jpeg, 15605 Bytes) to file 20050527_051833-thumb.jpg File 13/16: 20060802_095200.jpg Warning: Directory Canon has an unexpected next pointer; ignored. -Writing thumbnail (image/jpeg, 6260 Bytes) to file ./20060802_095200-thumb.jpg +Writing thumbnail (image/jpeg, 6260 Bytes) to file 20060802_095200-thumb.jpg File 14/16: 20001004_015404.jpg -Writing thumbnail (image/jpeg, 13824 Bytes) to file ./20001004_015404-thumb.jpg +Writing thumbnail (image/jpeg, 13824 Bytes) to file 20001004_015404-thumb.jpg File 15/16: 20060127_225027.jpg -Writing thumbnail (image/jpeg, 6137 Bytes) to file ./20060127_225027-thumb.jpg +Writing thumbnail (image/jpeg, 6137 Bytes) to file 20060127_225027-thumb.jpg File 16/16: 20110626_213900.psd 20110626_213900.psd: Exif data doesn't contain a thumbnail exiv2-empty.exv: No Exif data found in the file @@ -5623,38 +5623,38 @@ File 16/16: 20110626_213900.psd Insert Exif data --------------------------------------------------------- File 1/16: exiv2-empty.jpg File 2/16: 20031214_000043.jpg -Writing Exif data from ./20031214_000043.exv to 20031214_000043.jpg +Writing Exif data from 20031214_000043.exv to 20031214_000043.jpg File 3/16: 20000506_020544.jpg -Writing Exif data from ./20000506_020544.exv to 20000506_020544.jpg +Writing Exif data from 20000506_020544.exv to 20000506_020544.jpg File 4/16: 20040329_224245.jpg -Writing Exif data from ./20040329_224245.exv to 20040329_224245.jpg +Writing Exif data from 20040329_224245.exv to 20040329_224245.jpg File 5/16: 20010405_235039.jpg -Writing Exif data from ./20010405_235039.exv to 20010405_235039.jpg +Writing Exif data from 20010405_235039.exv to 20010405_235039.jpg File 6/16: 20030925_201850.jpg -Writing Exif data from ./20030925_201850.exv to 20030925_201850.jpg +Writing Exif data from 20030925_201850.exv to 20030925_201850.jpg File 7/16: 20001026_044550.jpg -Writing Exif data from ./20001026_044550.exv to 20001026_044550.jpg -Writing JPEG comment from ./20001026_044550.exv to 20001026_044550.jpg +Writing Exif data from 20001026_044550.exv to 20001026_044550.jpg +Writing JPEG comment from 20001026_044550.exv to 20001026_044550.jpg File 8/16: 20030926_111535.jpg -Writing Exif data from ./20030926_111535.exv to 20030926_111535.jpg +Writing Exif data from 20030926_111535.exv to 20030926_111535.jpg File 9/16: 20040316_075137.jpg -Writing Exif data from ./20040316_075137.exv to 20040316_075137.jpg +Writing Exif data from 20040316_075137.exv to 20040316_075137.jpg File 10/16: 20040208_093744.jpg -Writing Exif data from ./20040208_093744.exv to 20040208_093744.jpg +Writing Exif data from 20040208_093744.exv to 20040208_093744.jpg File 11/16: 20050218_212016.jpg -Writing Exif data from ./20050218_212016.exv to 20050218_212016.jpg +Writing Exif data from 20050218_212016.exv to 20050218_212016.jpg File 12/16: 20050527_051833.jpg -Writing Exif data from ./20050527_051833.exv to 20050527_051833.jpg +Writing Exif data from 20050527_051833.exv to 20050527_051833.jpg File 13/16: 20060802_095200.jpg -Writing Exif data from ./20060802_095200.exv to 20060802_095200.jpg +Writing Exif data from 20060802_095200.exv to 20060802_095200.jpg File 14/16: 20001004_015404.jpg -Writing Exif data from ./20001004_015404.exv to 20001004_015404.jpg +Writing Exif data from 20001004_015404.exv to 20001004_015404.jpg File 15/16: 20060127_225027.jpg -Writing Exif data from ./20060127_225027.exv to 20060127_225027.jpg +Writing Exif data from 20060127_225027.exv to 20060127_225027.jpg File 16/16: 20110626_213900.psd -Writing Exif data from ./20110626_213900.exv to 20110626_213900.psd -Writing IPTC data from ./20110626_213900.exv to 20110626_213900.psd -Writing XMP data from ./20110626_213900.exv to 20110626_213900.psd +Writing Exif data from 20110626_213900.exv to 20110626_213900.psd +Writing IPTC data from 20110626_213900.exv to 20110626_213900.psd +Writing XMP data from 20110626_213900.exv to 20110626_213900.psd exiv2-empty.exv: No Exif data found in the file Compare original and inserted image data --------------------------------- diff --git a/unitTests/CMakeLists.txt b/unitTests/CMakeLists.txt index 7e209a62..ca0372fa 100644 --- a/unitTests/CMakeLists.txt +++ b/unitTests/CMakeLists.txt @@ -2,13 +2,11 @@ find_package(GTest REQUIRED) add_executable(unit_tests mainTestRunner.cpp + test_basicio.cpp test_bmpimage.cpp + test_cr2header_int.cpp test_datasets.cpp test_DateValue.cpp - test_TimeValue.cpp - test_XmpKey.cpp - test_basicio.cpp - test_cr2header_int.cpp test_enforce.cpp test_FileIo.cpp test_futils.cpp @@ -16,12 +14,14 @@ add_executable(unit_tests test_image_int.cpp test_ImageFactory.cpp test_IptcKey.cpp + test_LangAltValueRead.cpp test_pngimage.cpp test_safe_op.cpp test_slice.cpp test_tiffheader.cpp test_types.cpp - test_LangAltValueRead.cpp + test_TimeValue.cpp + test_XmpKey.cpp $ )