From a4164ce8663e905888a518eb10375aa50afc3eb3 Mon Sep 17 00:00:00 2001 From: Kevin Backhouse Date: Wed, 28 Dec 2022 09:33:08 -0600 Subject: [PATCH 1/3] Remove libinih from codebase and add it as a dependency instead. --- .github/workflows/codeql-analysis.yml | 2 +- .../workflows/nightly_Linux_distributions.yml | 2 +- .github/workflows/on_PR_linux_matrix.yml | 1 - .github/workflows/on_PR_mac_matrix.yml | 1 + .../workflows/on_PR_mac_special_builds.yml | 1 + .github/workflows/on_PR_windows_matrix.yml | 16 +- .github/workflows/on_push_BasicWinLinMac.yml | 1 + README.md | 2 +- ci/install_dependencies.sh | 34 ++- cmake/Findinih.cmake | 43 ++++ cmake/findDependencies.cmake | 8 + conanfile.py | 2 + include/exiv2/exiv2.hpp | 1 - include/exiv2/ini.hpp | 193 -------------- samples/CMakeLists.txt | 3 + samples/ini-test.cpp | 3 +- src/CMakeLists.txt | 9 +- src/ini.cpp | 239 ------------------ src/makernote_int.cpp | 4 +- unitTests/CMakeLists.txt | 2 + 20 files changed, 116 insertions(+), 451 deletions(-) create mode 100644 cmake/Findinih.cmake delete mode 100644 include/exiv2/ini.hpp delete mode 100644 src/ini.cpp diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 9a103bebb6..4a6bcb7137 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -41,7 +41,7 @@ jobs: - name: Install dependencies run: | sudo apt-get update - sudo apt-get install -y libexpat1-dev zlib1g-dev libbrotli-dev + sudo apt-get install -y libexpat1-dev zlib1g-dev libbrotli-dev libinih-dev # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/nightly_Linux_distributions.yml b/.github/workflows/nightly_Linux_distributions.yml index 88e696bb6d..47f0ba013f 100644 --- a/.github/workflows/nightly_Linux_distributions.yml +++ b/.github/workflows/nightly_Linux_distributions.yml @@ -20,7 +20,7 @@ jobs: fail-fast: false matrix: # arch suffering this issue: https://github.com/abseil/abseil-cpp/issues/709 - container_image: ["fedora:latest", "debian:10", "archlinux:base", "ubuntu:20.04", "tgagor/centos-stream:2.0.11", "alpine:3.13"] + container_image: ["fedora:latest", "debian:11", "archlinux:base", "ubuntu:22.04", "tgagor/centos:stream9", "alpine:3.17"] compiler: [g++, clang++] build_type: [Release, Debug] shared_libraries: [ON, OFF] diff --git a/.github/workflows/on_PR_linux_matrix.yml b/.github/workflows/on_PR_linux_matrix.yml index be606d1103..15ee51688d 100644 --- a/.github/workflows/on_PR_linux_matrix.yml +++ b/.github/workflows/on_PR_linux_matrix.yml @@ -50,7 +50,6 @@ jobs: run: | cd build-base_linux cmake --install . - tree install - name: Test run: | diff --git a/.github/workflows/on_PR_mac_matrix.yml b/.github/workflows/on_PR_mac_matrix.yml index 89d57d2355..a561a4e363 100644 --- a/.github/workflows/on_PR_mac_matrix.yml +++ b/.github/workflows/on_PR_mac_matrix.yml @@ -26,6 +26,7 @@ jobs: - name: install dependencies run: | brew install ninja + brew install inih pushd /tmp curl -LO https://github.com/google/googletest/archive/release-1.8.0.tar.gz tar xzf release-1.8.0.tar.gz diff --git a/.github/workflows/on_PR_mac_special_builds.yml b/.github/workflows/on_PR_mac_special_builds.yml index 6ae213ec6a..88ef1e905c 100644 --- a/.github/workflows/on_PR_mac_special_builds.yml +++ b/.github/workflows/on_PR_mac_special_builds.yml @@ -21,6 +21,7 @@ jobs: - name: install dependencies run: | brew install ninja + brew install inih pushd /tmp curl -LO https://github.com/google/googletest/archive/release-1.8.0.tar.gz tar xzf release-1.8.0.tar.gz diff --git a/.github/workflows/on_PR_windows_matrix.yml b/.github/workflows/on_PR_windows_matrix.yml index 06f0c9134e..8f86fb0dd3 100644 --- a/.github/workflows/on_PR_windows_matrix.yml +++ b/.github/workflows/on_PR_windows_matrix.yml @@ -115,6 +115,7 @@ jobs: update: true install: >- base-devel + git pacboy: >- cc:p gcc-libs:p @@ -128,6 +129,8 @@ jobs: zlib:p brotli:p curl:p + meson:p + libinih:p - name: Build run: | @@ -150,7 +153,7 @@ jobs: matrix: build_type: [Release] shared_libraries: [ON] - platform: [x64] + platform: [x86_64] name: Cygwin ${{matrix.platform}} - BuildType:${{matrix.build_type}} - SHARED:${{matrix.shared_libraries}} env: SHELLOPTS: igncr @@ -180,6 +183,17 @@ jobs: libbrotlicommon1 libbrotlidec1 libbrotli-devel + meson + ccache + + - name: Build and install inih + run: | + git clone https://github.com/benhoyt/inih.git inih_build && \ + cd inih_build && \ + git checkout r56 && \ + meson --buildtype=plain --prefix=/usr builddir && \ + meson compile -C builddir && \ + meson install -C builddir - name: Build run: | diff --git a/.github/workflows/on_push_BasicWinLinMac.yml b/.github/workflows/on_push_BasicWinLinMac.yml index e4b55b8723..ac14122046 100644 --- a/.github/workflows/on_push_BasicWinLinMac.yml +++ b/.github/workflows/on_push_BasicWinLinMac.yml @@ -103,6 +103,7 @@ jobs: - name: install dependencies run: | brew install ninja + brew install inih pushd /tmp curl -LO https://github.com/google/googletest/archive/release-1.8.0.tar.gz tar xzf release-1.8.0.tar.gz diff --git a/README.md b/README.md index 6b1350201c..3c0c7aa8f6 100644 --- a/README.md +++ b/README.md @@ -1217,7 +1217,7 @@ Update your system and install the build tools and dependencies (zlib, expat, gt ```bash $ sudo apt --yes update -$ sudo apt install --yes build-essential git clang ccache python3 libxml2-utils cmake python3 libexpat1-dev libz-dev zlib1g-dev libbrotli-dev libssh-dev libcurl4-openssl-dev libgtest-dev google-mock +$ sudo apt install --yes build-essential git clang ccache python3 libxml2-utils cmake python3 libexpat1-dev libz-dev zlib1g-dev libbrotli-dev libssh-dev libcurl4-openssl-dev libgtest-dev google-mock libinih-dev ``` For users of other platforms, the script /ci/install_dependencies.sh has code used to configure many platforms. The code in that file is a useful guide to configuring your platform. diff --git a/ci/install_dependencies.sh b/ci/install_dependencies.sh index 63885dbaa2..0f7c163dfd 100755 --- a/ci/install_dependencies.sh +++ b/ci/install_dependencies.sh @@ -20,6 +20,17 @@ debian_build_gtest() { cd .. } +# Centos doesn't have a working version of the inih library, so we need to build it ourselves. +centos_build_inih() { + [-d inih_build ] || git clone https://github.com/benhoyt/inih.git inih_build + cd inih_build + git checkout r56 + meson --buildtype=plain builddir + meson compile -C builddir + meson install -C builddir + cd .. +} + # workaround for really bare-bones Archlinux containers: if [ -x "$(command -v pacman)" ]; then pacman --noconfirm -Sy @@ -30,39 +41,46 @@ distro_id=$(grep '^ID=' /etc/os-release|awk -F = '{print $2}'|sed 's/\"//g') case "$distro_id" in 'fedora') - dnf -y --refresh install gcc-c++ clang cmake make expat-devel zlib-devel brotli-devel libssh-devel libcurl-devel gtest-devel which dos2unix glibc-langpack-en diffutils + dnf -y --refresh install gcc-c++ clang cmake make expat-devel zlib-devel brotli-devel libssh-devel libcurl-devel gtest-devel which dos2unix glibc-langpack-en diffutils inih-devel ;; 'debian') apt-get update - apt-get install -y cmake g++ clang make libexpat1-dev zlib1g-dev libbrotli-dev libssh-dev libcurl4-openssl-dev libgtest-dev libxml2-utils + apt-get install -y cmake g++ clang make libexpat1-dev zlib1g-dev libbrotli-dev libssh-dev libcurl4-openssl-dev libgtest-dev libxml2-utils libinih-dev debian_build_gtest ;; 'arch') pacman --noconfirm -Syu - pacman --noconfirm --needed -S gcc clang cmake make expat zlib brotli libssh curl gtest dos2unix which diffutils + pacman --noconfirm --needed -S gcc clang cmake make expat zlib brotli libssh curl gtest dos2unix which diffutils libinih ;; 'ubuntu') apt-get update - apt-get install -y cmake g++ clang make libexpat1-dev zlib1g-dev libbrotli-dev libssh-dev libcurl4-openssl-dev libgtest-dev google-mock libxml2-utils + apt-get install -y cmake g++ clang make libexpat1-dev zlib1g-dev libbrotli-dev libssh-dev libcurl4-openssl-dev libgtest-dev google-mock libxml2-utils libinih-dev debian_build_gtest ;; 'alpine') apk update - apk add gcc g++ clang cmake make expat-dev zlib-dev brotli-dev libssh-dev curl-dev gtest gtest-dev gmock libintl gettext-dev which dos2unix bash libxml2-utils diffutils + apk add gcc g++ clang cmake make expat-dev zlib-dev brotli-dev libssh-dev curl-dev gtest gtest-dev gmock libintl gettext-dev which dos2unix bash libxml2-utils diffutils inih-dev inih-inireader-dev + ;; + + 'rhel') + dnf clean all + dnf -y install gcc-c++ clang cmake make expat-devel zlib-devel brotli-devel libssh-devel libcurl-devel which dos2unix inih-devel ;; - 'centos'|'rhel') + 'centos') dnf clean all - dnf -y install gcc-c++ clang cmake make expat-devel zlib-devel brotli-devel libssh-devel libcurl-devel which dos2unix + dnf -y install gcc-c++ clang cmake make expat-devel zlib-devel brotli-devel libssh-devel libcurl-devel which dos2unix git + dnf -y --enablerepo=crb install meson + centos_build_inih ;; 'opensuse-tumbleweed') zypper --non-interactive refresh - zypper --non-interactive install gcc-c++ clang cmake make libexpat-devel zlib-devel libbrotli-devel libssh-devel curl libcurl-devel git which dos2unix libxml2-tools + zypper --non-interactive install gcc-c++ clang cmake make libexpat-devel zlib-devel libbrotli-devel libssh-devel curl libcurl-devel git which dos2unix libxml2-tools libinih-devel pushd /tmp curl -LO https://github.com/google/googletest/archive/release-1.8.0.tar.gz tar xzf release-1.8.0.tar.gz diff --git a/cmake/Findinih.cmake b/cmake/Findinih.cmake new file mode 100644 index 0000000000..0913d32a92 --- /dev/null +++ b/cmake/Findinih.cmake @@ -0,0 +1,43 @@ +set(inih_LIBRARY_NAMES "inih" "libinih") +set(inih_inireader_LIBRARY_NAMES "INIReader" "libINIReader") + +find_path(inih_INCLUDE_DIR + NAMES "ini.h" + DOC "inih include directory") + +find_path(inih_inireader_INCLUDE_DIR + NAMES "INIReader.h" + DOC "INIReader include directory") + +find_library(inih_LIBRARY + NAMES ${inih_LIBRARY_NAMES} + DOC "inih library") + +find_library(inih_inireader_LIBRARY + NAMES ${inih_inireader_LIBRARY_NAMES} + DOC "inih library") + +mark_as_advanced(inih_INCLUDE_DIR) +mark_as_advanced(inih_LIBRARY) +mark_as_advanced(inih_inireader_INCLUDE_DIR) +mark_as_advanced(inih_inireader_LIBRARY) + +find_package_handle_standard_args(inih REQUIRED_VARS inih_LIBRARY inih_INCLUDE_DIR) + +if(inih_FOUND) + set(inih_INCLUDE_DIRS "${inih_INCLUDE_DIR}") + set(inih_LIBRARIES "${inih_LIBRARY}") + if(NOT TARGET inih::libinih) + add_library(inih::libinih INTERFACE IMPORTED) + endif() + set_property(TARGET inih::libinih PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${inih_INCLUDE_DIRS}") + set_property(TARGET inih::libinih PROPERTY INTERFACE_LINK_LIBRARIES "${inih_LIBRARIES}") + + set(inih_inireader_INCLUDE_DIRS "${inih_inireader_INCLUDE_DIR}") + set(inih_inireader_LIBRARIES "${inih_inireader_LIBRARY}") + if(NOT TARGET inih::inireader) + add_library(inih::inireader INTERFACE IMPORTED) + endif() + set_property(TARGET inih::inireader PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${inih_inireader_INCLUDE_DIRS}") + set_property(TARGET inih::inireader PROPERTY INTERFACE_LINK_LIBRARIES "${inih_inireader_LIBRARIES}") +endif() diff --git a/cmake/findDependencies.cmake b/cmake/findDependencies.cmake index 2effaeefca..d3f3f7611c 100644 --- a/cmake/findDependencies.cmake +++ b/cmake/findDependencies.cmake @@ -76,6 +76,14 @@ if( ICONV_FOUND ) message ( "-- Iconv_LIBRARIES : " ${Iconv_LIBRARIES} ) endif() +find_package(inih) +if( inih_FOUND ) + message ( "-- inih_INCLUDE_DIRS : " ${inih_INCLUDE_DIRS} ) + message ( "-- inih_LIBRARIES : " ${inih_LIBRARIES} ) + message ( "-- inih_inireader_INCLUDE_DIRS : " ${inih_inireader_INCLUDE_DIRS} ) + message ( "-- inih_inireader_LIBRARIES : " ${inih_inireader_LIBRARIES} ) +endif() + if( BUILD_WITH_CCACHE ) find_program(CCACHE_FOUND ccache) if(CCACHE_FOUND) diff --git a/conanfile.py b/conanfile.py index 65ff93cd1a..3d869d831b 100644 --- a/conanfile.py +++ b/conanfile.py @@ -25,6 +25,8 @@ def requirements(self): self.requires('brotli/1.0.9') + self.requires('inih/55') + if self.options.webready: self.requires('libcurl/7.85.0') diff --git a/include/exiv2/exiv2.hpp b/include/exiv2/exiv2.hpp index 2798f7d55e..bae5614d22 100644 --- a/include/exiv2/exiv2.hpp +++ b/include/exiv2/exiv2.hpp @@ -21,7 +21,6 @@ #include "exiv2/gifimage.hpp" #include "exiv2/http.hpp" #include "exiv2/image.hpp" -#include "exiv2/ini.hpp" #include "exiv2/iptc.hpp" #include "exiv2/jp2image.hpp" #include "exiv2/jpgimage.hpp" diff --git a/include/exiv2/ini.hpp b/include/exiv2/ini.hpp deleted file mode 100644 index 6845758a7d..0000000000 --- a/include/exiv2/ini.hpp +++ /dev/null @@ -1,193 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later AND BSD-3-Clause - -// Read an INI file into easy-to-access name/value pairs. -// inih and INIReader are released under the New BSD license (see LICENSE.txt). -// Go to the project home page for more info: -// -// https://github.com/benhoyt/inih - -#ifndef __INIREADER_H__ -#define __INIREADER_H__ - -#include "exiv2lib_export.h" - -#include "config.h" - -#include -#include - -namespace Exiv2 { -#ifndef __INI_H__ -#define __INI_H__ - -/* Make this header file easier to include in C++ code */ -#ifdef __cplusplus -extern "C" { -#endif - -//! @brief typedef for prototype of handler function. -using ini_handler = int (*)(void* user, const char* section, const char* name, const char* value); - -//! Typedef for prototype of fgets-style reader function. -using ini_reader = char* (*)(char* str, int num, void* stream); - -/*! - @brief Parse given INI-style file. May have [section]s, name=value pairs - (whitespace stripped), and comments starting with ';' (semicolon). Section - is "" if name=value pair parsed before any section heading. name:value - pairs are also supported as a concession to Python's configparser. - - For each name=value pair parsed, call handler function with given user - pointer as well as section, name, and value (data only valid for duration - of handler call). Handler should return nonzero on success, zero on error. - - @param filename path to file - @param handler user defined handler - @param user void pointer passed to user handler - - @return 0 on success, line number of first error on parse error (doesn't - stop on first error), -1 on file open error, or -2 on memory allocation - error (only when INI_USE_STACK is zero). - - @return 0 on success -*/ -int ini_parse(const char* filename, ini_handler handler, void* user); - -/*! @brief Same as ini_parse(), but takes a FILE* instead of filename. This doesn't - close the file when it's finished -- the caller must do that. - - @param file open "C" file - @param handler user defined handler - @param user void pointer passed to user handler - */ -int ini_parse_file(FILE* file, ini_handler handler, void* user); - -/*! @brief Same as ini_parse(), but takes an ini_reader function pointer instead of - filename. Used for implementing custom or string-based I/O. - @param reader magic - @param stream more magic - @param handler user defined handler - @param user void pointer passed to user handler - - @return 0 on success -*/ -int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, void* user); - -/*! @brief Nonzero to allow multi-line value parsing, in the style of Python's - configparser. If allowed, ini_parse() will call the handler with the same - name for each subsequent line parsed. -*/ -#ifndef INI_ALLOW_MULTILINE -#define INI_ALLOW_MULTILINE 1 -#endif - -/*! @brief Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of - the file. See http://code.google.com/p/inih/issues/detail?id=21 -*/ -#ifndef INI_ALLOW_BOM -#define INI_ALLOW_BOM 1 -#endif - -/*! @brief Nonzero to allow inline comments (with valid inline comment characters - specified by INI_INLINE_COMMENT_PREFIXES). Set to 0 to turn off and match - Python 3.2+ configparser behaviour. -*/ -#ifndef INI_ALLOW_INLINE_COMMENTS -#define INI_ALLOW_INLINE_COMMENTS 1 -#endif -#ifndef INI_INLINE_COMMENT_PREFIXES -#define INI_INLINE_COMMENT_PREFIXES ";" -#endif - -//! @brief Nonzero to use stack, zero to use heap (malloc/free). -#ifndef INI_USE_STACK -#define INI_USE_STACK 1 -#endif - -//! @brief Stop parsing on first error (default is to keep parsing). -#ifndef INI_STOP_ON_FIRST_ERROR -#define INI_STOP_ON_FIRST_ERROR 0 -#endif - -//! @brief Maximum line length for any line in INI file. -#ifndef INI_MAX_LINE -#define INI_MAX_LINE 200 -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* __INI_H__ */ - -/*! @brief Read an INI file into easy-to-access name/value pairs. (Note that I've gone - for simplicity here rather than speed, but it should be pretty decent.) - */ -class EXIV2API INIReader { - public: - /*! @brief Construct INIReader and parse given filename. See ini.h for more info - about the parsing. - */ - explicit INIReader(const std::string& filename); - - /*! @brief Return the result of ini_parse(), i.e., 0 on success, line number of - first error on parse error, or -1 on file open error. - */ - [[nodiscard]] int ParseError() const; - - /*! @brief Get a string value from INI file, returning default_value if not found. - - @param section name of section - @param name name of key - @param default_value default if not found - - @return value - */ - std::string Get(const std::string& section, const std::string& name, const std::string& default_value); - - /*! @brief Get an integer (long) value from INI file, returning default_value if - not found or not a valid integer (decimal "1234", "-1234", or hex "0x4d2"). - - @param section name of section - @param name name of key - @param default_value default if not found - - @return value - */ - long GetInteger(const std::string& section, const std::string& name, long default_value); - - /*! @brief Get a real (floating point double) value from INI file, returning - default_value if not found or not a valid floating point value - according to strtod(). - - @param section name of section - @param name name of key - @param default_value default if not found - - @return value - */ - double GetReal(const std::string& section, const std::string& name, double default_value); - - /*! @brief Get a boolean value from INI file, returning default_value if not found or if - not a valid true/false value. Valid true values are "true", "yes", "on", "1", - and valid false values are "false", "no", "off", "0" (not case sensitive). - - @param section name of section - @param name name of key - @param default_value default if not found - - @return value - */ - bool GetBoolean(const std::string& section, const std::string& name, bool default_value); - - private: - int _error; //!< status - std::map _values; //!< values from file - static std::string MakeKey(const std::string& section, - const std::string& name); //!< return key encoded from section/name - static int ValueHandler(void* user, const char* section, const char* name, - const char* value); //!< value handler -}; -} // namespace Exiv2 - -#endif // __INIREADER_H__ diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 41b3abbc47..a6c36f3278 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -72,6 +72,9 @@ target_include_directories(path-test PRIVATE install( TARGETS metacopy RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) +target_link_libraries( ini-test PRIVATE inih::libinih ) +target_link_libraries( ini-test PRIVATE inih::inireader ) + if( EXPAT_FOUND ) add_executable( geotag geotag.cpp) list(APPEND APPLICATIONS geotag) diff --git a/samples/ini-test.cpp b/samples/ini-test.cpp index 122c8cb263..443121cd86 100644 --- a/samples/ini-test.cpp +++ b/samples/ini-test.cpp @@ -9,6 +9,7 @@ Config loaded from : 'initest.ini' version=6, name=Bob Smith, email=bob@smith.co */ // Example that shows simple usage of the INIReader class +#include #include #include @@ -20,7 +21,7 @@ int main() { #endif const char* ini = "ini-test.ini"; - Exiv2::INIReader reader(ini); + INIReader reader(ini); if (reader.ParseError() < 0) { std::cerr << "Can't load '" << ini << "'" << std::endl; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 108f656012..9c75e9c843 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -57,7 +57,6 @@ set(PUBLIC_HEADERS ../include/exiv2/http.hpp ../include/exiv2/image.hpp ../include/exiv2/image_types.hpp - ../include/exiv2/ini.hpp ../include/exiv2/iptc.hpp ../include/exiv2/jp2image.hpp ../include/exiv2/jpgimage.hpp @@ -101,7 +100,6 @@ add_library( exiv2lib gifimage.cpp http.cpp image.cpp - ini.cpp iptc.cpp jp2image.cpp jpgimage.cpp @@ -250,6 +248,13 @@ if( ICONV_FOUND ) target_link_libraries( exiv2lib PRIVATE Iconv::Iconv ) endif() +if( inih_FOUND ) + target_link_libraries( exiv2lib_int PRIVATE inih::libinih ) + target_link_libraries( exiv2lib_int PRIVATE inih::inireader ) + target_link_libraries( exiv2lib PRIVATE inih::libinih ) + target_link_libraries( exiv2lib PRIVATE inih::inireader ) +endif() + write_basic_package_version_file(exiv2ConfigVersion.cmake COMPATIBILITY ExactVersion) install(TARGETS exiv2lib EXPORT exiv2Config diff --git a/src/ini.cpp b/src/ini.cpp deleted file mode 100644 index f89ee40bdb..0000000000 --- a/src/ini.cpp +++ /dev/null @@ -1,239 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later AND BSD-3-Clause - -// Read an INI file into easy-to-access name/value pairs. - -// inih and INIReader are released under the New BSD license (see LICENSE.txt). -// Go to the project home page for more info: -// -// https://github.com/benhoyt/inih - -#include "ini.hpp" - -#include -#include -#include - -using std::string; -using namespace Exiv2; - -#include - -#if !INI_USE_STACK -#include -#endif - -#define MAX_SECTION 50 -#define MAX_NAME 50 - -/* Strip whitespace chars off end of given string, in place. Return s. */ -static char* rstrip(char* s) { - char* p = s + strlen(s); - while (p > s && isspace(static_cast(*--p))) - *p = '\0'; - return s; -} - -/* Return pointer to first non-whitespace char in given string. */ -static char* lskip(const char* s) { - while (*s && isspace(static_cast(*s))) - s++; - return const_cast(s); -} - -/* Return pointer to first char (of chars) or inline comment in given string, - or pointer to null at end of string if neither found. Inline comment must - be prefixed by a whitespace character to register as a comment. */ -static char* find_chars_or_comment(const char* s, const char* chars) { -#if INI_ALLOW_INLINE_COMMENTS - int was_space = 0; - while (*s && (!chars || !strchr(chars, *s)) && !(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) { - was_space = isspace(static_cast(*s)); - s++; - } -#else - while (*s && (!chars || !strchr(chars, *s))) { - s++; - } -#endif - return const_cast(s); -} - -/* Version of strncpy that ensures dest (size bytes) is null-terminated. */ -static char* strncpy0(char* dest, const char* src, size_t size) { - memcpy(dest, src, size); - dest[size - 1] = '\0'; - return dest; -} - -/* See documentation in header file. */ -int Exiv2::ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, void* user) { - /* Uses a fair bit of stack (use heap instead if you need to) */ -#if INI_USE_STACK - char line[INI_MAX_LINE]; -#else - char* line; -#endif - char section[MAX_SECTION] = ""; - char prev_name[MAX_NAME] = ""; - - char* start; - char* end; - char* name; - char* value; - int lineno = 0; - int error = 0; - -#if !INI_USE_STACK - line = (char*)malloc(INI_MAX_LINE); - if (!line) { - return -2; - } -#endif - - /* Scan through stream line by line */ - while (reader(line, INI_MAX_LINE, stream)) { - lineno++; - - start = line; -#if INI_ALLOW_BOM - if (lineno == 1 && static_cast(start[0]) == 0xEF && static_cast(start[1]) == 0xBB && - static_cast(start[2]) == 0xBF) { - start += 3; - } -#endif - start = lskip(rstrip(start)); - - if (*start == ';' || *start == '#') { - /* Per Python configparser, allow both ; and # comments at the - start of a line */ - } -#if INI_ALLOW_MULTILINE - else if (*prev_name && *start && start > line) { - /* Non-blank line with leading whitespace, treat as continuation - of previous name's value (as per Python configparser). */ - if (!handler(user, section, prev_name, start) && !error) - error = lineno; - } -#endif - else if (*start == '[') { - /* A "[section]" line */ - end = find_chars_or_comment(start + 1, "]"); - if (*end == ']') { - *end = '\0'; - strncpy0(section, start + 1, sizeof(section)); - *prev_name = '\0'; - } else if (!error) { - /* No ']' found on section line */ - error = lineno; - } - } else if (*start) { - /* Not a comment, must be a name[=:]value pair */ - end = find_chars_or_comment(start, "=:"); - if (*end == '=' || *end == ':') { - *end = '\0'; - name = rstrip(start); - value = lskip(end + 1); -#if INI_ALLOW_INLINE_COMMENTS - end = find_chars_or_comment(value, nullptr); - if (*end) - *end = '\0'; -#endif - rstrip(value); - - /* Valid name[=:]value pair found, call handler */ - strncpy0(prev_name, name, sizeof(prev_name)); - if (!handler(user, section, name, value) && !error) - error = lineno; - } else if (!error) { - /* No '=' or ':' found on name[=:]value line */ - error = lineno; - } - } - -#if INI_STOP_ON_FIRST_ERROR - if (error) - break; -#endif - } - -#if !INI_USE_STACK - free(line); -#endif - - return error; -} - -/* See documentation in header file. */ -int Exiv2::ini_parse_file(FILE* file, ini_handler handler, void* user) { - return Exiv2::ini_parse_stream(reinterpret_cast(fgets), file, handler, user); -} - -/* See documentation in header file. */ -int Exiv2::ini_parse(const char* filename, ini_handler handler, void* user) { - FILE* file; - int error; - - file = fopen(filename, "r"); - if (!file) - return -1; - error = Exiv2::ini_parse_file(file, handler, user); - fclose(file); - return error; -} - -INIReader::INIReader(const std::string& filename) { - _error = ini_parse(filename.c_str(), ValueHandler, this); -} - -int INIReader::ParseError() const { - return _error; -} - -string INIReader::Get(const string& section, const string& name, const string& default_value) { - string key = MakeKey(section, name); - return _values.count(key) ? _values[key] : default_value; -} - -long INIReader::GetInteger(const string& section, const string& name, long default_value) { - string valstr = Get(section, name, ""); - const char* value = valstr.c_str(); - char* end; - // This parses "1234" (decimal) and also "0x4D2" (hex) - long n = std::strtol(value, &end, 0); - return end > value ? n : default_value; -} - -double INIReader::GetReal(const string& section, const string& name, double default_value) { - string valstr = Get(section, name, ""); - const char* value = valstr.c_str(); - char* end; - double n = strtod(value, &end); - return end > value ? n : default_value; -} - -bool INIReader::GetBoolean(const string& section, const string& name, bool default_value) { - string valstr = Get(section, name, ""); - // Convert to lower case to make string comparisons case-insensitive - std::transform(valstr.begin(), valstr.end(), valstr.begin(), ::tolower); - if (valstr == "true" || valstr == "yes" || valstr == "on" || valstr == "1") - return true; - if (valstr == "false" || valstr == "no" || valstr == "off" || valstr == "0") - return false; - return default_value; -} - -string INIReader::MakeKey(const string& section, const string& name) { - string key = section + "=" + name; - // Convert to lower case to make section/name lookups case-insensitive - std::transform(key.begin(), key.end(), key.begin(), ::tolower); - return key; -} - -int INIReader::ValueHandler(void* user, const char* section, const char* name, const char* value) { - auto reader = static_cast(user); - string key = MakeKey(section, name); - if (!reader->_values[key].empty()) - reader->_values[key] += "\n"; - reader->_values[key] += value; - return 1; -} diff --git a/src/makernote_int.cpp b/src/makernote_int.cpp index 79a99b0fd8..0c243975e0 100644 --- a/src/makernote_int.cpp +++ b/src/makernote_int.cpp @@ -7,7 +7,6 @@ // included header files #include "config.h" -#include "ini.hpp" #include "makernote_int.hpp" #include "safe_op.hpp" #include "tiffcomposite_int.hpp" @@ -16,6 +15,7 @@ #include "utils.hpp" // + standard includes +#include #include #include #include @@ -81,7 +81,7 @@ std::string getExiv2ConfigPath() { std::string readExiv2Config(const std::string& section, const std::string& value, const std::string& def) { std::string result = def; - Exiv2::INIReader reader(Exiv2::Internal::getExiv2ConfigPath()); + INIReader reader(Exiv2::Internal::getExiv2ConfigPath()); if (reader.ParseError() == 0) { result = reader.Get(section, value, def); } diff --git a/unitTests/CMakeLists.txt b/unitTests/CMakeLists.txt index 633847fccc..cbb2554bb4 100644 --- a/unitTests/CMakeLists.txt +++ b/unitTests/CMakeLists.txt @@ -42,6 +42,8 @@ target_link_libraries(unit_tests GTest::gtest GTest::gtest_main std::filesystem + inih::libinih + inih::inireader ) # ZLIB is used in exiv2lib_int. From cccf265eabdabe97092701103ef90f838fab3beb Mon Sep 17 00:00:00 2001 From: Kevin Backhouse Date: Wed, 28 Dec 2022 10:44:36 -0500 Subject: [PATCH 2/3] Update .github/workflows/on_PR_windows_matrix.yml --- .github/workflows/on_PR_windows_matrix.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/on_PR_windows_matrix.yml b/.github/workflows/on_PR_windows_matrix.yml index 8f86fb0dd3..f9a345fcab 100644 --- a/.github/workflows/on_PR_windows_matrix.yml +++ b/.github/workflows/on_PR_windows_matrix.yml @@ -115,7 +115,6 @@ jobs: update: true install: >- base-devel - git pacboy: >- cc:p gcc-libs:p From ba258cb1ae0a70f045bc5be68e7d5e18c5cfb263 Mon Sep 17 00:00:00 2001 From: Kevin Backhouse Date: Thu, 29 Dec 2022 13:04:07 -0600 Subject: [PATCH 3/3] cmake fatal error if inih library is not found. --- cmake/Findinih.cmake | 34 ++++++++++++++++++---------------- cmake/findDependencies.cmake | 10 ++++------ src/CMakeLists.txt | 10 ++++------ 3 files changed, 26 insertions(+), 28 deletions(-) diff --git a/cmake/Findinih.cmake b/cmake/Findinih.cmake index 0913d32a92..22fc247019 100644 --- a/cmake/Findinih.cmake +++ b/cmake/Findinih.cmake @@ -24,20 +24,22 @@ mark_as_advanced(inih_inireader_LIBRARY) find_package_handle_standard_args(inih REQUIRED_VARS inih_LIBRARY inih_INCLUDE_DIR) -if(inih_FOUND) - set(inih_INCLUDE_DIRS "${inih_INCLUDE_DIR}") - set(inih_LIBRARIES "${inih_LIBRARY}") - if(NOT TARGET inih::libinih) - add_library(inih::libinih INTERFACE IMPORTED) - endif() - set_property(TARGET inih::libinih PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${inih_INCLUDE_DIRS}") - set_property(TARGET inih::libinih PROPERTY INTERFACE_LINK_LIBRARIES "${inih_LIBRARIES}") - - set(inih_inireader_INCLUDE_DIRS "${inih_inireader_INCLUDE_DIR}") - set(inih_inireader_LIBRARIES "${inih_inireader_LIBRARY}") - if(NOT TARGET inih::inireader) - add_library(inih::inireader INTERFACE IMPORTED) - endif() - set_property(TARGET inih::inireader PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${inih_inireader_INCLUDE_DIRS}") - set_property(TARGET inih::inireader PROPERTY INTERFACE_LINK_LIBRARIES "${inih_inireader_LIBRARIES}") +if(NOT inih_FOUND) + message(FATAL_ERROR "inih library not found") endif() + +set(inih_INCLUDE_DIRS "${inih_INCLUDE_DIR}") +set(inih_LIBRARIES "${inih_LIBRARY}") +if(NOT TARGET inih::libinih) + add_library(inih::libinih INTERFACE IMPORTED) +endif() +set_property(TARGET inih::libinih PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${inih_INCLUDE_DIRS}") +set_property(TARGET inih::libinih PROPERTY INTERFACE_LINK_LIBRARIES "${inih_LIBRARIES}") + +set(inih_inireader_INCLUDE_DIRS "${inih_inireader_INCLUDE_DIR}") +set(inih_inireader_LIBRARIES "${inih_inireader_LIBRARY}") +if(NOT TARGET inih::inireader) + add_library(inih::inireader INTERFACE IMPORTED) +endif() +set_property(TARGET inih::inireader PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${inih_inireader_INCLUDE_DIRS}") +set_property(TARGET inih::inireader PROPERTY INTERFACE_LINK_LIBRARIES "${inih_inireader_LIBRARIES}") diff --git a/cmake/findDependencies.cmake b/cmake/findDependencies.cmake index d3f3f7611c..1e2cff1d46 100644 --- a/cmake/findDependencies.cmake +++ b/cmake/findDependencies.cmake @@ -77,12 +77,10 @@ if( ICONV_FOUND ) endif() find_package(inih) -if( inih_FOUND ) - message ( "-- inih_INCLUDE_DIRS : " ${inih_INCLUDE_DIRS} ) - message ( "-- inih_LIBRARIES : " ${inih_LIBRARIES} ) - message ( "-- inih_inireader_INCLUDE_DIRS : " ${inih_inireader_INCLUDE_DIRS} ) - message ( "-- inih_inireader_LIBRARIES : " ${inih_inireader_LIBRARIES} ) -endif() +message ( "-- inih_INCLUDE_DIRS : " ${inih_INCLUDE_DIRS} ) +message ( "-- inih_LIBRARIES : " ${inih_LIBRARIES} ) +message ( "-- inih_inireader_INCLUDE_DIRS : " ${inih_inireader_INCLUDE_DIRS} ) +message ( "-- inih_inireader_LIBRARIES : " ${inih_inireader_LIBRARIES} ) if( BUILD_WITH_CCACHE ) find_program(CCACHE_FOUND ccache) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9c75e9c843..45599953fb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -248,12 +248,10 @@ if( ICONV_FOUND ) target_link_libraries( exiv2lib PRIVATE Iconv::Iconv ) endif() -if( inih_FOUND ) - target_link_libraries( exiv2lib_int PRIVATE inih::libinih ) - target_link_libraries( exiv2lib_int PRIVATE inih::inireader ) - target_link_libraries( exiv2lib PRIVATE inih::libinih ) - target_link_libraries( exiv2lib PRIVATE inih::inireader ) -endif() +target_link_libraries( exiv2lib_int PRIVATE inih::libinih ) +target_link_libraries( exiv2lib_int PRIVATE inih::inireader ) +target_link_libraries( exiv2lib PRIVATE inih::libinih ) +target_link_libraries( exiv2lib PRIVATE inih::inireader ) write_basic_package_version_file(exiv2ConfigVersion.cmake COMPATIBILITY ExactVersion)