From d3a154ab06f94a39a76705afba92d758132050f2 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Sat, 16 Sep 2023 19:09:48 -0700 Subject: [PATCH] switch from custom stringFormat to fmtlib The latter helps to avoid wrong format errors and is simpler to use. Will be replaced by std::format once C++20 becomes mandatory. Signed-off-by: Rosen Penev --- .github/workflows/codeql-analysis.yml | 4 +- .github/workflows/on_PR_mac_matrix.yml | 1 + .../workflows/on_PR_mac_special_builds.yml | 1 + .github/workflows/on_PR_meson.yaml | 33 +++++++++++- .github/workflows/on_PR_windows_matrix.yml | 54 +------------------ .github/workflows/on_push_BasicWinLinMac.yml | 1 + CMakeLists.txt | 5 ++ ci/install_dependencies.sh | 16 +++--- conanfile.py | 2 + meson.build | 4 ++ src/CMakeLists.txt | 6 +++ src/bmffimage.cpp | 14 ++--- src/futils.cpp | 2 +- src/image.cpp | 9 ++-- src/image_int.cpp | 26 --------- src/image_int.hpp | 17 +++--- src/jp2image.cpp | 7 ++- src/jpgimage.cpp | 6 +-- src/pngimage.cpp | 5 +- src/rafimage.cpp | 52 +++++++++--------- src/webpimage.cpp | 3 +- subprojects/fmt.wrap | 13 +++++ unitTests/CMakeLists.txt | 4 ++ 23 files changed, 133 insertions(+), 152 deletions(-) create mode 100644 subprojects/fmt.wrap diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index a6421f285a..94bfad34b7 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -37,11 +37,11 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 - + - name: Install dependencies run: | sudo apt-get update - sudo apt-get install -y libexpat1-dev zlib1g-dev libbrotli-dev libinih-dev + sudo apt-get install -y libfmt-dev libexpat1-dev zlib1g-dev libbrotli-dev libinih-dev # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/on_PR_mac_matrix.yml b/.github/workflows/on_PR_mac_matrix.yml index 3311f2903e..65bcbd8409 100644 --- a/.github/workflows/on_PR_mac_matrix.yml +++ b/.github/workflows/on_PR_mac_matrix.yml @@ -27,6 +27,7 @@ jobs: run: | brew install ninja brew install inih + brew install fmt brew install googletest - name: Build diff --git a/.github/workflows/on_PR_mac_special_builds.yml b/.github/workflows/on_PR_mac_special_builds.yml index 67e7656253..9673971562 100644 --- a/.github/workflows/on_PR_mac_special_builds.yml +++ b/.github/workflows/on_PR_mac_special_builds.yml @@ -22,6 +22,7 @@ jobs: run: | brew install ninja brew install inih + brew install fmt brew install googletest - name: Build diff --git a/.github/workflows/on_PR_meson.yaml b/.github/workflows/on_PR_meson.yaml index fe4470eae6..ff809ac775 100644 --- a/.github/workflows/on_PR_meson.yaml +++ b/.github/workflows/on_PR_meson.yaml @@ -115,6 +115,7 @@ jobs: cc:p cmake:p curl:p + fmt:p gtest:p libinih:p meson:p @@ -126,6 +127,34 @@ jobs: meson setup "${{github.workspace}}/build" -Dauto_features=${{matrix.deps}} -Dwarning_level=3 -Dcpp_std=c++20 meson compile -C "${{github.workspace}}/build" --verbose meson test -C "${{github.workspace}}/build" --verbose + Cygwin: + runs-on: windows-latest + strategy: + matrix: + deps: ['enabled', 'disabled'] + platform: ['x86', 'x86_64'] + name: Cygwin-${{matrix.platform}}-deps=${{matrix.deps}} + defaults: + run: + shell: C:\cygwin\bin\bash.exe --noprofile --norc -o igncr -eo pipefail '{0}' + steps: + - uses: actions/checkout@v4 + - uses: cygwin/cygwin-install-action@v4 + with: + platform: ${{matrix.platform}} + packages: :> + cmake + gcc-g++ + meson + ninja + pkg-config + python3 + libiconv-devel + - name: Compile and Test + run: | + meson setup build -Dauto_features=${{matrix.deps}} -Dwarning_level=3 -Dcpp_std=c++20 + meson compile -C build --verbose + meson test -C build --verbose MacOS: runs-on: macos-latest name: macOS-deps=${{matrix.deps}} @@ -137,7 +166,7 @@ jobs: - name: Install packages run: | - brew install curl brotli inih expat googletest + brew install fmt curl brotli inih expat googletest python3 -m pip install meson==0.54.1 ninja - name: Compile and Test @@ -154,7 +183,7 @@ jobs: uses: vmactions/freebsd-vm@v1 with: prepare: | - pkg install -y cmake curl ninja meson gettext pkgconf googletest expat inih brotli + pkg install -y cmake curl ninja meson gettext pkgconf googletest expat inih brotli libfmt run: | meson setup "${{github.workspace}}/build" -Dwarning_level=3 -Dcpp_std=c++20 meson compile -C "${{github.workspace}}/build" --verbose diff --git a/.github/workflows/on_PR_windows_matrix.yml b/.github/workflows/on_PR_windows_matrix.yml index 878e80a838..949316b13f 100644 --- a/.github/workflows/on_PR_windows_matrix.yml +++ b/.github/workflows/on_PR_windows_matrix.yml @@ -116,6 +116,7 @@ jobs: libiconv:p libinih:p zlib:p + fmt:p - name: Build run: | @@ -131,56 +132,3 @@ jobs: - name: Test run: | ctest --test-dir build --output-on-failure - - cygwin: - runs-on: windows-latest - strategy: - fail-fast: false - matrix: - build_type: [Release] - shared_libraries: [ON] - platform: [x86_64] - name: Cygwin ${{matrix.platform}} - BuildType:${{matrix.build_type}} - SHARED:${{matrix.shared_libraries}} - env: - SHELLOPTS: igncr - defaults: - run: - shell: C:\cygwin\bin\bash.exe -eo pipefail '{0}' - steps: - # Make sure we don't check out scripts using Windows CRLF line endings - - run: git config --global core.autocrlf input - shell: pwsh - - uses: actions/checkout@v4 - - - name: Set up Cygwin - uses: cygwin/cygwin-install-action@v4 - with: - platform: ${{matrix.platform}} - packages: >- - gcc-g++ - cmake - ninja - pkg-config - python3 - libbrotli-devel - libcurl-devel - libexpat-devel - libiconv-devel - libinih-devel - zlib-devel - - - name: Build - run: | - cmake --preset base_windows \ - -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \ - -DBUILD_SHARED_LIBS=${{matrix.shared_libraries}} \ - -DCONAN_AUTO_INSTALL=OFF \ - -DEXIV2_BUILD_SAMPLES=OFF \ - -DEXIV2_BUILD_UNIT_TESTS=OFF \ - -DEXIV2_TEAM_WARNINGS_AS_ERRORS=OFF \ - -S . -B build && \ - cmake --build build --parallel - - - name: Test - run: | - ctest --test-dir build --output-on-failure diff --git a/.github/workflows/on_push_BasicWinLinMac.yml b/.github/workflows/on_push_BasicWinLinMac.yml index 360175d13d..6b93a6c286 100644 --- a/.github/workflows/on_push_BasicWinLinMac.yml +++ b/.github/workflows/on_push_BasicWinLinMac.yml @@ -93,6 +93,7 @@ jobs: run: | brew install ninja brew install inih + brew install fmt brew install googletest - name: build and compile diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d5ae28dd6..e4e8edb960 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,6 +91,11 @@ endif() include_directories(${CMAKE_BINARY_DIR}) # Make the exv_conf.h file visible for the full project +check_cxx_symbol_exists(__cpp_lib_format "format" HAVE_STD_FORMAT) +if(NOT HAVE_STD_FORMAT) + find_package(fmt REQUIRED) +endif() + if(EXIV2_ENABLE_XMP) add_subdirectory(xmpsdk) endif() diff --git a/ci/install_dependencies.sh b/ci/install_dependencies.sh index aa98275b60..a1add1e1e9 100755 --- a/ci/install_dependencies.sh +++ b/ci/install_dependencies.sh @@ -41,46 +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 ninja-build expat-devel zlib-devel brotli-devel libssh-devel libcurl-devel gmock-devel glibc-langpack-en inih-devel + dnf -y --refresh install gcc-c++ clang cmake ninja-build expat-devel zlib-devel brotli-devel libssh-devel libcurl-devel gmock-devel glibc-langpack-en inih-devel fmt-devel ;; 'debian') apt-get update - apt-get install -y cmake ninja-build g++ clang libexpat1-dev zlib1g-dev libbrotli-dev libssh-dev libcurl4-openssl-dev libgmock-dev libxml2-utils libinih-dev + apt-get install -y cmake ninja-build g++ clang libexpat1-dev zlib1g-dev libbrotli-dev libssh-dev libcurl4-openssl-dev libgmock-dev libxml2-utils libinih-dev libfmt-dev # debian_build_gtest ;; 'arch') pacman --noconfirm -Syu - pacman --noconfirm --needed -S gcc clang cmake ninja expat zlib brotli libssh curl gtest libinih + pacman --noconfirm --needed -S gcc clang cmake ninja expat zlib brotli libssh curl gtest libinih fmt ;; 'ubuntu') apt-get update - apt-get install -y cmake ninja-build g++ clang libexpat1-dev zlib1g-dev libbrotli-dev libssh-dev libcurl4-openssl-dev libgmock-dev libxml2-utils libinih-dev + apt-get install -y cmake ninja-build g++ clang libexpat1-dev zlib1g-dev libbrotli-dev libssh-dev libcurl4-openssl-dev libgmock-dev libxml2-utils libinih-dev libfmt-dev # debian_build_gtest ;; 'alpine') apk update - apk add gcc g++ clang cmake samurai expat-dev zlib-dev brotli-dev libssh-dev curl-dev gtest gtest-dev gmock libintl gettext-dev libxml2-utils inih-dev inih-inireader-dev + apk add gcc g++ clang cmake samurai expat-dev zlib-dev brotli-dev libssh-dev curl-dev gtest gtest-dev gmock libintl gettext-dev libxml2-utils inih-dev inih-inireader-dev fmt-dev ;; 'rhel') dnf clean all - dnf -y install gcc-c++ clang cmake ninja-build expat-devel zlib-devel brotli-devel libssh-devel libcurl-devel inih-devel + dnf -y install gcc-c++ clang cmake ninja-build expat-devel zlib-devel brotli-devel libssh-devel libcurl-devel inih-devel fmt-devel ;; 'centos') dnf clean all - dnf -y install gcc-c++ clang cmake expat-devel zlib-devel brotli-devel libssh-devel libcurl-devel git + dnf -y install gcc-c++ clang cmake expat-devel zlib-devel brotli-devel libssh-devel libcurl-devel git fmt-devel dnf -y --enablerepo=crb install ninja-build meson centos_build_inih ;; 'opensuse-tumbleweed') zypper --non-interactive refresh - zypper --non-interactive install gcc-c++ clang cmake ninja libexpat-devel zlib-devel libbrotli-devel libssh-devel libcurl-devel gmock libxml2-tools libinih-devel + zypper --non-interactive install gcc-c++ clang cmake ninja libexpat-devel zlib-devel libbrotli-devel libssh-devel libcurl-devel gmock libxml2-tools libinih-devel libfmt-devel ;; *) echo "Sorry, no predefined dependencies for your distribution $distro_id exist yet" diff --git a/conanfile.py b/conanfile.py index 3d869d831b..7c85117a10 100644 --- a/conanfile.py +++ b/conanfile.py @@ -27,6 +27,8 @@ def requirements(self): self.requires('inih/55') + self.requires('fmt/10.1.1') + if self.options.webready: self.requires('libcurl/7.85.0') diff --git a/meson.build b/meson.build index f0142ed7d9..88d8732633 100644 --- a/meson.build +++ b/meson.build @@ -54,6 +54,10 @@ deps = [] deps += cpp.find_library('ws2_32', required: host_machine.system() == 'windows') deps += cpp.find_library('procstat', required: host_machine.system() == 'freebsd') +if not cpp.has_header_symbol('format', '__cpp_lib_format') + deps += dependency('fmt') +endif + if cpp.get_argument_syntax() == 'gcc' and cpp.version().version_compare('<9') if host_machine.system() == 'linux' and cpp.get_define('_LIBCPP_VERSION', prefix: '#include ') == '' deps += cpp.find_library('stdc++fs') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4c92f3dfc5..63ede2a785 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -250,6 +250,12 @@ else() target_link_libraries(exiv2lib PRIVATE psapi ws2_32 shell32) endif() +if(NOT HAVE_STD_FORMAT) + target_link_libraries(exiv2lib PRIVATE fmt::fmt) + target_link_libraries(exiv2lib_int PRIVATE fmt::fmt) + list(APPEND requires_private_list "fmt") +endif() + if(EXIV2_ENABLE_PNG) target_link_libraries(exiv2lib PRIVATE ZLIB::ZLIB) list(APPEND requires_private_list "zlib") diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index ad084ea2a4..60eca65343 100644 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -81,7 +81,7 @@ bool enableBMFF(bool enable) { } std::string Iloc::toString() const { - return Internal::stringFormat("ID = %u from,length = %u,%u", ID_, start_, length_); + return stringFormat("ID = {} from,length = {},{}", ID_, start_, length_); } BmffImage::BmffImage(BasicIo::UniquePtr io, bool /* create */) : @@ -269,7 +269,7 @@ uint64_t BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintS if (bTrace) { bLF = true; out << Internal::indent(depth) << "Exiv2::BmffImage::boxHandler: " << toAscii(box_type) - << Internal::stringFormat(" %8zd->%" PRIu64 " ", address, box_length); + << stringFormat(" {:8}->{} ", address, box_length); } if (box_length == 1) { @@ -366,7 +366,7 @@ uint64_t BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintS id = " *** XMP ***"; } if (bTrace) { - out << Internal::stringFormat("ID = %3d ", ID) << name << " " << id; + out << stringFormat("ID = {:3} {} {}", ID, name, id); } } break; @@ -444,7 +444,7 @@ uint64_t BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintS uint32_t ldata = data.read_uint32(skip + step - 4, endian_); if (bTrace) { out << Internal::indent(depth) - << Internal::stringFormat("%8zd | %8zd | ID | %4u | %6u,%6u", address + skip, step, ID, offset, ldata) + << stringFormat("{:8} | {:8} | ID | {:4} | {:6},{:6}", address + skip, step, ID, offset, ldata) << std::endl; } // save data for post-processing in meta box @@ -463,7 +463,7 @@ uint64_t BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintS uint32_t height = data.read_uint32(skip, endian_); skip += 4; if (bTrace) { - out << "pixelWidth_, pixelHeight_ = " << Internal::stringFormat("%d, %d", width, height); + out << stringFormat("pixelWidth_, pixelHeight_ = {}, {}", width, height); } // HEIC files can have multiple ispe records // Store largest width/height @@ -678,8 +678,8 @@ void BmffImage::parseCr3Preview(const DataBuf& data, std::ostream& out, bool bTr return "application/octet-stream"; }(); if (bTrace) { - out << Internal::stringFormat("width,height,size = %zu,%zu,%zu", nativePreview.width_, nativePreview.height_, - nativePreview.size_); + out << stringFormat("width,height,size = {},{},{}", nativePreview.width_, nativePreview.height_, + nativePreview.size_); } nativePreviews_.push_back(std::move(nativePreview)); } diff --git a/src/futils.cpp b/src/futils.cpp index 98bf8db787..88408cc016 100644 --- a/src/futils.cpp +++ b/src/futils.cpp @@ -373,7 +373,7 @@ std::string getProcessPath() { return "unknown"; // pathbuf not big enough auto path = fs::path(pathbuf); #elif defined(__sun__) - auto path = fs::read_symlink(Internal::stringFormat("/proc/%d/path/a.out", getpid())); + auto path = fs::read_symlink(stringFormat("/proc/%d/path/a.out", getpid())); #elif defined(__unix__) auto path = fs::read_symlink("/proc/self/exe"); #endif diff --git a/src/image.cpp b/src/image.cpp index f3c8e03bd2..efdcdfdadd 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -350,8 +350,7 @@ void Image::printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStruct throw Error(ErrorCode::kerTiffDirectoryTooLarge); if (bFirst && bPrint) { - out << Internal::indent(depth) << Internal::stringFormat("STRUCTURE OF TIFF FILE (%c%c): ", c, c) << io.path() - << std::endl; + out << Internal::indent(depth) << stringFormat("STRUCTURE OF TIFF FILE ({}{}): {}", c, c, io.path()) << std::endl; } // Read the dictionary @@ -435,11 +434,11 @@ void Image::printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStruct if (bPrint) { const size_t address = start + 2 + i * 12; - const std::string offsetString = bOffsetIsPointer ? Internal::stringFormat("%10u", offset) : ""; + const std::string offsetString = bOffsetIsPointer ? stringFormat("{:9}", offset) : ""; out << Internal::indent(depth) - << Internal::stringFormat("%8zu | %#06x %-28s |%10s |%9u |%10s | ", address, tag, tagName(tag).c_str(), - typeName(type), count, offsetString.c_str()); + << stringFormat("{:8} | {:#06x} {:<28} | {:>9} | {:>8} | {:9} | ", address, tag, tagName(tag).c_str(), + typeName(type), count, offsetString); if (isShortType(type)) { for (size_t k = 0; k < kount; k++) { out << sp << byteSwap2(buf, k * size, bSwap); diff --git a/src/image_int.cpp b/src/image_int.cpp index bd3b3773cd..a253a76a9a 100644 --- a/src/image_int.cpp +++ b/src/image_int.cpp @@ -9,32 +9,6 @@ #include namespace Exiv2::Internal { -std::string stringFormat(const char* format, ...) { - std::string result; - std::vector buffer; - size_t need = std::strlen(format) * 8; // initial guess - int rc = -1; - - // vsnprintf writes at most size (2nd parameter) bytes (including \0) - // returns the number of bytes required for the formatted string excluding \0 - // the following loop goes through: - // one iteration (if 'need' was large enough for the for formatted string) - // or two iterations (after the first call to vsnprintf we know the required length) - do { - buffer.resize(need + 1); - va_list args; // variable arg list - va_start(args, format); // args start after format - rc = vsnprintf(buffer.data(), buffer.size(), format, args); - va_end(args); // free the args - if (rc > 0) - need = static_cast(rc); - } while (buffer.size() <= need); - - if (rc > 0) - result = std::string(buffer.data(), need); - return result; -} - [[nodiscard]] std::string indent(size_t i) { return std::string(2 * i, ' '); } diff --git a/src/image_int.hpp b/src/image_int.hpp index 75e6428fb6..8dbe43d381 100644 --- a/src/image_int.hpp +++ b/src/image_int.hpp @@ -12,12 +12,14 @@ #include // for ostream, basic_ostream::put #include -#if defined(__MINGW32__) -#define ATTRIBUTE_FORMAT_PRINTF __attribute__((format(__MINGW_PRINTF_FORMAT, 1, 2))) -#elif defined(__GNUC__) -#define ATTRIBUTE_FORMAT_PRINTF __attribute__((format(printf, 1, 2))) +#if __has_include() +#include +#endif +#ifndef __cpp_lib_format +#include +#define stringFormat fmt::format #else -#define ATTRIBUTE_FORMAT_PRINTF +#define stringFormat std::format #endif // ***************************************************************************** @@ -26,11 +28,6 @@ namespace Exiv2::Internal { // ***************************************************************************** // class definitions -/*! - @brief format a string in the pattern of \em sprintf \em . - */ -std::string stringFormat(const char* format, ...) ATTRIBUTE_FORMAT_PRINTF; - /*! * @brief Helper struct for binary data output via @ref binaryToString. * diff --git a/src/jp2image.cpp b/src/jp2image.cpp index 37b9a60b57..4c94fee803 100644 --- a/src/jp2image.cpp +++ b/src/jp2image.cpp @@ -411,8 +411,7 @@ void Jp2Image::printStructure(std::ostream& out, PrintStructureOption option, si Internal::enforce(box.length <= boxHSize + io_->size() - io_->tell(), ErrorCode::kerCorruptedMetadata); if (bPrint) { - out << Internal::stringFormat("%8zd | %8zd | ", position - boxHSize, static_cast(box.length)) - << toAscii(box.type) << " | "; + out << stringFormat("{:8} | {:8} | {} | ", position - boxHSize, box.length, toAscii(box.type)); bLF = true; if (box.type == kJp2BoxTypeClose) lf(out, bLF); @@ -454,8 +453,8 @@ void Jp2Image::printStructure(std::ostream& out, PrintStructureOption option, si DataBuf data(subBox.length - boxHSize); io_->read(data.data(), data.size()); if (bPrint) { - out << Internal::stringFormat("%8zu | %8u | sub:", address, subBox.length) << toAscii(subBox.type) - << " | " << Internal::binaryToString(makeSlice(data, 0, std::min(30, data.size()))); + out << stringFormat("{:8} | {:8} | sub:{} | ", address, subBox.length, toAscii(subBox.type)) + << Internal::binaryToString(makeSlice(data, 0, std::min(30, data.size()))); bLF = true; } diff --git a/src/jpgimage.cpp b/src/jpgimage.cpp index 22646af189..2fbd1bac30 100644 --- a/src/jpgimage.cpp +++ b/src/jpgimage.cpp @@ -294,7 +294,7 @@ void JpegBase::readMetadata() { #define REPORT_MARKER \ if ((option == kpsBasic || option == kpsRecursive)) \ - out << Internal::stringFormat("%8zd | 0xff%02x %-5s", io_->tell() - 2, marker, nm[marker].c_str()) + out << stringFormat("{:8} | 0xff{:02x} {:<5}", io_->tell() - 2, marker, nm[marker].c_str()) void JpegBase::printStructure(std::ostream& out, PrintStructureOption option, size_t depth) { if (io_->open() != 0) @@ -360,7 +360,7 @@ void JpegBase::printStructure(std::ostream& out, PrintStructureOption option, si } if (bPrint && markerHasLength(marker)) - out << Internal::stringFormat(" | %7d ", size); + out << stringFormat(" | {:7} ", size); // print signature for APPn if (marker >= app0_ && marker <= (app0_ | 0x0F)) { @@ -433,7 +433,7 @@ void JpegBase::printStructure(std::ostream& out, PrintStructureOption option, si enforce(size >= 16, "Buffer too small to extract chunk information."); const int chunk = buf.read_uint8(2 + 12); const int chunks = buf.read_uint8(2 + 13); - out << Internal::stringFormat(" chunk %d/%d", chunk, chunks); + out << stringFormat(" chunk {}/{}", chunk, chunks); } } diff --git a/src/pngimage.cpp b/src/pngimage.cpp index a78839e883..ae40289bb7 100644 --- a/src/pngimage.cpp +++ b/src/pngimage.cpp @@ -256,9 +256,8 @@ void PngImage::printStructure(std::ostream& out, PrintStructureOption option, si enforce(bufRead == 4, ErrorCode::kerFailedToReadImageData); io_->seek(restore, BasicIo::beg); // restore file pointer - out << Internal::stringFormat("%8d | %-5s |%8d | ", static_cast(address), chType, dataOffset) - << dataString - << Internal::stringFormat(" | 0x%02x%02x%02x%02x", checksum[0], checksum[1], checksum[2], checksum[3]) + out << stringFormat("{:8} | {:<5} |{:8} | {}", address, chType, dataOffset, dataString) + << stringFormat(" | 0x{:02x}{:02x}{:02x}{:02x}", checksum[0], checksum[1], checksum[2], checksum[3]) << std::endl; } diff --git a/src/rafimage.cpp b/src/rafimage.cpp index 3ad906a68e..c8668b5309 100644 --- a/src/rafimage.cpp +++ b/src/rafimage.cpp @@ -72,7 +72,7 @@ void RafImage::printStructure(std::ostream& out, PrintStructureOption option, si if (bPrint) { io_->seek(0, BasicIo::beg); // rewind size_t address = io_->tell(); - constexpr auto format = " %9zu | %9" PRIu32 " | "; + constexpr auto format = " {:8} | {:8} | "; { out << Internal::indent(depth) << "STRUCTURE OF RAF FILE: " << io().path() << std::endl; @@ -83,7 +83,7 @@ void RafImage::printStructure(std::ostream& out, PrintStructureOption option, si io_->readOrThrow(magicdata, 16); magicdata[16] = 0; { - out << Internal::indent(depth) << Internal::stringFormat(format, address, 16U) // 0 + out << Internal::indent(depth) << stringFormat(format, address, 16) // 0 << " magic : " << reinterpret_cast(magicdata) << std::endl; } @@ -92,7 +92,7 @@ void RafImage::printStructure(std::ostream& out, PrintStructureOption option, si io_->read(data1, 4); data1[4] = 0; { - out << Internal::indent(depth) << Internal::stringFormat(format, address, 4U) // 16 + out << Internal::indent(depth) << stringFormat(format, address, 4) // 16 << " data1 : " << std::string(reinterpret_cast(&data1)) << std::endl; } @@ -101,7 +101,7 @@ void RafImage::printStructure(std::ostream& out, PrintStructureOption option, si io_->read(data2, 8); data2[8] = 0; { - out << Internal::indent(depth) << Internal::stringFormat(format, address, 8U) // 20 + out << Internal::indent(depth) << stringFormat(format, address, 8) // 20 << " data2 : " << std::string(reinterpret_cast(&data2)) << std::endl; } @@ -110,7 +110,7 @@ void RafImage::printStructure(std::ostream& out, PrintStructureOption option, si io_->read(camdata, 32); camdata[32] = 0; { - out << Internal::indent(depth) << Internal::stringFormat(format, address, 32U) // 28 + out << Internal::indent(depth) << stringFormat(format, address, 32) // 28 << " camera : " << std::string(reinterpret_cast(&camdata)) << std::endl; } @@ -119,7 +119,7 @@ void RafImage::printStructure(std::ostream& out, PrintStructureOption option, si io_->read(dir_version, 4); dir_version[4] = 0; { - out << Internal::indent(depth) << Internal::stringFormat(format, address, 4U) // 60 + out << Internal::indent(depth) << stringFormat(format, address, 4) // 60 << " version : " << std::string(reinterpret_cast(&dir_version)) << std::endl; } @@ -127,7 +127,7 @@ void RafImage::printStructure(std::ostream& out, PrintStructureOption option, si DataBuf unknown(20); io_->readOrThrow(unknown.data(), unknown.size()); { - out << Internal::indent(depth) << Internal::stringFormat(format, address, 20U) + out << Internal::indent(depth) << stringFormat(format, address, 20) << " unknown : " << Internal::binaryToString(makeSlice(unknown, 0, unknown.size())) << std::endl; } @@ -145,9 +145,9 @@ void RafImage::printStructure(std::ostream& out, PrintStructureOption option, si std::stringstream j_len; j_off << jpg_img_off; j_len << jpg_img_len; - out << Internal::indent(depth) << Internal::stringFormat(format, address, 4U) << " JPEG offset : " << j_off.str() + out << Internal::indent(depth) << stringFormat(format, address, 4) << " JPEG offset : " << j_off.str() << std::endl; - out << Internal::indent(depth) << Internal::stringFormat(format, address2, 4U) << " JPEG length : " << j_len.str() + out << Internal::indent(depth) << stringFormat(format, address2, 4) << " JPEG length : " << j_len.str() << std::endl; } @@ -167,10 +167,10 @@ void RafImage::printStructure(std::ostream& out, PrintStructureOption option, si std::stringstream c_len; c_off << meta_off[i]; c_len << meta_len[i]; - out << Internal::indent(depth) << Internal::stringFormat(format, address, 4U) << "meta offset" << i + 1 << " : " + out << Internal::indent(depth) << stringFormat(format, address, 4) << "meta offset" << i + 1 << " : " << c_off.str() << std::endl; - out << Internal::indent(depth) << Internal::stringFormat(format, address2, 4U) << "meta length" << i + 1 - << " : " << c_len.str() << std::endl; + out << Internal::indent(depth) << stringFormat(format, address2, 4) << "meta length" << i + 1 << " : " + << c_len.str() << std::endl; } address = io_->tell(); @@ -199,16 +199,16 @@ void RafImage::printStructure(std::ostream& out, PrintStructureOption option, si c_skip << cfa_skip[i]; c_size << cfa_size[i]; c_stride << cfa_stride[i]; - out << Internal::indent(depth) << Internal::stringFormat(format, address, 4U) << " CFA offset" << i + 1 << " : " + out << Internal::indent(depth) << stringFormat(format, address, 4) << " CFA offset" << i + 1 << " : " << c_off.str() << std::endl; - out << Internal::indent(depth) << Internal::stringFormat(format, address2, 4U) << " CFA length" << i + 1 - << " : " << c_len.str() << std::endl; - out << Internal::indent(depth) << Internal::stringFormat(format, address3, 4U) << " CFA skip" << i + 1 - << " : " << c_skip.str() << std::endl; - out << Internal::indent(depth) << Internal::stringFormat(format, address4, 4U) << " CFA chunk" << i + 1 - << " : " << c_size.str() << std::endl; - out << Internal::indent(depth) << Internal::stringFormat(format, address5, 4U) << " CFA stride" << i + 1 - << " : " << c_stride.str() << std::endl; + out << Internal::indent(depth) << stringFormat(format, address2, 4) << " CFA length" << i + 1 << " : " + << c_len.str() << std::endl; + out << Internal::indent(depth) << stringFormat(format, address3, 4) << " CFA skip" << i + 1 << " : " + << c_skip.str() << std::endl; + out << Internal::indent(depth) << stringFormat(format, address4, 4) << " CFA chunk" << i + 1 << " : " + << c_size.str() << std::endl; + out << Internal::indent(depth) << stringFormat(format, address5, 4) << " CFA stride" << i + 1 << " : " + << c_stride.str() << std::endl; } } @@ -217,7 +217,7 @@ void RafImage::printStructure(std::ostream& out, PrintStructureOption option, si DataBuf payload(16); // header is different from chunks io_->readOrThrow(payload.data(), payload.size()); { - out << Internal::indent(depth) << Internal::stringFormat(format, address, jpg_img_len) + out << Internal::indent(depth) << stringFormat(format, address, jpg_img_len) << " JPEG data : " << Internal::binaryToString(makeSlice(payload, 0, payload.size())) << std::endl; } @@ -225,7 +225,7 @@ void RafImage::printStructure(std::ostream& out, PrintStructureOption option, si address = io_->tell(); io_->readOrThrow(payload.data(), payload.size()); { - out << Internal::indent(depth) << Internal::stringFormat(format, address, meta_len[0]) + out << Internal::indent(depth) << stringFormat(format, address, meta_len[0]) << " meta data1 : " << Internal::binaryToString(makeSlice(payload, 0, payload.size())) << std::endl; } @@ -234,7 +234,7 @@ void RafImage::printStructure(std::ostream& out, PrintStructureOption option, si address = io_->tell(); io_->readOrThrow(payload.data(), payload.size()); { - out << Internal::indent(depth) << Internal::stringFormat(format, address, meta_len[1]) + out << Internal::indent(depth) << stringFormat(format, address, meta_len[1]) << " meta data2 : " << Internal::binaryToString(makeSlice(payload, 0, payload.size())) << std::endl; } } @@ -243,7 +243,7 @@ void RafImage::printStructure(std::ostream& out, PrintStructureOption option, si address = io_->tell(); io_->readOrThrow(payload.data(), payload.size()); { - out << Internal::indent(depth) << Internal::stringFormat(format, address, cfa_len[0]) + out << Internal::indent(depth) << stringFormat(format, address, cfa_len[0]) << " CFA data1 : " << Internal::binaryToString(makeSlice(payload, 0, payload.size())) << std::endl; } @@ -252,7 +252,7 @@ void RafImage::printStructure(std::ostream& out, PrintStructureOption option, si address = io_->tell(); io_->readOrThrow(payload.data(), payload.size()); { - out << Internal::indent(depth) << Internal::stringFormat(format, address, cfa_len[1]) // cfa_off + out << Internal::indent(depth) << stringFormat(format, address, cfa_len[1]) // cfa_off << " CFA data2 : " << Internal::binaryToString(makeSlice(payload, 0, payload.size())) << std::endl; } } diff --git a/src/webpimage.cpp b/src/webpimage.cpp index f8d0f463ee..e76dea2421 100644 --- a/src/webpimage.cpp +++ b/src/webpimage.cpp @@ -433,8 +433,7 @@ void WebPImage::printStructure(std::ostream& out, PrintStructureOption option, s io_->read(payload.data(), payload.size()); if (bPrint) { - out << Internal::indent(depth) - << Internal::stringFormat(" %s | %8u | %8u | ", chunkId.c_str(), size, static_cast(offset)) + out << Internal::indent(depth) << stringFormat(" {} | {:8} | {:8} | ", chunkId.c_str(), size, offset) << Internal::binaryToString(makeSlice(payload, 0, payload.size() > 32 ? 32 : payload.size())) << std::endl; } diff --git a/subprojects/fmt.wrap b/subprojects/fmt.wrap new file mode 100644 index 0000000000..bc109cc3b0 --- /dev/null +++ b/subprojects/fmt.wrap @@ -0,0 +1,13 @@ +[wrap-file] +directory = fmt-10.1.1 +source_url = https://github.com/fmtlib/fmt/archive/10.1.1.tar.gz +source_filename = fmt-10.1.1.tar.gz +source_hash = 78b8c0a72b1c35e4443a7e308df52498252d1cefc2b08c9a97bc9ee6cfe61f8b +patch_filename = fmt_10.1.1-1_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/fmt_10.1.1-1/get_patch +patch_hash = adec33acaf87c0859c52b242a44bc71c3427751da3f1adaed511f4186794a42f +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/fmt_10.1.1-1/fmt-10.1.1.tar.gz +wrapdb_version = 10.1.1-1 + +[provide] +fmt = fmt_dep diff --git a/unitTests/CMakeLists.txt b/unitTests/CMakeLists.txt index 0f7c505eb2..f68fbc8e22 100644 --- a/unitTests/CMakeLists.txt +++ b/unitTests/CMakeLists.txt @@ -44,6 +44,10 @@ target_compile_definitions(unit_tests PRIVATE exiv2lib_STATIC TESTDATA_PATH="${P target_link_libraries(unit_tests PRIVATE exiv2lib GTest::gmock_main std::filesystem) +if(NOT HAVE_STD_FORMAT) + target_link_libraries(unit_tests PRIVATE fmt::fmt) +endif() + if(EXIV2_ENABLE_INIH) target_link_libraries(unit_tests PRIVATE inih::libinih inih::inireader) endif()