Merge remote-tracking branch 'origin'

main
Viktor Schneider 3 years ago
commit 73a1a0ec21

@ -53,7 +53,7 @@ predicate indexK_with_fixedarray(ClassTemplateInstantiation t, ArrayIndexCall ca
t.getSimpleName() = "array" and t.getSimpleName() = "array" and
idx = call.getArgument(0) and idx = call.getArgument(0) and
lowerBound(idx) >= 0 and lowerBound(idx) >= 0 and
upperBound(idx) < t.getTemplateArgument(1).(Literal).getValue().toInt() upperBound(idx) < lowerBound(t.getTemplateArgument(1))
) )
} }

@ -2,6 +2,9 @@
# https://google.github.io/oss-fuzz/getting-started/continuous-integration/ # https://google.github.io/oss-fuzz/getting-started/continuous-integration/
name: CIFuzz name: CIFuzz
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on: on:
pull_request: pull_request:
paths-ignore: paths-ignore:

@ -5,6 +5,10 @@
# or to provide custom queries or build logic. # or to provide custom queries or build logic.
name: "CodeQL" name: "CodeQL"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on: on:
push: push:
branches: [0.27-maintenance, main] branches: [0.27-maintenance, main]

@ -6,6 +6,10 @@ on:
schedule: schedule:
- cron: 0 4 * * * - cron: 0 4 * * *
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
name: Nightly - Linux distributions name: Nightly - Linux distributions
jobs: jobs:

@ -4,6 +4,10 @@
name: On PRs - Linux-Ubuntu Quick Fuzz name: On PRs - Linux-Ubuntu Quick Fuzz
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on: on:
pull_request: pull_request:
paths-ignore: paths-ignore:
@ -24,18 +28,8 @@ jobs:
- name: build and compile - name: build and compile
run: | run: |
mkdir build && cd build && \ cmake --preset linux-sanitizers -S . -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=$(which clang++) -DEXIV2_BUILD_FUZZ_TESTS=ON -DEXIV2_BUILD_UNIT_TESTS=OFF
cmake -GNinja -DEXIV2_ENABLE_PNG=ON \ cmake --build build --parallel
-DEXIV2_BUILD_SAMPLES=ON \
-DEXIV2_ENABLE_WEBREADY=ON \
-DEXIV2_ENABLE_CURL=ON \
-DEXIV2_ENABLE_BMFF=ON \
-DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON \
-DCMAKE_CXX_COMPILER=$(which clang++) \
-DEXIV2_BUILD_FUZZ_TESTS=ON \
-DEXIV2_TEAM_USE_SANITIZERS=ON \
.. && \
cmake --build . --parallel
- name: Fuzz - name: Fuzz
run: | run: |

@ -1,5 +1,9 @@
name: On PRs - Linux-Ubuntu Matrix name: On PRs - Linux-Ubuntu Matrix
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on: on:
pull_request: pull_request:
paths-ignore: paths-ignore:
@ -22,7 +26,7 @@ jobs:
- name: install dependencies - name: install dependencies
run: | run: |
sudo apt-get install ninja-build sudo apt-get install ninja-build
pip3 install conan==1.45.0 pip3 install conan==1.48.1
- name: Conan common config - name: Conan common config
run: | run: |
@ -39,20 +43,8 @@ jobs:
- name: Build - name: Build
run: | run: |
cd build && \ cmake --preset base_linux -S . -B build -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DBUILD_SHARED_LIBS=${{matrix.shared_libraries}}
cmake -GNinja \ cmake --build build --parallel
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
-DBUILD_SHARED_LIBS=${{matrix.shared_libraries}} \
-DEXIV2_BUILD_SAMPLES=ON \
-DEXIV2_ENABLE_PNG=ON \
-DEXIV2_ENABLE_WEBREADY=ON \
-DEXIV2_ENABLE_CURL=ON \
-DEXIV2_BUILD_UNIT_TESTS=ON \
-DEXIV2_ENABLE_BMFF=ON \
-DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON \
-DCMAKE_INSTALL_PREFIX=install \
.. && \
cmake --build . --parallel
- name: Install - name: Install
run: | run: |

@ -1,5 +1,9 @@
name: On PRs - Linux Special Builds name: On PRs - Linux Special Builds
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on: on:
workflow_dispatch: workflow_dispatch:
pull_request: pull_request:
@ -20,7 +24,7 @@ jobs:
- name: install dependencies - name: install dependencies
run: | run: |
sudo apt-get install ninja-build sudo apt-get install ninja-build
pip3 install conan==1.45.0 pip3 install conan==1.48.1
pip3 install gcovr pip3 install gcovr
- name: Conan common config - name: Conan common config
@ -37,21 +41,8 @@ jobs:
- name: Build - name: Build
run: | run: |
cd build && \ cmake --preset linux-coverage -S . -B build
cmake -GNinja \ cmake --build build --parallel
-DCMAKE_BUILD_TYPE=Debug \
-DBUILD_SHARED_LIBS=ON \
-DEXIV2_ENABLE_PNG=ON \
-DEXIV2_ENABLE_WEBREADY=ON \
-DEXIV2_ENABLE_CURL=ON \
-DEXIV2_BUILD_UNIT_TESTS=ON \
-DEXIV2_ENABLE_BMFF=ON \
-DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON \
-DEXIV2_BUILD_SAMPLES=ON \
-DBUILD_WITH_COVERAGE=ON \
-DCMAKE_INSTALL_PREFIX=install \
.. && \
cmake --build . --parallel
- name: Tests + Upload coverage - name: Tests + Upload coverage
run: | run: |
@ -78,9 +69,8 @@ jobs:
- name: install dependencies - name: install dependencies
run: | run: |
sudo apt-get update
sudo apt-get install valgrind ninja-build sudo apt-get install valgrind ninja-build
pip3 install conan==1.45.0 pip3 install conan==1.48.1
- name: Conan common config - name: Conan common config
run: | run: |
@ -96,9 +86,8 @@ jobs:
- name: Build - name: Build
run: | run: |
cd build cmake --preset linux-release -S . -B build
cmake -GNinja -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DEXIV2_ENABLE_PNG=ON -DEXIV2_ENABLE_WEBREADY=ON -DEXIV2_ENABLE_CURL=ON -DEXIV2_BUILD_UNIT_TESTS=ON -DEXIV2_ENABLE_BMFF=ON -DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON -DBUILD_WITH_COVERAGE=OFF -DCMAKE_INSTALL_PREFIX=install .. cmake --build build --parallel
cmake --build . --parallel
- name: Tests with valgrind - name: Tests with valgrind
run: | run: |
@ -116,7 +105,7 @@ jobs:
- name: install dependencies - name: install dependencies
run: | run: |
sudo apt-get install ninja-build sudo apt-get install ninja-build
pip3 install conan==1.45.0 pip3 install conan==1.48.1
- name: Conan common config - name: Conan common config
run: | run: |
@ -132,22 +121,8 @@ jobs:
- name: Build - name: Build
run: | run: |
cd build && \ cmake --preset linux-sanitizers -S . -B build
cmake -GNinja \ cmake --build build --parallel
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_SHARED_LIBS=ON \
-DEXIV2_BUILD_SAMPLES=ON \
-DEXIV2_ENABLE_PNG=ON \
-DEXIV2_ENABLE_WEBREADY=ON \
-DEXIV2_ENABLE_CURL=ON \
-DEXIV2_BUILD_UNIT_TESTS=ON \
-DEXIV2_ENABLE_BMFF=ON \
-DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON \
-DBUILD_WITH_COVERAGE=OFF \
-DEXIV2_TEAM_USE_SANITIZERS=ON \
-DCMAKE_INSTALL_PREFIX=install \
.. && \
cmake --build . --parallel
- name: Tests - name: Tests
run: | run: |
@ -163,9 +138,8 @@ jobs:
- name: install dependencies - name: install dependencies
run: | run: |
sudo apt-get update sudo apt-get install valgrind doxygen graphviz gettext ninja-build
sudo apt-get install valgrind doxygen graphviz gettext pip3 install conan==1.48.1
pip3 install conan==1.45.0
- name: Conan common config - name: Conan common config
run: | run: |
@ -181,22 +155,8 @@ jobs:
- name: Build - name: Build
run: | run: |
cd build && \ cmake --preset linux-release -S . -B build -DEXIV2_BUILD_DOC=ON -DCMAKE_CXX_FLAGS="-DEXIV2_DEBUG_MESSAGES"
cmake -DCMAKE_BUILD_TYPE=Release \ cmake --build build --parallel
-DBUILD_SHARED_LIBS=ON \
-DEXIV2_BUILD_SAMPLES=ON \
-DEXIV2_ENABLE_PNG=ON \
-DEXIV2_ENABLE_WEBREADY=ON \
-DEXIV2_ENABLE_CURL=ON \
-DEXIV2_BUILD_UNIT_TESTS=ON \
-DEXIV2_ENABLE_BMFF=ON \
-DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON \
-DBUILD_WITH_COVERAGE=ON \
-DEXIV2_BUILD_DOC=ON \
-DEXIV2_ENABLE_NLS=ON \
-DCMAKE_CXX_FLAGS="-DEXIV2_DEBUG_MESSAGES" \
.. && \
cmake --build . --parallel
- name: Generate documentation - name: Generate documentation
run: | run: |

@ -1,5 +1,9 @@
name: On PRs - Linux - Static Analysis name: On PRs - Linux - Static Analysis
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on: on:
workflow_dispatch: workflow_dispatch:
pull_request: pull_request:
@ -19,7 +23,7 @@ jobs:
- name: install dependencies - name: install dependencies
run: | run: |
pip3 install conan==1.45.0 pip3 install conan==1.48.1
sudo add-apt-repository ppa:ubuntu-lxc/daily -y sudo add-apt-repository ppa:ubuntu-lxc/daily -y
wget -q -O - https://files.pvs-studio.com/etc/pubkey.txt |sudo apt-key add - wget -q -O - https://files.pvs-studio.com/etc/pubkey.txt |sudo apt-key add -
sudo wget -O /etc/apt/sources.list.d/viva64.list https://files.pvs-studio.com/etc/viva64.list sudo wget -O /etc/apt/sources.list.d/viva64.list https://files.pvs-studio.com/etc/viva64.list
@ -40,19 +44,7 @@ jobs:
- name: Configure - name: Configure
run: | run: |
cd build && \ cmake --preset linux-debug-NoConan -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
cmake -DCMAKE_BUILD_TYPE=Debug \
-DBUILD_SHARED_LIBS=ON \
-DEXIV2_ENABLE_PNG=ON \
-DEXIV2_ENABLE_WEBREADY=ON \
-DEXIV2_ENABLE_CURL=ON \
-DEXIV2_BUILD_UNIT_TESTS=ON \
-DEXIV2_ENABLE_BMFF=ON \
-DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON \
-DBUILD_WITH_COVERAGE=ON \
-DCMAKE_INSTALL_PREFIX=install \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
.. \
- name: Static Analysis - name: Static Analysis
env: env:

@ -1,5 +1,9 @@
name: On PRs - Mac Matrix name: On PRs - Mac Matrix
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on: on:
pull_request: pull_request:
paths-ignore: paths-ignore:
@ -33,21 +37,8 @@ jobs:
- name: Build - name: Build
run: | run: |
mkdir build && cd build && \ cmake --preset base_mac -S . -B build -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DBUILD_SHARED_LIBS=${{matrix.shared_libraries}} -DCMAKE_CXX_FLAGS="-Wno-deprecated-declarations"
cmake -GNinja \ cmake --build build --parallel
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
-DBUILD_SHARED_LIBS=${{matrix.shared_libraries}} \
-DEXIV2_BUILD_SAMPLES=ON \
-DEXIV2_ENABLE_PNG=ON \
-DEXIV2_ENABLE_WEBREADY=ON \
-DEXIV2_ENABLE_CURL=ON \
-DEXIV2_BUILD_UNIT_TESTS=ON \
-DEXIV2_ENABLE_BMFF=ON \
-DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON \
-DCMAKE_INSTALL_PREFIX=install \
-DCMAKE_CXX_FLAGS="-Wno-deprecated-declarations" \
.. && \
cmake --build . --parallel
- name: Install - name: Install
run: | run: |

@ -1,5 +1,9 @@
name: On PRs - Mac Special Builds name: On PRs - Mac Special Builds
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on: on:
workflow_dispatch: workflow_dispatch:
pull_request: pull_request:
@ -28,22 +32,8 @@ jobs:
- name: Build - name: Build
run: | run: |
mkdir build && cd build && \ cmake --preset base_mac -S . -B build -DEXIV2_TEAM_USE_SANITIZERS=ON
cmake -GNinja \ cmake --build build --parallel
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_SHARED_LIBS=ON \
-DEXIV2_BUILD_SAMPLES=ON \
-DEXIV2_ENABLE_PNG=ON \
-DEXIV2_ENABLE_WEBREADY=ON \
-DEXIV2_ENABLE_CURL=ON \
-DEXIV2_BUILD_UNIT_TESTS=ON \
-DEXIV2_ENABLE_BMFF=ON \
-DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON \
-DBUILD_WITH_COVERAGE=OFF \
-DEXIV2_TEAM_USE_SANITIZERS=ON \
-DCMAKE_INSTALL_PREFIX=install \
.. && \
cmake --build . --parallel
- name: Tests - name: Tests
run: | run: |

@ -1,5 +1,9 @@
name: On PRs - Windows Matrix name: On PRs - Windows Matrix
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on: on:
pull_request: pull_request:
paths-ignore: paths-ignore:
@ -50,7 +54,7 @@ jobs:
- name: Install Conan & Common config - name: Install Conan & Common config
run: | run: |
pip.exe install "conan==1.45.0" pip.exe install "conan==1.48.1"
conan config install https://github.com/conan-io/conanclientcert.git conan config install https://github.com/conan-io/conanclientcert.git
conan profile new --detect default conan profile new --detect default
conan profile update settings.build_type=${{matrix.build_type}} default conan profile update settings.build_type=${{matrix.build_type}} default
@ -73,23 +77,12 @@ jobs:
- name: Build - name: Build
run: | run: |
cmake -GNinja ` cmake --preset base_windows -S . -B build -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DBUILD_SHARED_LIBS=${{matrix.shared_libraries}}
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} `
-DBUILD_SHARED_LIBS=${{matrix.shared_libraries}} `
-DEXIV2_ENABLE_NLS=OFF `
-DEXIV2_ENABLE_WEBREADY=ON `
-DEXIV2_ENABLE_BMFF=ON `
-DEXIV2_BUILD_UNIT_TESTS=ON `
-DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON `
-DCMAKE_INSTALL_PREFIX=install `
-S . -B build && `
cmake --build build --parallel cmake --build build --parallel
- name: Install - name: Install
run: | run: |
cd build cmake --install build
cmake --install .
tree /f install
- name: Test - name: Test
if: ${{matrix.platform == 'x64'}} if: ${{matrix.platform == 'x64'}}
@ -122,26 +115,26 @@ jobs:
install: >- install: >-
base-devel base-devel
pacboy: >- pacboy: >-
toolchain:p cc:p
gcc-libs:p
libwinpthread:p
cmake:p cmake:p
ninja:p
expat:p expat:p
gettext:p gettext:p
gtest:p gtest:p
libiconv:p libiconv:p
zlib:p zlib:p
curl:p
- name: Build - name: Build
run: | run: |
cmake -G"MSYS Makefiles" \ cmake --preset base_windows -S . -B build \
-DCMAKE_CXX_FLAGS=-Wno-deprecated \
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} \ -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
-DBUILD_SHARED_LIBS=${{matrix.shared_libraries}} \ -DBUILD_SHARED_LIBS=${{matrix.shared_libraries}} \
-DEXIV2_BUILD_SAMPLES=ON \ -DCONAN_AUTO_INSTALL=OFF \
-DEXIV2_ENABLE_NLS=OFF \ -DCMAKE_CXX_FLAGS=-Wno-deprecated \
-DEXIV2_ENABLE_WEBREADY=ON \ -DEXIV2_TEAM_WARNINGS_AS_ERRORS=OFF
-DEXIV2_ENABLE_BMFF=ON \
-DEXIV2_BUILD_UNIT_TESTS=ON \
-S . -B build && \
cmake --build build --parallel cmake --build build --parallel
- name: Test - name: Test
@ -176,6 +169,7 @@ jobs:
gcc-g++ gcc-g++
cmake cmake
ninja ninja
libcurl-devel
libexpat-devel libexpat-devel
libxml2-devel libxml2-devel
libxslt-devel libxslt-devel
@ -190,6 +184,7 @@ jobs:
-DEXIV2_ENABLE_NLS=OFF \ -DEXIV2_ENABLE_NLS=OFF \
-DEXIV2_ENABLE_WIN_UNICODE=OFF \ -DEXIV2_ENABLE_WIN_UNICODE=OFF \
-DEXIV2_ENABLE_WEBREADY=ON \ -DEXIV2_ENABLE_WEBREADY=ON \
-DEXIV2_ENABLE_CURL=ON \
-DEXIV2_ENABLE_BMFF=ON \ -DEXIV2_ENABLE_BMFF=ON \
-DEXIV2_BUILD_UNIT_TESTS=OFF \ -DEXIV2_BUILD_UNIT_TESTS=OFF \
-S . -B build && \ -S . -B build && \

@ -8,6 +8,10 @@ on:
paths-ignore: paths-ignore:
- "*.md" - "*.md"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
name: On PUSH - Basic CI for main platforms name: On PUSH - Basic CI for main platforms
jobs: jobs:
@ -41,35 +45,16 @@ jobs:
- name: Install Conan & Common config - name: Install Conan & Common config
run: | run: |
pip.exe install "conan==1.45.0" pip.exe install "conan==1.48.1"
conan profile new --detect default conan profile new --detect default
conan profile show default conan profile show default
conan profile update settings.compiler="Visual Studio" default conan profile update settings.compiler="Visual Studio" default
conan profile update settings.compiler.version=17 default conan profile update settings.compiler.version=17 default
conan config set storage.path=$Env:GITHUB_WORKSPACE/conanCache conan config set storage.path=$Env:GITHUB_WORKSPACE/conanCache
- name: Run Conan
run: |
md build
cd build
conan profile list
conan install .. --build missing
- name: Build - name: Build
run: | run: |
cmake -GNinja ` cmake --preset win-release -S . -B build
-DCMAKE_BUILD_TYPE=Release `
-DBUILD_SHARED_LIBS=ON `
-DEXIV2_BUILD_SAMPLES=ON `
-DEXIV2_ENABLE_NLS=OFF `
-DEXIV2_ENABLE_PNG=ON `
-DEXIV2_ENABLE_WEBREADY=ON `
-DEXIV2_ENABLE_BMFF=ON `
-DEXIV2_BUILD_UNIT_TESTS=ON `
-DEXIV2_ENABLE_WIN_UNICODE=OFF `
-DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON `
-DCMAKE_INSTALL_PREFIX=install .. `
-S . -B build && `
cmake --build build --parallel cmake --build build --parallel
@ -88,7 +73,7 @@ jobs:
- name: install dependencies - name: install dependencies
run: | run: |
sudo apt-get install ninja-build sudo apt-get install ninja-build
pip3 install conan==1.45.0 pip3 install conan==1.48.1
- name: Conan - name: Conan
run: | run: |
@ -100,20 +85,8 @@ jobs:
- name: build and compile - name: build and compile
run: | run: |
cd build && \ cmake --preset linux-release-NoConan -S . -B build
cmake -GNinja \ cmake --build build --parallel
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_SHARED_LIBS=ON \
-DEXIV2_BUILD_SAMPLES=ON \
-DEXIV2_ENABLE_PNG=ON \
-DEXIV2_ENABLE_WEBREADY=ON \
-DEXIV2_ENABLE_CURL=ON \
-DEXIV2_BUILD_UNIT_TESTS=ON \
-DEXIV2_ENABLE_BMFF=ON \
-DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON \
-DCMAKE_INSTALL_PREFIX=install \
.. && \
cmake --build . --parallel
- name: Test - name: Test
run: | run: |
@ -141,21 +114,8 @@ jobs:
- name: build and compile - name: build and compile
run: | run: |
mkdir build && cd build && \ cmake --preset base_mac -S . -B build -DCMAKE_CXX_FLAGS="-Wno-deprecated-declarations"
cmake -GNinja \ cmake --build build --parallel
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_SHARED_LIBS=ON \
-DEXIV2_BUILD_SAMPLES=ON \
-DEXIV2_ENABLE_PNG=ON \
-DEXIV2_ENABLE_WEBREADY=ON \
-DEXIV2_ENABLE_CURL=ON \
-DEXIV2_BUILD_UNIT_TESTS=ON \
-DEXIV2_ENABLE_BMFF=ON \
-DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON \
-DCMAKE_INSTALL_PREFIX=install \
-DCMAKE_CXX_FLAGS="-Wno-deprecated-declarations" \
.. && \
cmake --build . --parallel
- name: Test - name: Test
run: | run: |

@ -1,5 +1,9 @@
name: On PUSH - Linux Special Builds for main branch name: On PUSH - Linux Special Builds for main branch
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on: on:
push: push:
branches: branches:
@ -8,6 +12,7 @@ on:
- '!*' - '!*'
paths-ignore: paths-ignore:
- "*.md" - "*.md"
workflow_dispatch:
jobs: jobs:
special_debugRelease: special_debugRelease:
@ -19,8 +24,9 @@ jobs:
- name: install dependencies - name: install dependencies
run: | run: |
pip3 install conan==1.45.0 sudo apt-get install ninja-build
pip install gcovr pip3 install conan==1.48.1
pip3 install gcovr
- name: Conan common config - name: Conan common config
run: | run: |
@ -36,20 +42,8 @@ jobs:
- name: Build - name: Build
run: | run: |
cd build && \ cmake --preset linux-coverage -S . -B build
cmake -DCMAKE_BUILD_TYPE=Debug \ cmake --build build
-DBUILD_SHARED_LIBS=ON \
-DEXIV2_ENABLE_PNG=ON \
-DEXIV2_ENABLE_WEBREADY=ON \
-DEXIV2_ENABLE_CURL=ON \
-DEXIV2_BUILD_UNIT_TESTS=ON \
-DEXIV2_ENABLE_BMFF=ON \
-DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON \
-DEXIV2_BUILD_SAMPLES=ON \
-DBUILD_WITH_COVERAGE=ON \
-DCMAKE_INSTALL_PREFIX=install \
.. && \
cmake --build .
- name: Tests + Upload coverage - name: Tests + Upload coverage
run: | run: |

@ -1,4 +1,7 @@
name: Clang Format Checker name: Clang Format Checker
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
clang-format-checking: clang-format-checking:

@ -1,4 +1,7 @@
name: Release name: Release
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on: on:
push: push:
tags: tags:
@ -22,7 +25,7 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: | run: |
sudo apt-get install ninja-build gettext doxygen graphviz sudo apt-get install ninja-build gettext doxygen graphviz
pip3 install conan==1.45.0 pip3 install conan==1.48.1
- name: Conan common config - name: Conan common config
run: | run: |
@ -39,16 +42,7 @@ jobs:
- name: Build packaged release - name: Build packaged release
run: | run: |
cmake -GNinja -S . -B build \ cmake --preset linux-all -S . -B build -DEXIV2_TEAM_PACKAGING=ON -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DEXIV2_ENABLE_WEBREADY=OFF -DEXIV2_ENABLE_CURL=OFF
-DEXIV2_TEAM_PACKAGING=ON \
-DBUILD_SHARED_LIBS=ON \
-DEXIV2_ENABLE_WEBREADY=OFF \
-DEXIV2_ENABLE_NLS=ON \
-DCMAKE_BUILD_TYPE=Release \
-DEXIV2_ENABLE_BMFF=ON \
-DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
-DEXIV2_BUILD_DOC=ON
cmake --build build -t doc cmake --build build -t doc
cmake --build build -t package cmake --build build -t package
@ -114,20 +108,28 @@ jobs:
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v3 uses: actions/setup-python@v3
with: with:
python-version: 3.9 python-version: 3.7
- name: Install doxygen - name: Install doxygen
run: | run: |
choco install doxygen.install choco install doxygen.install
choco install graphviz choco install graphviz
- name: Restore conan cache
uses: actions/cache@v2
with:
path: ${{github.workspace}}/conanCache
key: ${{runner.os}}-release-win-${{ hashFiles('conanfile.py') }}
- name: Install Conan & Common config - name: Install Conan & Common config
run: | run: |
pip.exe install "conan==1.45.0" pip.exe install "conan==1.48.1"
conan profile new --detect default conan profile new --detect default
conan profile show default
conan profile update settings.build_type=Release default conan profile update settings.build_type=Release default
conan profile update settings.compiler="Visual Studio" default conan profile update settings.compiler="Visual Studio" default
conan profile update settings.compiler.version=17 default conan profile update settings.compiler.version=17 default
conan config set storage.path=$Env:GITHUB_WORKSPACE/conanCache
- name: Run Conan - name: Run Conan
run: | run: |
@ -137,18 +139,9 @@ jobs:
- name: Build packaged release - name: Build packaged release
run: | run: |
cmake -GNinja -S . -B build ` cmake --preset win-release -S . -B build -DEXIV2_TEAM_PACKAGING=ON -DEXIV2_BUILD_DOC=ON -DEXIV2_ENABLE_WEBREADY=OFF -DEXIV2_ENABLE_CURL=OFF
-DEXIV2_TEAM_PACKAGING=ON ` cmake --build build --parallel -t doc
-DBUILD_SHARED_LIBS=ON ` cmake --build build --parallel -t package
-DEXIV2_ENABLE_WEBREADY=OFF `
-DEXIV2_ENABLE_NLS=OFF `
-DCMAKE_BUILD_TYPE=Release `
-DEXIV2_ENABLE_BMFF=ON `
-DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON `
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON `
-DEXIV2_BUILD_DOC=ON
cmake --build build -t doc
cmake --build build -t package
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v3
with: with:
@ -196,14 +189,14 @@ jobs:
with: with:
script: | script: |
try{ try{
const rel_id = await github.repos.getReleaseByTag({ const rel_id = await github.rest.repos.getReleaseByTag({
...context.repo, ...context.repo,
tag: "nightly" tag: "nightly"
}).then(result => result.data.id); }).then(result => result.data.id);
console.log( "Found existing nightly release with id: ", rel_id); console.log( "Found existing nightly release with id: ", rel_id);
await github.repos.deleteRelease({ await github.rest.repos.deleteRelease({
...context.repo, ...context.repo,
release_id: rel_id release_id: rel_id
}); });
@ -215,7 +208,7 @@ jobs:
} }
try{ try{
await github.git.deleteRef({ await github.rest.git.deleteRef({
...context.repo, ...context.repo,
ref: "tags/nightly" ref: "tags/nightly"
}); });

1
.gitignore vendored

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

@ -0,0 +1,149 @@
{
"version": 3,
"configurePresets": [
{
"name": "base_ninja",
"description": "Base preset to use ninja as generator",
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/build-${presetName}",
"installDir": "${sourceDir}/build-${presetName}/install",
"cacheVariables": {
"BUILD_SHARED_LIBS": true,
"CONAN_AUTO_INSTALL": true,
"EXIV2_BUILD_SAMPLES": true,
"EXIV2_ENABLE_WEBREADY": true,
"EXIV2_ENABLE_CURL": true,
"EXIV2_ENABLE_PNG": true,
"EXIV2_ENABLE_BMFF": true,
"EXIV2_BUILD_UNIT_TESTS": true,
"EXIV2_TEAM_WARNINGS_AS_ERRORS": true,
"EXIV2_ENABLE_NLS": false
}
},
{
"name": "base_windows",
"description": "Base preset for Windows (specially useful for CI jobs)",
"displayName": "Base preset for Windows (specially useful for CI jobs)",
"inherits": "base_ninja",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
}
},
{
"name": "base_linux",
"description": "Base preset for Linux",
"displayName": "Base preset for Linux with default compiler: GCC (specially useful for CI jobs)",
"inherits": "base_ninja",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
},
"cacheVariables": {
"BUILD_WITH_CCACHE": true
}
},
{
"name": "base_mac",
"description": "Base preset for macOS (no conan usage)",
"displayName": "Base preset for macOS with default compiler: AppleClang (specially useful for CI jobs)",
"inherits": "base_ninja",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CONAN_AUTO_INSTALL": false
}
},
{
"name": "msvc",
"displayName": "Visual Studio cl toolchain (also usable from VS Code)",
"inherits": "base_windows",
"architecture": {
"value": "x64",
"strategy": "external"
},
"toolset": {
"value": "host=x64",
"strategy": "external"
},
"cacheVariables": {
"CMAKE_C_COMPILER": "cl.exe",
"CMAKE_CXX_COMPILER": "cl.exe",
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "win-debug",
"displayName": "Windows Debug with configured architecture",
"description": "Sets Debug build type with the preloaded Visual Studio Environment",
"inherits": "base_windows",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "win-release",
"displayName": "Windows Release with configured architecture",
"description": "Sets Release build type with the preloaded Visual Studio Environment",
"inherits": "base_windows",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "linux-debug",
"displayName": "Linux Debug (Ninja Generator) with default architecture",
"inherits": "base_linux",
"cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" }
},
{
"name": "linux-release",
"displayName": "Linux Release (Ninja Generator) with default architecture",
"inherits": "base_linux",
"cacheVariables": { "CMAKE_BUILD_TYPE": "Release" }
},
{
"name": "linux-debug-NoConan",
"displayName": "Same as linux-debug but without automatic conan execution",
"inherits": "linux-debug",
"cacheVariables": { "CONAN_AUTO_INSTALL": false }
},
{
"name": "linux-release-NoConan",
"displayName": "Same as linux-release but without automatic conan execution",
"inherits": "linux-release",
"cacheVariables": { "CONAN_AUTO_INSTALL": false }
},
{
"name": "linux-coverage",
"displayName": "Same as linux-debug-NoConan with coverage enabled",
"inherits": "linux-debug-NoConan",
"cacheVariables": { "BUILD_WITH_COVERAGE": true }
},
{
"name": "linux-sanitizers",
"displayName": "Same as linux-debug-NoConan with sanitizers enabled",
"inherits": "linux-debug-NoConan",
"cacheVariables": { "EXIV2_TEAM_USE_SANITIZERS": true }
},
{
"name": "linux-all",
"displayName": "Same as linux-release-NoConan and with rest of things enabled (doc + NLS)",
"description": "requires installation of packages: doxygen graphviz gettext",
"inherits": "linux-release-NoConan",
"cacheVariables": {
"EXIV2_ENABLE_NLS": true,
"EXIV2_BUILD_DOC": true
}
}
]
}

@ -32,6 +32,7 @@ The file ReadMe.txt in a build bundle describes how to install the library on th
- [Building, Installing, Using and Uninstalling Exiv2](#B_I_U) - [Building, Installing, Using and Uninstalling Exiv2](#B_I_U)
- [Build, Install, Use and Uninstall Exiv2 on a UNIX-like system](#B_I_U_Unix) - [Build, Install, Use and Uninstall Exiv2 on a UNIX-like system](#B_I_U_Unix)
- [Build and Install Exiv2 with Visual Studio](#B_I_U_VisualStudio) - [Build and Install Exiv2 with Visual Studio](#B_I_U_VisualStudio)
- [Configure the project with CMake presets](#CMakePresets)
- [Build Options](#BuildOptions) - [Build Options](#BuildOptions)
- [Dependencies](#Dependencies) - [Dependencies](#Dependencies)
- [Building and linking your code with Exiv2](#BuildAndLinkYourCode) - [Building and linking your code with Exiv2](#BuildAndLinkYourCode)
@ -126,7 +127,7 @@ path.
## Build and Install Exiv2 with Visual Studio ## Build and Install Exiv2 with Visual Studio
We recommend that you use conan to download the Exiv2 external dependencies on Windows. On other platforms (macOS, Linux and others), traditionally the platform package managers have been used. These are discussed at [Platform Notes](#PlatformNotes). The options to configure and compile the project using Visual Studio are similar to UNIX like systems. We recommend to use conan to download the Exiv2 external dependencies on Windows. On other platforms (macOS, Linux and others), traditionally the platform package managers have been used. However, conan can be used in any platform/architecture to bring the project dependencies. These are discussed at [Platform Notes](#PlatformNotes). The options to configure and compile the project using Visual Studio are similar to UNIX like systems.
See [README-CONAN](README-CONAN.md) for more information about Conan. See [README-CONAN](README-CONAN.md) for more information about Conan.
When you build, you may install with the following command. When you build, you may install with the following command.
@ -136,6 +137,99 @@ When you build, you may install with the following command.
``` ```
This will create and copy the exiv2 build artefacts to `%ProgramFiles%/exiv2`. To be able to run the `exiv2` command line application from any terminal you should modify your path to include `%ProgramFiles%/exiv2/bin`. This will create and copy the exiv2 build artefacts to `%ProgramFiles%/exiv2`. To be able to run the `exiv2` command line application from any terminal you should modify your path to include `%ProgramFiles%/exiv2/bin`.
[TOC](#TOC)
<div id="CMakePresets">
## Configure the project with the CMake presets
CMake presets (see documentation [here](https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html)) were added recently to the project to ease the CMake configuration process for typical configurations. The presets are defined in the file `CMakePresets.json` and they can be used from the terminal or interpreted by different IDEs. Please note that one needs to use a recent version of CMake (>= 3.21) supporting the presets feature.
One can list the available presets using the `--list-presets` option:
```bash
# Running the command from a Windows terminal
$ cmake --list-presets
Available configure presets:
"msvc" - Visual Studio cl toolchain (also usable from VS Code)
"win-debug" - Windows Debug with configured architecture
"win-release" - Windows Release with configured architecture
# Running the command from a Linux terminal
$ cmake --list-presets
Available configure presets:
"linux-debug" - Linux Debug with default architecture
"linux-release" - Linux Release with default architecture
```
The project configuration with a specific preset can be choosen with the CMake `--preset` option. In the following terminal output we comment out some interesting things happening during the project configuration:
```bash
# Configuring the project using a preset
$ cmake --preset win-release
Preset CMake variables:
# Note that with the usage of a preset, we pass many different options to CMake.
BUILD_SHARED_LIBS:BOOL="TRUE"
CMAKE_BUILD_TYPE="Release"
CMAKE_INSTALL_PREFIX:PATH="C:/dev/personal/exiv2/build-win-release/install"
# A build & install directory are configured with the preset
CONAN_AUTO_INSTALL:BOOL="TRUE"
EXIV2_BUILD_SAMPLES:BOOL="TRUE"
EXIV2_BUILD_UNIT_TESTS:BOOL="TRUE"
EXIV2_ENABLE_BMFF:BOOL="TRUE"
EXIV2_ENABLE_CURL:BOOL="TRUE"
EXIV2_ENABLE_NLS:BOOL="FALSE"
EXIV2_ENABLE_PNG:BOOL="TRUE"
EXIV2_ENABLE_WEBREADY:BOOL="TRUE"
EXIV2_TEAM_WARNINGS_AS_ERRORS:BOOL="TRUE"
# Conan can be automatically detected in your system and it is run automatically to bring the
# project dependencies
-- Conan: Detected VS runtime: MD
-- Conan: checking conan executable
-- Conan: Found program C:/dev/envs/conan/Scripts/conan.exe
-- Conan: Version found Conan version 1.47.0
-- Conan executing: C:/dev/envs/conan/Scripts/conan.exe install .. --remote conancenter --build missing --options webready=True --settings arch=x86_64 --settings build_type=Release --settings compiler=Visual Studio --settings compiler.version=17 --settings compiler.runtime=MD
...
# CMake finds the project dependencies which were automatically handled by conan
-- Conan: Using autogenerated FindZLIB.cmake
-- Library zlib found C:/Users/luis/.conan/data/zlib/1.2.11/_/_/package/-- Conan: Using autogenerated FindCURL.cmake
-- Library libcurl_imp found C:/Users/luis/.conan/data/libcurl/7.79.0/_/_/package/
...
# CMake finish the project configuration and prints a report
-- Install prefix: C:/dev/personal/exiv2/build-win-release/install
-- ------------------------------------------------------------------
-- CMake Generator: Ninja
-- CMAKE_BUILD_TYPE: Release
-- Compiler info: MSVC (C:/Program Files/Microsoft Visual Studio/2022/Professional/VC/Tools/MSVC/14.30.30705/bin/Hostx64/x64/cl.exe) ; version: 19.30.30705.0
-- CMAKE_CXX_STANDARD:17
-- --- Compiler flags ---
-- General: /DWIN32 /D_WINDOWS /W3 /GR /EHsc
/MP
/utf-8
/WX
-- Extra:
-- Debug: /MDd /Zi /Ob0 /Ox /Zo
-- Release: /MD /O2 /DNDEBUG
-- RelWithDebInfo: /MD /Zi /O2 /DNDEBUG
-- MinSizeRel: /MD /O1 /DNDEBUG
-- --- Linker flags ---
-- General: /machine:x64 /WX
-- Debug: /debug /INCREMENTAL
-- Release: /INCREMENTAL:NO
-- RelWithDebInfo: /debug /INCREMENTAL
-- MinSizeRel: /INCREMENTAL:NO
--
...
-- Build files have been written to: C:/dev/personal/exiv2/build-win-release
```
Note that the usage of CMake presets allow the project contributors to use the same set of options easily in different environments (using terminal, IDEs or CI).
[TOC](#TOC) [TOC](#TOC)
<div id="BuildOptions"> <div id="BuildOptions">
@ -145,7 +239,7 @@ There are two groups of CMake options which are relevant to the project: global
| Options | Purpose (_default_) | | Options | Purpose (_default_) |
|:------------- |:------------- | |:------------- |:------------- |
| CMAKE\_INSTALL\_PREFIX<br/>CMAKE\_BUILD\_TYPE<br/>BUILD\_SHARED\_LIBS | Where to install on your computer _**(/usr/local)**_<br/>Type of build _**(Release)**_ See: [Debugging Exiv2](#Debugging) <br/>Build exiv2lib as shared or static _**(On)**_ | | CMAKE\_INSTALL\_PREFIX<br/>CMAKE\_BUILD\_TYPE<br/>BUILD\_SHARED\_LIBS | Where to install on your computer _**(/usr/local)**_<br/>Type of build _**(Release)**_ See: [Debugging Exiv2](#Debugging) <br/>Build exiv2lib as SHARED or STATIC |
Options defined at `exiv2/CMakeLists.txt` include: Options defined at `exiv2/CMakeLists.txt` include:
@ -160,10 +254,10 @@ option( EXIV2_ENABLE_BMFF "Build with BMFF support" ON
577 rmills@rmillsmm:~/gnu/github/exiv2/exiv2 $ 577 rmills@rmillsmm:~/gnu/github/exiv2/exiv2 $
``` ```
Options are defined on the CMake command-line: Using the command-line, these variables can be set/updated using the option `-D`:
```bash ```bash
$ cmake -DBUILD_SHARED_LIBS=On -DEXIV2_ENABLE_NLS=Off $ cmake -DBUILD_SHARED_LIBS=ON -DEXIV2_ENABLE_NLS=OFF
``` ```
[TOC](#TOC) [TOC](#TOC)
@ -175,9 +269,9 @@ The following Exiv2 features require external libraries:
| Feature | Package | Default | To change default | Availability | | Feature | Package | Default | To change default | Availability |
|:-------------------------- |:-------- |:--------:| :---------------------------- |:----------- | |:-------------------------- |:-------- |:--------:| :---------------------------- |:----------- |
| PNG image support | zlib | ON | -DEXIV2\_ENABLE\_PNG=Off | [http://zlib.net/](http://zlib.net/) | | PNG image support | zlib | ON | -DEXIV2\_ENABLE\_PNG=OFF | [http://zlib.net/](http://zlib.net/) |
| XMP support | expat | ON | -DEXIV2\_ENABLE\_XMP=Off | [http://expat.sourceforge.net](http://expat.sourceforge.net)/<br/>Use _**Expat 2.2.6**_ and later | | XMP support | expat | ON | -DEXIV2\_ENABLE\_XMP=OFF | [http://expat.sourceforge.net](http://expat.sourceforge.net)/<br/>Use _**Expat 2.2.6**_ and later |
| Natural language system | gettext | OFF | -DEXIV2\_ENABLE\_NLS=On | [http://www.gnu.org/software/gettext/](http://www.gnu.org/software/gettext/) | | Natural language system | gettext | OFF | -DEXIV2\_ENABLE\_NLS=ON | [http://www.gnu.org/software/gettext/](http://www.gnu.org/software/gettext/) |
| Character set conversion | libiconv | | Disabled for Visual Studio.<br>Linked when installed on UNIX like platforms. | [https://www.gnu.org/software/libiconv/](https://www.gnu.org/software/libiconv/) | | Character set conversion | libiconv | | Disabled for Visual Studio.<br>Linked when installed on UNIX like platforms. | [https://www.gnu.org/software/libiconv/](https://www.gnu.org/software/libiconv/) |
On UNIX systems, you may install the dependencies using the distribution's package management system. Install the On UNIX systems, you may install the dependencies using the distribution's package management system. Install the
@ -297,7 +391,7 @@ Localisation is supported on a UNIX-like platform: Linux, macOS, Cygwin and Min
Crowdin have provided Exiv2 with a free open-source license to use their services. The Exiv2 localisation project is located at [https://crowdin.com/project/exiv2](https://crowdin.com/project/exiv2). You will also need to register to have a free user account on Crowdin. The Crowdin setup is discussed here: [https://github.com/Exiv2/exiv2/issues/1510](https://github.com/Exiv2/exiv2/issues/1510). It is recommended that you coordinate with Leonardo before contributing localisation changes on Crowdin. You can contact Leonardo by via GitHub. Crowdin have provided Exiv2 with a free open-source license to use their services. The Exiv2 localisation project is located at [https://crowdin.com/project/exiv2](https://crowdin.com/project/exiv2). You will also need to register to have a free user account on Crowdin. The Crowdin setup is discussed here: [https://github.com/Exiv2/exiv2/issues/1510](https://github.com/Exiv2/exiv2/issues/1510). It is recommended that you coordinate with Leonardo before contributing localisation changes on Crowdin. You can contact Leonardo by via GitHub.
To build localisation support, use the CMake option `-DEXIV2_ENABLE_NLS=On`. You must install the `gettext` package with your package manager or from source. The `gettext` package is available from [http://www.gnu.org/software/gettext/](http://www.gnu.org/software/gettext/) and includes the library `libintl` and utilities to build localisation files. If CMake produces error messages which mention libintl or gettext, you should verify that the package `gettext` has been correctly built and installed. To build localisation support, use the CMake option `-DEXIV2_ENABLE_NLS=ON`. You must install the `gettext` package with your package manager or from source. The `gettext` package is available from [http://www.gnu.org/software/gettext/](http://www.gnu.org/software/gettext/) and includes the library `libintl` and utilities to build localisation files. If CMake produces error messages which mention libintl or gettext, you should verify that the package `gettext` has been correctly built and installed.
You must install the build to test localisation. This ensures that the localisation message files can be found at run-time. You cannot test localisation in the directory `build\bin`. You must install the build to test localisation. This ensures that the localisation message files can be found at run-time. You cannot test localisation in the directory `build\bin`.
@ -386,11 +480,11 @@ $
Building documentation requires installing special tools. You will probably prefer to Building documentation requires installing special tools. You will probably prefer to
read the documentation on-line from the project website: https://exiv2.org read the documentation on-line from the project website: https://exiv2.org
To build documentation, use the CMake option **`-DEXIV2_BUILD_DOC=On`**. To build documentation, use the CMake option **`-DEXIV2_BUILD_DOC=ON`**.
Additionally, you will require an additional build step to actually build the documentation. Additionally, you will require an additional build step to actually build the documentation.
```bash ```bash
$ cmake ..options.. -DEXIV2_BUILD_DOC=On $ cmake ..options.. -DEXIV2_BUILD_DOC=ON
$ cmake --build . --target doc $ cmake --build . --target doc
``` ```
@ -437,7 +531,7 @@ When the Exiv2 websites are updated, the generated tag webpages are reformatted
## Building Exiv2 Packages ## Building Exiv2 Packages
To enable the building of Exiv2 packages, use the CMake option `-DEXIV2_TEAM_PACKAGING=On`. To enable the building of Exiv2 packages, use the CMake option `-DEXIV2_TEAM_PACKAGING=ON`.
You should not build Exiv2 Packages. This feature is intended for use by Team Exiv2 to create Platform and Source Packages on the buildserver. You should not build Exiv2 Packages. This feature is intended for use by Team Exiv2 to create Platform and Source Packages on the buildserver.
@ -451,7 +545,7 @@ Create and build exiv2 for your platform.
$ git clone https://github.com/exiv2/exiv2 $ git clone https://github.com/exiv2/exiv2
$ mkdir -p exiv2/build $ mkdir -p exiv2/build
$ cd exiv2/build $ cd exiv2/build
$ cmake .. -G "Unix Makefiles" -DEXIV2_TEAM_PACKAGING=On $ cmake .. -G "Unix Makefiles" -DEXIV2_TEAM_PACKAGING=ON
... ...
-- Build files have been written to: .../build -- Build files have been written to: .../build
$ cmake --build . --config Release $ cmake --build . --config Release
@ -603,19 +697,19 @@ Installing and using ccache (and other similar utilities), is platform dependent
$ sudo apt install --yes ccache $ sudo apt install --yes ccache
``` ```
To build with ccache, use the CMake option **-DBUILD\_WITH\_CCACHE=On** To build with ccache, use the CMake option **-DBUILD\_WITH\_CCACHE=ON**
```bash ```bash
$ cd <exiv2dir> $ cd <exiv2dir>
$ mkdir build ; cd build ; cd build $ mkdir build ; cd build ; cd build
$ cmake .. -G "Unix Makefiles" -DBUILD_WITH_CCACHE=On $ cmake .. -G "Unix Makefiles" -DBUILD_WITH_CCACHE=ON
$ cmake --build . $ cmake --build .
# Build again to appreciate the performance gain # Build again to appreciate the performance gain
$ cmake --build . --target clean $ cmake --build . --target clean
$ cmake --build . $ cmake --build .
``` ```
Due to the way in which ccache is installed in Fedora (and other Linux distros), ccache effectively replaces the compiler. A default build or **-DBUILD\_WITH\_CCACHE=Off** is not effective and the environment variable CCACHE_DISABLE is required to disable ccache. [https://github.com/Exiv2/exiv2/issues/361](https://github.com/Exiv2/exiv2/issues/361) Due to the way in which ccache is installed in Fedora (and other Linux distros), ccache effectively replaces the compiler. A default build or **-DBUILD\_WITH\_CCACHE=OFF** is not effective and the environment variable CCACHE_DISABLE is required to disable ccache. [https://github.com/Exiv2/exiv2/issues/361](https://github.com/Exiv2/exiv2/issues/361)
[TOC](#TOC) [TOC](#TOC)
<div id="ThreadSafety"> <div id="ThreadSafety">
@ -707,10 +801,9 @@ $ make
Note, you may wish to choose to build with optional features and/or build static libraries. To do this, request appropriately on the mingw64-cmake command: Note, you may wish to choose to build with optional features and/or build static libraries. To do this, request appropriately on the mingw64-cmake command:
```bash ```bash
$ mingw64-cmake .. -DEXIV2_TEAM_EXTRA_WARNINGS=On \ $ mingw64-cmake .. -DEXIV2_TEAM_EXTRA_WARNINGS=ON \
-DEXIV2_ENABLE_WEBREADY=On \ -DEXIV2_ENABLE_WEBREADY=ON \
-DEXIV2_ENABLE_WIN_UNICODE=On \ -DBUILD_SHARED_LIBS=OFF
-DBUILD_SHARED_LIBS=Off
``` ```
The options available for cross-compiling are the same as provided for all builds. See: [Build Options](#BuildOptions) The options available for cross-compiling are the same as provided for all builds. See: [Build Options](#BuildOptions)
@ -773,7 +866,7 @@ You will find that 3 tests fail at the end of the test suite. It is safe to ign
## Static and Shared Libraries ## Static and Shared Libraries
You can build either static or shared libraries. Both can be linked with either static or shared run-time libraries. You specify the shared/static with the option `-BUILD_SHARED_LIBS=On|Off` You specify the run-time with the option `-DEXIV2_ENABLE_DYNAMIC_RUNTIME=On|Off`. The default for both options default is On. So you build shared and use the shared libraries which are `.dll` on Windows (msvc, Cygwin and MinGW/msys), `.dylib` on macOS and `.so` on Linux and UNIX. You can build either static or shared libraries. Both can be linked with either static or shared run-time libraries. You specify the shared/static with the option `-BUILD_SHARED_LIBS=ON|OFF` You specify the run-time with the option `-DEXIV2_ENABLE_DYNAMIC_RUNTIME=ON|OFF`. The default for both options default is ON. So you build shared and use the shared libraries which are `.dll` on Windows (msvc, Cygwin and MinGW/msys), `.dylib` on macOS and `.so` on Linux and UNIX.
CMake creates your build artefacts in the directories `bin` and `lib`. The `bin` directory contains your executables and .DLLs. The `lib` directory contains your static libraries. When you install exiv2, the build artefacts are copied to your system's prefix directory which by default is `/usr/local/`. If you wish to test and use your build without installing, you will have to set you PATH appropriately. Linux/Unix users should also set `LD_LIBRARY_PATH` and macOS users should set `DYLD_LIBRARY_PATH`. CMake creates your build artefacts in the directories `bin` and `lib`. The `bin` directory contains your executables and .DLLs. The `lib` directory contains your static libraries. When you install exiv2, the build artefacts are copied to your system's prefix directory which by default is `/usr/local/`. If you wish to test and use your build without installing, you will have to set you PATH appropriately. Linux/Unix users should also set `LD_LIBRARY_PATH` and macOS users should set `DYLD_LIBRARY_PATH`.
@ -806,13 +899,13 @@ This is discussed: [https://github.com/Exiv2/exiv2/issues/1230](https://github.c
**Attention is drawn to the possibility that bmff support may be the subject of patent rights. _Exiv2 shall not be held responsible for identifying any or all such patent rights. Exiv2 shall not be held responsible for the legal consequences of the use of this code_.** **Attention is drawn to the possibility that bmff support may be the subject of patent rights. _Exiv2 shall not be held responsible for identifying any or all such patent rights. Exiv2 shall not be held responsible for the legal consequences of the use of this code_.**
Access to the bmff code is guarded in two ways. Firstly, you have to build the library with the CMake option: `-DEXIV2_ENABLE_BMFF=On`. Secondly, the application must enable bmff support at run-time by calling the following function. Access to the bmff code is guarded in two ways. Firstly, you have to build the library with the CMake option: `-DEXIV2_ENABLE_BMFF=ON`. Secondly, the application must enable bmff support at run-time by calling the following function.
```cpp ```cpp
EXIV2API bool enableBMFF(bool enable); EXIV2API bool enableBMFF(bool enable);
``` ```
The return value from `enableBMFF()` is true if the library has been build with bmff support (CMake option -DEXIV2_ENABLE_BMFF=On). The return value from `enableBMFF()` is true if the library has been build with bmff support (CMake option -DEXIV2_ENABLE_BMFF=ON).
Applications may wish to provide a preference setting to enable bmff support and thereby place the responsibility for the use of this code with the user of the application. Applications may wish to provide a preference setting to enable bmff support and thereby place the responsibility for the use of this code with the user of the application.
@ -928,7 +1021,7 @@ The Variable EXIV2\_PORT or EXIV2\_HTTP can be set to None to skip http tests.
You can run tests directly from the build: You can run tests directly from the build:
```bash ```bash
$ cmake .. -G "Unix Makefiles" -DEXIV2_BUILD_UNIT_TESTS=On $ cmake .. -G "Unix Makefiles" -DEXIV2_BUILD_UNIT_TESTS=ON
... lots of output and build summary ... ... lots of output and build summary ...
$ cmake --build . $ cmake --build .
... lots of output ... ... lots of output ...
@ -993,7 +1086,7 @@ As a summary, the procedure is:
c:\...\exiv2>mkdir build c:\...\exiv2>mkdir build
c:\...\exiv2>cd build c:\...\exiv2>cd build
c:\...\exiv2\build>conan install .. --build missing --profile msvc2019Release c:\...\exiv2\build>conan install .. --build missing --profile msvc2019Release
c:\...\exiv2\build>cmake .. -DEXIV2_BUILD_UNIT_TESTS=On -G "Visual Studio 16 2019" c:\...\exiv2\build>cmake .. -DEXIV2_BUILD_UNIT_TESTS=ON -G "Visual Studio 16 2019"
c:\...\exiv2\build>cmake --build . --config Release c:\...\exiv2\build>cmake --build . --config Release
... lots of output from compiler and linker ... ... lots of output from compiler and linker ...
c:\...\exiv2\build>ctest -C Release c:\...\exiv2\build>ctest -C Release
@ -1012,7 +1105,7 @@ set EXIV2_PORT=
## Unit Tests ## Unit Tests
The code for the unit tests is in `<exiv2dir>/unitTests`. To include unit tests in the build, use the *CMake* option `-DEXIV2_BUILD_UNIT_TESTS=On`. The code for the unit tests is in `<exiv2dir>/unitTests`. To include unit tests in the build, use the *CMake* option `-DEXIV2_BUILD_UNIT_TESTS=ON`.
There is a discussion on the web about installing GTest: [https://github.com/Exiv2/exiv2/issues/575](https://github.com/Exiv2/exiv2/issues/575) There is a discussion on the web about installing GTest: [https://github.com/Exiv2/exiv2/issues/575](https://github.com/Exiv2/exiv2/issues/575)

@ -6,12 +6,14 @@
#include "app_utils.hpp" #include "app_utils.hpp"
#include "config.h" #include "config.h"
#include "easyaccess.hpp" #include "easyaccess.hpp"
#include "enforce.hpp"
#include "exif.hpp" #include "exif.hpp"
#include "futils.hpp" #include "futils.hpp"
#include "i18n.h" // NLS support. #include "i18n.h" // NLS support.
#include "image.hpp" #include "image.hpp"
#include "iptc.hpp" #include "iptc.hpp"
#include "preview.hpp" #include "preview.hpp"
#include "safe_op.hpp"
#include "types.hpp" #include "types.hpp"
#include "xmp_exiv2.hpp" #include "xmp_exiv2.hpp"
@ -38,9 +40,10 @@
#include <utime.h> #include <utime.h>
#endif #endif
#if !defined(__MINGW__) && !defined(_MSC_VER) #ifndef _WIN32
#define _fileno(a) a #define _setmode(a, b) \
#define _setmode(a, b) do { \
} while (false)
#endif #endif
namespace fs = std::filesystem; namespace fs = std::filesystem;
@ -177,7 +180,7 @@ int setModeAndPrintStructure(Exiv2::PrintStructureOption option, const std::stri
ascii.write_uint8(str.size() * 3, 0); ascii.write_uint8(str.size() * 3, 0);
std::copy(str.begin(), str.end(), iccProfile.begin()); std::copy(str.begin(), str.end(), iccProfile.begin());
if (Exiv2::base64encode(iccProfile.c_data(), str.size(), reinterpret_cast<char*>(ascii.data()), str.size() * 3)) { if (Exiv2::base64encode(iccProfile.c_data(), str.size(), reinterpret_cast<char*>(ascii.data()), str.size() * 3)) {
long chunk = 60; const size_t chunk = 60;
std::string code = std::string("data:") + ascii.c_str(); std::string code = std::string("data:") + ascii.c_str();
size_t length = code.size(); size_t length = code.size();
for (size_t start = 0; start < length; start += chunk) { for (size_t start = 0; start < length; start += chunk) {
@ -197,34 +200,25 @@ int setModeAndPrintStructure(Exiv2::PrintStructureOption option, const std::stri
int Print::run(const std::string& path) { int Print::run(const std::string& path) {
try { try {
path_ = path; path_ = path;
int rc = 0;
switch (Params::instance().printMode_) { switch (Params::instance().printMode_) {
case Params::pmSummary: case Params::pmSummary:
rc = Params::instance().greps_.empty() ? printSummary() : printList(); return Params::instance().greps_.empty() ? printSummary() : printList();
break;
case Params::pmList: case Params::pmList:
rc = printList(); return printList();
break;
case Params::pmComment: case Params::pmComment:
rc = printComment(); return printComment();
break;
case Params::pmPreview: case Params::pmPreview:
rc = printPreviewList(); return printPreviewList();
break;
case Params::pmStructure: case Params::pmStructure:
rc = printStructure(std::cout, Exiv2::kpsBasic, path_); return printStructure(std::cout, Exiv2::kpsBasic, path_);
break;
case Params::pmRecursive: case Params::pmRecursive:
rc = printStructure(std::cout, Exiv2::kpsRecursive, path_); return printStructure(std::cout, Exiv2::kpsRecursive, path_);
break;
case Params::pmXMP: case Params::pmXMP:
rc = setModeAndPrintStructure(Exiv2::kpsXMP, path_, binary()); return setModeAndPrintStructure(Exiv2::kpsXMP, path_, binary());
break;
case Params::pmIccProfile: case Params::pmIccProfile:
rc = setModeAndPrintStructure(Exiv2::kpsIccProfile, path_, binary()); return setModeAndPrintStructure(Exiv2::kpsIccProfile, path_, binary());
break;
} }
return rc; return 0;
} catch (const Exiv2::Error& e) { } catch (const Exiv2::Error& e) {
std::cerr << "Exiv2 exception in print action for file " << path << ":\n" << e << "\n"; std::cerr << "Exiv2 exception in print action for file " << path << ":\n" << e << "\n";
return 1; return 1;
@ -242,7 +236,7 @@ int Print::printSummary() {
auto image = Exiv2::ImageFactory::open(path_); auto image = Exiv2::ImageFactory::open(path_);
image->readMetadata(); image->readMetadata();
Exiv2::ExifData& exifData = image->exifData(); const Exiv2::ExifData& exifData = image->exifData();
align_ = 16; align_ = 16;
// Filename // Filename
@ -362,8 +356,8 @@ int Print::printList() {
auto image = Exiv2::ImageFactory::open(path_); auto image = Exiv2::ImageFactory::open(path_);
image->readMetadata(); image->readMetadata();
// Set defaults for metadata types and data columns // Set defaults for metadata types and data columns
if (Params::instance().printTags_ == Exiv2::mdNone) { if (Params::instance().printTags_ == MetadataId::invalid) {
Params::instance().printTags_ = Exiv2::mdExif | Exiv2::mdIptc | Exiv2::mdXmp; Params::instance().printTags_ = MetadataId::exif | MetadataId::iptc | MetadataId::xmp;
} }
if (Params::instance().printItems_ == 0) { if (Params::instance().printItems_ == 0) {
Params::instance().printItems_ = Params::prKey | Params::prType | Params::prCount | Params::prTrans; Params::instance().printItems_ = Params::prKey | Params::prType | Params::prCount | Params::prTrans;
@ -374,7 +368,7 @@ int Print::printList() {
int Print::printMetadata(const Exiv2::Image* image) { int Print::printMetadata(const Exiv2::Image* image) {
bool ret = false; bool ret = false;
bool noExif = false; bool noExif = false;
if (Params::instance().printTags_ & Exiv2::mdExif) { if ((Params::instance().printTags_ & MetadataId::exif) == MetadataId::exif) {
const Exiv2::ExifData& exifData = image->exifData(); const Exiv2::ExifData& exifData = image->exifData();
for (auto&& md : exifData) { for (auto&& md : exifData) {
ret |= printMetadatum(md, image); ret |= printMetadatum(md, image);
@ -384,7 +378,7 @@ int Print::printMetadata(const Exiv2::Image* image) {
} }
bool noIptc = false; bool noIptc = false;
if (Params::instance().printTags_ & Exiv2::mdIptc) { if ((Params::instance().printTags_ & MetadataId::iptc) == MetadataId::iptc) {
const Exiv2::IptcData& iptcData = image->iptcData(); const Exiv2::IptcData& iptcData = image->iptcData();
for (auto&& md : iptcData) { for (auto&& md : iptcData) {
ret |= printMetadatum(md, image); ret |= printMetadatum(md, image);
@ -394,7 +388,7 @@ int Print::printMetadata(const Exiv2::Image* image) {
} }
bool noXmp = false; bool noXmp = false;
if (Params::instance().printTags_ & Exiv2::mdXmp) { if ((Params::instance().printTags_ & MetadataId::xmp) == MetadataId::xmp) {
const Exiv2::XmpData& xmpData = image->xmpData(); const Exiv2::XmpData& xmpData = image->xmpData();
for (auto&& md : xmpData) { for (auto&& md : xmpData) {
ret |= printMetadatum(md, image); ret |= printMetadatum(md, image);
@ -434,7 +428,7 @@ bool Print::grepTag(const std::string& key) {
bool Print::keyTag(const std::string& key) { bool Print::keyTag(const std::string& key) {
bool result = Params::instance().keys_.empty(); bool result = Params::instance().keys_.empty();
for (auto&& k : Params::instance().keys_) { for (const auto& k : Params::instance().keys_) {
if (result) if (result)
break; break;
result = key == k; result = key == k;
@ -496,6 +490,12 @@ bool Print::printMetadatum(const Exiv2::Metadatum& md, const Exiv2::Image* pImag
first = false; first = false;
std::cout << std::setw(30) << std::setfill(' ') << std::left << md.tagLabel(); std::cout << std::setw(30) << std::setfill(' ') << std::left << md.tagLabel();
} }
if (Params::instance().printItems_ & Params::prDesc) {
if (!first)
std::cout << " ";
first = false;
std::cout << std::setw(30) << std::setfill(' ') << std::left << md.tagDesc();
}
if (Params::instance().printItems_ & Params::prType) { if (Params::instance().printItems_ & Params::prType) {
if (!first) if (!first)
std::cout << " "; std::cout << " ";
@ -586,7 +586,7 @@ int Print::printPreviewList() {
int cnt = 0; int cnt = 0;
Exiv2::PreviewManager pm(*image); Exiv2::PreviewManager pm(*image);
Exiv2::PreviewPropertiesList list = pm.getPreviewProperties(); Exiv2::PreviewPropertiesList list = pm.getPreviewProperties();
for (auto&& pos : list) { for (const auto& pos : list) {
if (manyFiles) { if (manyFiles) {
std::cout << std::setfill(' ') << std::left << std::setw(20) << path_ << " "; std::cout << std::setfill(' ') << std::left << std::setw(20) << path_ << " ";
} }
@ -735,7 +735,7 @@ int Erase::eraseThumbnail(Exiv2::Image* image) {
} }
int Erase::eraseExifData(Exiv2::Image* image) { int Erase::eraseExifData(Exiv2::Image* image) {
if (Params::instance().verbose_ && image->exifData().count() > 0) { if (Params::instance().verbose_ && !image->exifData().empty()) {
std::cout << _("Erasing Exif data from the file") << std::endl; std::cout << _("Erasing Exif data from the file") << std::endl;
} }
image->clearExifData(); image->clearExifData();
@ -743,7 +743,7 @@ int Erase::eraseExifData(Exiv2::Image* image) {
} }
int Erase::eraseIptcData(Exiv2::Image* image) { int Erase::eraseIptcData(Exiv2::Image* image) {
if (Params::instance().verbose_ && image->iptcData().count() > 0) { if (Params::instance().verbose_ && !image->iptcData().empty()) {
std::cout << _("Erasing IPTC data from the file") << std::endl; std::cout << _("Erasing IPTC data from the file") << std::endl;
} }
image->clearIptcData(); image->clearIptcData();
@ -759,7 +759,7 @@ int Erase::eraseComment(Exiv2::Image* image) {
} }
int Erase::eraseXmpData(Exiv2::Image* image) { int Erase::eraseXmpData(Exiv2::Image* image) {
if (Params::instance().verbose_ && image->xmpData().count() > 0) { if (Params::instance().verbose_ && !image->xmpData().empty()) {
std::cout << _("Erasing XMP data from the file") << std::endl; std::cout << _("Erasing XMP data from the file") << std::endl;
} }
image->clearXmpData(); // Quick fix for bug #612 image->clearXmpData(); // Quick fix for bug #612
@ -1141,28 +1141,28 @@ int Modify::applyCommands(Exiv2::Image* pImage) {
} }
// loop through command table and apply each command // loop through command table and apply each command
ModifyCmds& modifyCmds = Params::instance().modifyCmds_; const ModifyCmds& modifyCmds = Params::instance().modifyCmds_;
int rc = 0; int rc = 0;
int ret = 0; int ret = 0;
for (auto&& cmd : modifyCmds) { for (const auto& cmd : modifyCmds) {
switch (cmd.cmdId_) { switch (cmd.cmdId_) {
case add: case CmdId::add:
ret = addMetadatum(pImage, cmd); ret = addMetadatum(pImage, cmd);
if (rc == 0) if (rc == 0)
rc = ret; rc = ret;
break; break;
case set: case CmdId::set:
ret = setMetadatum(pImage, cmd); ret = setMetadatum(pImage, cmd);
if (rc == 0) if (rc == 0)
rc = ret; rc = ret;
break; break;
case del: case CmdId::del:
delMetadatum(pImage, cmd); delMetadatum(pImage, cmd);
break; break;
case reg: case CmdId::reg:
regNamespace(cmd); regNamespace(cmd);
break; break;
case invalidCmdId: case CmdId::invalid:
break; break;
} }
} }
@ -1182,13 +1182,13 @@ int Modify::addMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd) {
auto value = Exiv2::Value::create(modifyCmd.typeId_); auto value = Exiv2::Value::create(modifyCmd.typeId_);
int rc = value->read(modifyCmd.value_); int rc = value->read(modifyCmd.value_);
if (0 == rc) { if (0 == rc) {
if (modifyCmd.metadataId_ == exif) { if (modifyCmd.metadataId_ == MetadataId::exif) {
exifData.add(Exiv2::ExifKey(modifyCmd.key_), value.get()); exifData.add(Exiv2::ExifKey(modifyCmd.key_), value.get());
} }
if (modifyCmd.metadataId_ == iptc) { if (modifyCmd.metadataId_ == MetadataId::iptc) {
iptcData.add(Exiv2::IptcKey(modifyCmd.key_), value.get()); iptcData.add(Exiv2::IptcKey(modifyCmd.key_), value.get());
} }
if (modifyCmd.metadataId_ == xmp) { if (modifyCmd.metadataId_ == MetadataId::xmp) {
xmpData.add(Exiv2::XmpKey(modifyCmd.key_), value.get()); xmpData.add(Exiv2::XmpKey(modifyCmd.key_), value.get());
} }
} else { } else {
@ -1211,19 +1211,19 @@ int Modify::setMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd) {
Exiv2::IptcData& iptcData = pImage->iptcData(); Exiv2::IptcData& iptcData = pImage->iptcData();
Exiv2::XmpData& xmpData = pImage->xmpData(); Exiv2::XmpData& xmpData = pImage->xmpData();
Exiv2::Metadatum* metadatum = nullptr; Exiv2::Metadatum* metadatum = nullptr;
if (modifyCmd.metadataId_ == exif) { if (modifyCmd.metadataId_ == MetadataId::exif) {
auto pos = exifData.findKey(Exiv2::ExifKey(modifyCmd.key_)); auto pos = exifData.findKey(Exiv2::ExifKey(modifyCmd.key_));
if (pos != exifData.end()) { if (pos != exifData.end()) {
metadatum = &(*pos); metadatum = &(*pos);
} }
} }
if (modifyCmd.metadataId_ == iptc) { if (modifyCmd.metadataId_ == MetadataId::iptc) {
auto pos = iptcData.findKey(Exiv2::IptcKey(modifyCmd.key_)); auto pos = iptcData.findKey(Exiv2::IptcKey(modifyCmd.key_));
if (pos != iptcData.end()) { if (pos != iptcData.end()) {
metadatum = &(*pos); metadatum = &(*pos);
} }
} }
if (modifyCmd.metadataId_ == xmp) { if (modifyCmd.metadataId_ == MetadataId::xmp) {
auto pos = xmpData.findKey(Exiv2::XmpKey(modifyCmd.key_)); auto pos = xmpData.findKey(Exiv2::XmpKey(modifyCmd.key_));
if (pos != xmpData.end()) { if (pos != xmpData.end()) {
metadatum = &(*pos); metadatum = &(*pos);
@ -1244,13 +1244,13 @@ int Modify::setMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd) {
if (metadatum) { if (metadatum) {
metadatum->setValue(value.get()); metadatum->setValue(value.get());
} else { } else {
if (modifyCmd.metadataId_ == exif) { if (modifyCmd.metadataId_ == MetadataId::exif) {
exifData.add(Exiv2::ExifKey(modifyCmd.key_), value.get()); exifData.add(Exiv2::ExifKey(modifyCmd.key_), value.get());
} }
if (modifyCmd.metadataId_ == iptc) { if (modifyCmd.metadataId_ == MetadataId::iptc) {
iptcData.add(Exiv2::IptcKey(modifyCmd.key_), value.get()); iptcData.add(Exiv2::IptcKey(modifyCmd.key_), value.get());
} }
if (modifyCmd.metadataId_ == xmp) { if (modifyCmd.metadataId_ == MetadataId::xmp) {
xmpData.add(Exiv2::XmpKey(modifyCmd.key_), value.get()); xmpData.add(Exiv2::XmpKey(modifyCmd.key_), value.get());
} }
} }
@ -1271,21 +1271,21 @@ void Modify::delMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd) {
Exiv2::ExifData& exifData = pImage->exifData(); Exiv2::ExifData& exifData = pImage->exifData();
Exiv2::IptcData& iptcData = pImage->iptcData(); Exiv2::IptcData& iptcData = pImage->iptcData();
Exiv2::XmpData& xmpData = pImage->xmpData(); Exiv2::XmpData& xmpData = pImage->xmpData();
if (modifyCmd.metadataId_ == exif) { if (modifyCmd.metadataId_ == MetadataId::exif) {
Exiv2::ExifData::iterator pos; Exiv2::ExifData::iterator pos;
const Exiv2::ExifKey exifKey(modifyCmd.key_); const Exiv2::ExifKey exifKey(modifyCmd.key_);
while ((pos = exifData.findKey(exifKey)) != exifData.end()) { while ((pos = exifData.findKey(exifKey)) != exifData.end()) {
exifData.erase(pos); exifData.erase(pos);
} }
} }
if (modifyCmd.metadataId_ == iptc) { if (modifyCmd.metadataId_ == MetadataId::iptc) {
Exiv2::IptcData::iterator pos; Exiv2::IptcData::iterator pos;
const Exiv2::IptcKey iptcKey(modifyCmd.key_); const Exiv2::IptcKey iptcKey(modifyCmd.key_);
while ((pos = iptcData.findKey(iptcKey)) != iptcData.end()) { while ((pos = iptcData.findKey(iptcKey)) != iptcData.end()) {
iptcData.erase(pos); iptcData.erase(pos);
} }
} }
if (modifyCmd.metadataId_ == xmp) { if (modifyCmd.metadataId_ == MetadataId::xmp) {
Exiv2::XmpData::iterator pos; Exiv2::XmpData::iterator pos;
const Exiv2::XmpKey xmpKey(modifyCmd.key_); const Exiv2::XmpKey xmpKey(modifyCmd.key_);
if ((pos = xmpData.findKey(xmpKey)) != xmpData.end()) { if ((pos = xmpData.findKey(xmpKey)) != xmpData.end()) {
@ -1407,19 +1407,47 @@ int Adjust::adjustDateTime(Exiv2::ExifData& exifData, const std::string& key, co
std::cerr << path << ": " << _("Failed to parse timestamp") << " `" << timeStr << "'\n"; std::cerr << path << ": " << _("Failed to parse timestamp") << " `" << timeStr << "'\n";
return 1; return 1;
} }
const long monOverflow = (tm.tm_mon + monthAdjustment_) / 12;
tm.tm_mon = (tm.tm_mon + monthAdjustment_) % 12; // bounds checking for yearAdjustment_
tm.tm_year += yearAdjustment_ + monOverflow; enforce<std::overflow_error>(yearAdjustment_ >= std::numeric_limits<decltype(tm.tm_year)>::min(),
"year adjustment too low");
enforce<std::overflow_error>(yearAdjustment_ <= std::numeric_limits<decltype(tm.tm_year)>::max(),
"year adjustment too high");
const auto yearAdjustment = static_cast<decltype(tm.tm_year)>(yearAdjustment_);
// bounds checking for monthAdjustment_
enforce<std::overflow_error>(monthAdjustment_ >= std::numeric_limits<decltype(tm.tm_mon)>::min(),
"month adjustment too low");
enforce<std::overflow_error>(monthAdjustment_ <= std::numeric_limits<decltype(tm.tm_mon)>::max(),
"month adjustment too high");
const auto monthAdjustment = static_cast<decltype(tm.tm_mon)>(monthAdjustment_);
// bounds checking for dayAdjustment_
static constexpr time_t secondsInDay = 24 * 60 * 60;
enforce<std::overflow_error>(dayAdjustment_ >= std::numeric_limits<time_t>::min() / secondsInDay,
"day adjustment too low");
enforce<std::overflow_error>(dayAdjustment_ <= std::numeric_limits<time_t>::max() / secondsInDay,
"day adjustment too high");
const auto dayAdjustment = static_cast<time_t>(dayAdjustment_);
// bounds checking for adjustment_
enforce<std::overflow_error>(adjustment_ >= std::numeric_limits<time_t>::min(), "seconds adjustment too low");
enforce<std::overflow_error>(adjustment_ <= std::numeric_limits<time_t>::max(), "seconds adjustment too high");
const auto adjustment = static_cast<time_t>(adjustment_);
const auto monOverflow = Safe::add(tm.tm_mon, monthAdjustment) / 12;
tm.tm_mon = Safe::add(tm.tm_mon, monthAdjustment) % 12;
tm.tm_year = Safe::add(tm.tm_year, Safe::add(yearAdjustment, monOverflow));
// Let's not create files with non-4-digit years, we can't read them. // Let's not create files with non-4-digit years, we can't read them.
if (tm.tm_year > 9999 - 1900 || tm.tm_year < 1000 - 1900) { if (tm.tm_year > 9999 - 1900 || tm.tm_year < 1000 - 1900) {
if (Params::instance().verbose_) if (Params::instance().verbose_)
std::cout << std::endl; std::cout << std::endl;
std::cerr << path << ": " << _("Can't adjust timestamp by") << " " << yearAdjustment_ + monOverflow << " " std::cerr << path << ": " << _("Can't adjust timestamp by") << " " << yearAdjustment + monOverflow << " "
<< _("years") << "\n"; << _("years") << "\n";
return 1; return 1;
} }
time_t time = mktime(&tm); time_t time = mktime(&tm);
time += adjustment_ + dayAdjustment_ * 86400; time = Safe::add(time, Safe::add(adjustment, dayAdjustment * secondsInDay));
timeStr = time2Str(time); timeStr = time2Str(time);
if (Params::instance().verbose_) { if (Params::instance().verbose_) {
std::cout << " " << _("to") << " " << timeStr << std::endl; std::cout << " " << _("to") << " " << timeStr << std::endl;
@ -1587,25 +1615,31 @@ int str2Tm(const std::string& timeStr, struct tm* tm) {
std::memset(tm, 0x0, sizeof(struct tm)); std::memset(tm, 0x0, sizeof(struct tm));
tm->tm_isdst = -1; tm->tm_isdst = -1;
long tmp = 0; int64_t tmp = 0;
if (!Util::strtol(timeStr.substr(0, 4).c_str(), tmp)) if (!Util::strtol(timeStr.substr(0, 4).c_str(), tmp))
return 5; return 5;
tm->tm_year = tmp - 1900; // tmp is a 4-digit number so this cast cannot overflow
tm->tm_year = static_cast<decltype(tm->tm_year)>(tmp - 1900);
if (!Util::strtol(timeStr.substr(5, 2).c_str(), tmp)) if (!Util::strtol(timeStr.substr(5, 2).c_str(), tmp))
return 6; return 6;
tm->tm_mon = tmp - 1; // tmp is a 2-digit number so this cast cannot overflow
tm->tm_mon = static_cast<decltype(tm->tm_mon)>(tmp - 1);
if (!Util::strtol(timeStr.substr(8, 2).c_str(), tmp)) if (!Util::strtol(timeStr.substr(8, 2).c_str(), tmp))
return 7; return 7;
tm->tm_mday = tmp; // tmp is a 2-digit number so this cast cannot overflow
tm->tm_mday = static_cast<decltype(tm->tm_mday)>(tmp);
if (!Util::strtol(timeStr.substr(11, 2).c_str(), tmp)) if (!Util::strtol(timeStr.substr(11, 2).c_str(), tmp))
return 8; return 8;
tm->tm_hour = tmp; // tmp is a 2-digit number so this cast cannot overflow
tm->tm_hour = static_cast<decltype(tm->tm_hour)>(tmp);
if (!Util::strtol(timeStr.substr(14, 2).c_str(), tmp)) if (!Util::strtol(timeStr.substr(14, 2).c_str(), tmp))
return 9; return 9;
tm->tm_min = tmp; // tmp is a 2-digit number so this cast cannot overflow
tm->tm_min = static_cast<decltype(tm->tm_min)>(tmp);
if (!Util::strtol(timeStr.substr(17, 2).c_str(), tmp)) if (!Util::strtol(timeStr.substr(17, 2).c_str(), tmp))
return 10; return 10;
tm->tm_sec = tmp; // tmp is a 2-digit number so this cast cannot overflow
tm->tm_sec = static_cast<decltype(tm->tm_sec)>(tmp);
// Conversions to set remaining fields of the tm structure // Conversions to set remaining fields of the tm structure
if (mktime(tm) == static_cast<time_t>(-1)) if (mktime(tm) == static_cast<time_t>(-1))
@ -1615,7 +1649,7 @@ int str2Tm(const std::string& timeStr, struct tm* tm) {
} // str2Tm } // str2Tm
std::string time2Str(time_t time) { std::string time2Str(time_t time) {
struct tm* tm = localtime(&time); auto tm = localtime(&time);
return tm2Str(tm); return tm2Str(tm);
} // time2Str } // time2Str
@ -1633,7 +1667,7 @@ std::string tm2Str(const struct tm* tm) {
std::string temporaryPath() { std::string temporaryPath() {
static int count = 0; static int count = 0;
std::lock_guard<std::mutex> guard(cs); auto guard = std::scoped_lock(cs);
#if defined(_MSC_VER) || defined(__MINGW__) #if defined(_MSC_VER) || defined(__MINGW__)
HANDLE process = 0; HANDLE process = 0;
@ -1698,7 +1732,7 @@ int metacopy(const std::string& source, const std::string& tgt, Exiv2::ImageType
std::cout << _("Writing Exif data from") << " " << source << " " << _("to") << " " << target << std::endl; std::cout << _("Writing Exif data from") << " " << source << " " << _("to") << " " << target << std::endl;
} }
if (preserve) { if (preserve) {
for (auto&& exif : sourceImage->exifData()) { for (const auto& exif : sourceImage->exifData()) {
targetImage->exifData()[exif.key()] = exif.value(); targetImage->exifData()[exif.key()] = exif.value();
} }
} else { } else {
@ -1710,7 +1744,7 @@ int metacopy(const std::string& source, const std::string& tgt, Exiv2::ImageType
std::cout << _("Writing IPTC data from") << " " << source << " " << _("to") << " " << target << std::endl; std::cout << _("Writing IPTC data from") << " " << source << " " << _("to") << " " << target << std::endl;
} }
if (preserve) { if (preserve) {
for (auto&& iptc : sourceImage->iptcData()) { for (const auto& iptc : sourceImage->iptcData()) {
targetImage->iptcData()[iptc.key()] = iptc.value(); targetImage->iptcData()[iptc.key()] = iptc.value();
} }
} else { } else {
@ -1723,7 +1757,7 @@ int metacopy(const std::string& source, const std::string& tgt, Exiv2::ImageType
} }
// #1148 use Raw XMP packet if there are no XMP modification commands // #1148 use Raw XMP packet if there are no XMP modification commands
int tRawSidecar = Params::ctXmpSidecar | Params::ctXmpRaw; // option -eXX Params::CommonTarget tRawSidecar = Params::ctXmpSidecar | Params::ctXmpRaw; // option -eXX
if (Params::instance().modifyCmds_.empty() && (Params::instance().target_ & tRawSidecar) == tRawSidecar) { if (Params::instance().modifyCmds_.empty() && (Params::instance().target_ & tRawSidecar) == tRawSidecar) {
// std::cout << "short cut" << std::endl; // std::cout << "short cut" << std::endl;
// http://www.cplusplus.com/doc/tutorial/files/ // http://www.cplusplus.com/doc/tutorial/files/
@ -1733,7 +1767,7 @@ int metacopy(const std::string& source, const std::string& tgt, Exiv2::ImageType
os.close(); os.close();
rc = 0; rc = 0;
} else if (preserve) { } else if (preserve) {
for (auto&& xmp : sourceImage->xmpData()) { for (const auto& xmp : sourceImage->xmpData()) {
targetImage->xmpData()[xmp.key()] = xmp.value(); targetImage->xmpData()[xmp.key()] = xmp.value();
} }
} else { } else {

@ -97,8 +97,10 @@ class TaskFactory {
*/ */
static TaskFactory& instance(); static TaskFactory& instance();
~TaskFactory() = default;
//! Prevent copy construction: not implemented. //! Prevent copy construction: not implemented.
TaskFactory(const TaskFactory&) = delete; TaskFactory(const TaskFactory&) = delete;
TaskFactory& operator=(const TaskFactory&) = delete;
//! Destructor //! Destructor
void cleanup(); void cleanup();
@ -187,10 +189,10 @@ class Adjust : public Task {
private: private:
int adjustDateTime(Exiv2::ExifData& exifData, const std::string& key, const std::string& path) const; int adjustDateTime(Exiv2::ExifData& exifData, const std::string& key, const std::string& path) const;
long adjustment_{0}; int64_t adjustment_{0};
long yearAdjustment_{0}; int64_t yearAdjustment_{0};
long monthAdjustment_{0}; int64_t monthAdjustment_{0};
long dayAdjustment_{0}; int64_t dayAdjustment_{0};
}; // class Adjust }; // class Adjust

@ -1,19 +1,26 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "app_utils.hpp"
#include <climits> #include <climits>
#include <cstdlib> #include <cstdlib>
#include <limits>
namespace Util { namespace Util {
bool strtol(const char* nptr, long& n) { bool strtol(const char* nptr, int64_t& n) {
if (!nptr || *nptr == '\0') if (!nptr || *nptr == '\0')
return false; return false;
char* endptr = nullptr; char* endptr = nullptr;
long tmp = std::strtol(nptr, &endptr, 10); long long tmp = std::strtoll(nptr, &endptr, 10);
if (*endptr != '\0') if (*endptr != '\0')
return false; return false;
if (tmp == LONG_MAX || tmp == LONG_MIN) // strtoll returns LLONG_MAX or LLONG_MIN if an overflow occurs.
if (tmp == LLONG_MAX || tmp == LLONG_MIN)
return false; return false;
n = tmp; if (tmp < std::numeric_limits<int64_t>::min())
return false;
if (tmp > std::numeric_limits<int64_t>::max())
return false;
n = static_cast<int64_t>(tmp);
return true; return true;
} }

@ -3,13 +3,15 @@
#ifndef APP_UTILS_HPP_ #ifndef APP_UTILS_HPP_
#define APP_UTILS_HPP_ #define APP_UTILS_HPP_
#include <cstdint>
namespace Util { namespace Util {
/*! /*!
@brief Convert a C string to a long value, which is returned in n. @brief Convert a C string to an int64_t value, which is returned in n.
Returns true if the conversion is successful, else false. Returns true if the conversion is successful, else false.
n is not modified if the conversion is unsuccessful. See strtol(2). n is not modified if the conversion is unsuccessful. See strtol(2).
*/ */
bool strtol(const char* nptr, long& n); bool strtol(const char* nptr, int64_t& n);
} // namespace Util } // namespace Util
#endif // #ifndef UTILS_HPP_ #endif // #ifndef UTILS_HPP_

@ -34,15 +34,19 @@
// ***************************************************************************** // *****************************************************************************
// local declarations // local declarations
namespace { namespace {
const Params::YodAdjust emptyYodAdjust_[] = { constexpr auto emptyYodAdjust_ = std::array{
{false, "-Y", 0}, Params::YodAdjust{false, "-Y", 0},
{false, "-O", 0}, Params::YodAdjust{false, "-O", 0},
{false, "-D", 0}, Params::YodAdjust{false, "-D", 0},
}; };
//! List of all command identifiers and corresponding strings //! List of all command identifiers and corresponding strings
const CmdIdAndString cmdIdAndString[] = { constexpr auto cmdIdAndString = std::array{
{add, "add"}, {set, "set"}, {del, "del"}, {reg, "reg"}, {invalidCmdId, "invalidCmd"}, // End of list marker CmdIdAndString{CmdId::add, "add"},
CmdIdAndString{CmdId::set, "set"},
CmdIdAndString{CmdId::del, "del"},
CmdIdAndString{CmdId::reg, "reg"},
CmdIdAndString{CmdId::invalid, "invalidCmd"}, // End of list marker
}; };
// Return a command Id for a command string // Return a command Id for a command string
@ -50,7 +54,7 @@ CmdId commandId(const std::string& cmdString);
// Evaluate [-]HH[:MM[:SS]], returns true and sets time to the value // Evaluate [-]HH[:MM[:SS]], returns true and sets time to the value
// in seconds if successful, else returns false. // in seconds if successful, else returns false.
bool parseTime(const std::string& ts, long& time); bool parseTime(const std::string& ts, int64_t& time);
/*! /*!
@brief Parse the oparg string into a bitmap of common targets. @brief Parse the oparg string into a bitmap of common targets.
@ -58,7 +62,7 @@ bool parseTime(const std::string& ts, long& time);
@param action Action being processed @param action Action being processed
@return A bitmap of common targets or -1 in case of a parse error @return A bitmap of common targets or -1 in case of a parse error
*/ */
int parseCommonTargets(const std::string& optArg, const std::string& action); int64_t parseCommonTargets(const std::string& optArg, const std::string& action);
/*! /*!
@brief Parse numbers separated by commas into container @brief Parse numbers separated by commas into container
@ -137,7 +141,7 @@ int main(int argc, char* const argv[]) {
try { try {
// Create the required action class // Create the required action class
auto task = Action::TaskFactory::instance().create(Action::TaskType(params.action_)); auto task = Action::TaskFactory::instance().create(static_cast<Action::TaskType>(params.action_));
// Process all files // Process all files
auto filesCount = params.files_.size(); auto filesCount = params.files_.size();
@ -147,7 +151,7 @@ int main(int argc, char* const argv[]) {
} else { } else {
int w = filesCount > 9 ? filesCount > 99 ? 3 : 2 : 1; int w = filesCount > 9 ? filesCount > 99 ? 3 : 2 : 1;
int n = 1; int n = 1;
for (auto&& file : params.files_) { for (const auto& file : params.files_) {
// If extracting to stdout then ignore verbose // If extracting to stdout then ignore verbose
if (params.verbose_ && !(params.action_ & Action::extract && params.target_ & Params::ctStdInOut)) { if (params.verbose_ && !(params.action_ & Action::extract && params.target_ & Params::ctStdInOut)) {
std::cout << _("File") << " " << std::setw(w) << std::right << n++ << "/" << filesCount << ": " << file std::cout << _("File") << " " << std::setw(w) << std::right << n++ << "/" << filesCount << ": " << file
@ -279,14 +283,16 @@ void Params::help(std::ostream& os) const {
<< _(" X : Extract \"raw\" XMP\n") << _(" X : Extract \"raw\" XMP\n")
<< _(" -P flgs Print flags for fine control of tag lists ('print' action):\n") << _(" -P flgs Print flags for fine control of tag lists ('print' action):\n")
<< _(" E : Exif tags\n") << _(" I : IPTC tags\n") << _(" X : XMP tags\n") << _(" E : Exif tags\n") << _(" I : IPTC tags\n") << _(" X : XMP tags\n")
<< _(" x : Tag number (Exif and IPTC only)\n") << _(" x : Tag number for Exif or IPTC tags (in hexadecimal)\n")
<< _(" g : Group name (e.g. Exif.Photo.UserComment, Photo)\n") << _(" g : Group name (e.g. Exif.Photo.UserComment, Photo)\n")
<< _(" k : Key (e.g. Exif.Photo.UserComment)\n") << _(" k : Key (e.g. Exif.Photo.UserComment)\n")
<< _(" l : Tag label (e.g. Exif.Photo.UserComment, 'User comment')\n") << _(" l : Tag label (e.g. Exif.Photo.UserComment, 'User comment')\n")
<< _(" d : Tag description\n")
<< _(" n : Tag name (e.g. Exif.Photo.UserComment, UserComment)\n") << _(" y : Type\n") << _(" n : Tag name (e.g. Exif.Photo.UserComment, UserComment)\n") << _(" y : Type\n")
<< _(" c : Number of components (count)\n") << _(" y : Type\n") << _(" c : Number of components (count)\n")
<< _(" s : Size in bytes (Ascii and Comment types include NULL)\n") << _(" s : Size in bytes of vanilla value (may include NULL)\n")
<< _(" v : Plain data value, untranslated (vanilla)\n") << _(" v : Plain data value of untranslated (vanilla)\n")
<< _(" V : Plain data value, data type and the word 'set'\n")
<< _(" t : Interpreted (translated) human readable values\n") << _(" t : Interpreted (translated) human readable values\n")
<< _(" h : Hex dump of the data\n") << _(" h : Hex dump of the data\n")
<< _(" -d tgt1 Delete target(s) for the 'delete' action. Possible targets are:\n") << _(" -d tgt1 Delete target(s) for the 'delete' action. Possible targets are:\n")
@ -672,13 +678,13 @@ int Params::evalPrintFlags(const std::string& optArg) {
for (auto&& i : optArg) { for (auto&& i : optArg) {
switch (i) { switch (i) {
case 'E': case 'E':
printTags_ |= Exiv2::mdExif; printTags_ |= MetadataId::exif;
break; break;
case 'I': case 'I':
printTags_ |= Exiv2::mdIptc; printTags_ |= MetadataId::iptc;
break; break;
case 'X': case 'X':
printTags_ |= Exiv2::mdXmp; printTags_ |= MetadataId::xmp;
break; break;
case 'x': case 'x':
printItems_ |= prTag; printItems_ |= prTag;
@ -716,6 +722,9 @@ int Params::evalPrintFlags(const std::string& optArg) {
case 'V': case 'V':
printItems_ |= prSet | prKey | prType | prValue; printItems_ |= prSet | prKey | prType | prValue;
break; break;
case 'd':
printItems_ |= prDesc;
break;
default: default:
std::cerr << progname() << ": " << _("Unrecognized print item") << " `" << i << "'\n"; std::cerr << progname() << ": " << _("Unrecognized print item") << " `" << i << "'\n";
rc = 1; rc = 1;
@ -735,81 +744,68 @@ int Params::evalPrintFlags(const std::string& optArg) {
} // Params::evalPrintFlags } // Params::evalPrintFlags
int Params::evalDelete(const std::string& optArg) { int Params::evalDelete(const std::string& optArg) {
int rc = 0;
switch (action_) { switch (action_) {
case Action::none: case Action::none:
action_ = Action::erase; action_ = Action::erase;
target_ = 0; target_ = static_cast<CommonTarget>(0);
// fallthrough // fallthrough
case Action::erase: case Action::erase: {
rc = parseCommonTargets(optArg, "erase"); const auto rc = parseCommonTargets(optArg, "erase");
if (rc > 0) { if (rc > 0) {
target_ |= rc; target_ |= static_cast<CommonTarget>(rc);
rc = 0; return 0;
} else { }
rc = 1; return 1;
} }
break;
default: default:
std::cerr << progname() << ": " << _("Option -d is not compatible with a previous option\n"); std::cerr << progname() << ": " << _("Option -d is not compatible with a previous option\n");
rc = 1; return 1;
break;
} }
return rc;
} // Params::evalDelete } // Params::evalDelete
int Params::evalExtract(const std::string& optArg) { int Params::evalExtract(const std::string& optArg) {
int rc = 0;
switch (action_) { switch (action_) {
case Action::none: case Action::none:
case Action::modify: case Action::modify:
action_ = Action::extract; action_ = Action::extract;
target_ = 0; target_ = static_cast<CommonTarget>(0);
// fallthrough // fallthrough
case Action::extract: case Action::extract: {
rc = parseCommonTargets(optArg, "extract"); const auto rc = parseCommonTargets(optArg, "extract");
if (rc > 0) { if (rc > 0) {
target_ |= rc; target_ |= static_cast<CommonTarget>(rc);
rc = 0; return 0;
} else { }
rc = 1; return 1;
} }
break;
default: default:
std::cerr << progname() << ": " << _("Option -e is not compatible with a previous option\n"); std::cerr << progname() << ": " << _("Option -e is not compatible with a previous option\n");
rc = 1; return 1;
break;
} }
return rc;
} // Params::evalExtract } // Params::evalExtract
int Params::evalInsert(const std::string& optArg) { int Params::evalInsert(const std::string& optArg) {
int rc = 0;
switch (action_) { switch (action_) {
case Action::none: case Action::none:
case Action::modify: case Action::modify:
action_ = Action::insert; action_ = Action::insert;
target_ = 0; target_ = static_cast<CommonTarget>(0);
// fallthrough // fallthrough
case Action::insert: case Action::insert: {
rc = parseCommonTargets(optArg, "insert"); const auto rc = parseCommonTargets(optArg, "insert");
if (rc > 0) { if (rc > 0) {
target_ |= rc; target_ |= static_cast<CommonTarget>(rc);
rc = 0; return 0;
} else { }
rc = 1; return 1;
} }
break;
default: default:
std::cerr << progname() << ": " << _("Option -i is not compatible with a previous option\n"); std::cerr << progname() << ": " << _("Option -i is not compatible with a previous option\n");
rc = 1; return 1;
break;
} }
return rc;
} // Params::evalInsert } // Params::evalInsert
int Params::evalModify(int opt, const std::string& optArg) { int Params::evalModify(int opt, const std::string& optArg) {
int rc = 0;
switch (action_) { switch (action_) {
case Action::none: case Action::none:
action_ = Action::modify; action_ = Action::modify;
@ -823,14 +819,12 @@ int Params::evalModify(int opt, const std::string& optArg) {
cmdFiles_.push_back(optArg); // parse the files later cmdFiles_.push_back(optArg); // parse the files later
if (opt == 'M') if (opt == 'M')
cmdLines_.push_back(optArg); // parse the commands later cmdLines_.push_back(optArg); // parse the commands later
break; return 0;
default: default:
std::cerr << progname() << ": " << _("Option") << " -" << static_cast<char>(opt) << " " std::cerr << progname() << ": " << _("Option") << " -" << static_cast<char>(opt) << " "
<< _("is not compatible with a previous option\n"); << _("is not compatible with a previous option\n");
rc = 1; return 1;
break;
} }
return rc;
} // Params::evalModify } // Params::evalModify
int Params::nonoption(const std::string& argv) { int Params::nonoption(const std::string& argv) {
@ -1090,11 +1084,11 @@ cleanup:
// ***************************************************************************** // *****************************************************************************
// local implementations // local implementations
namespace { namespace {
bool parseTime(const std::string& ts, long& time) { bool parseTime(const std::string& ts, int64_t& time) {
std::string hstr, mstr, sstr; std::string hstr, mstr, sstr;
auto cts = new char[ts.length() + 1]; auto cts = new char[ts.length() + 1];
strcpy(cts, ts.c_str()); strcpy(cts, ts.c_str());
char* tmp = ::strtok(cts, ":"); auto tmp = ::strtok(cts, ":");
if (tmp) if (tmp)
hstr = tmp; hstr = tmp;
tmp = ::strtok(nullptr, ":"); tmp = ::strtok(nullptr, ":");
@ -1106,7 +1100,7 @@ bool parseTime(const std::string& ts, long& time) {
delete[] cts; delete[] cts;
int sign = 1; int sign = 1;
long hh(0), mm(0), ss(0); int64_t hh(0), mm(0), ss(0);
// [-]HH part // [-]HH part
if (!Util::strtol(hstr.c_str(), hh)) if (!Util::strtol(hstr.c_str(), hh))
return false; return false;
@ -1145,11 +1139,11 @@ void printUnrecognizedArgument(const char argc, const std::string& action) {
<< argc << "'\n"; << argc << "'\n";
} }
int parseCommonTargets(const std::string& optArg, const std::string& action) { int64_t parseCommonTargets(const std::string& optArg, const std::string& action) {
int rc = 0; int64_t rc = 0;
int target = 0; auto target = static_cast<Params::CommonTarget>(0);
int all = Params::ctExif | Params::ctIptc | Params::ctComment | Params::ctXmp; Params::CommonTarget all = Params::ctExif | Params::ctIptc | Params::ctComment | Params::ctXmp;
int extra = Params::ctXmpSidecar | Params::ctExif | Params::ctIptc | Params::ctXmp; Params::CommonTarget extra = Params::ctXmpSidecar | Params::ctExif | Params::ctIptc | Params::ctXmp;
for (size_t i = 0; rc == 0 && i < optArg.size(); ++i) { for (size_t i = 0; rc == 0 && i < optArg.size(); ++i) {
switch (optArg[i]) { switch (optArg[i]) {
case 'e': case 'e':
@ -1183,7 +1177,7 @@ int parseCommonTargets(const std::string& optArg, const std::string& action) {
target |= extra; // -eX target |= extra; // -eX
if (i > 0) { // -eXX or -iXX if (i > 0) { // -eXX or -iXX
target |= Params::ctXmpRaw; target |= Params::ctXmpRaw;
target &= ~extra; // turn off those bits target = static_cast<Params::CommonTarget>(target & ~extra); // turn off those bits
} }
break; break;
@ -1204,7 +1198,7 @@ int parseCommonTargets(const std::string& optArg, const std::string& action) {
break; break;
} }
} }
return rc ? rc : target; return rc ? rc : static_cast<int64_t>(target);
} }
int parsePreviewNumbers(Params::PreviewNumbers& previewNumbers, const std::string& optArg, int j) { int parsePreviewNumbers(Params::PreviewNumbers& previewNumbers, const std::string& optArg, int j) {
@ -1334,38 +1328,38 @@ bool parseLine(ModifyCmd& modifyCmd, const std::string& line, int num) {
std::string cmd(line.substr(cmdStart, cmdEnd - cmdStart)); std::string cmd(line.substr(cmdStart, cmdEnd - cmdStart));
CmdId cmdId = commandId(cmd); CmdId cmdId = commandId(cmd);
if (cmdId == invalidCmdId) { if (cmdId == CmdId::invalid) {
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage,
Exiv2::toString(num) + ": " + _("Invalid command") + " `" + cmd + "'"); Exiv2::toString(num) + ": " + _("Invalid command") + " `" + cmd + "'");
} }
Exiv2::TypeId defaultType = Exiv2::invalidTypeId; Exiv2::TypeId defaultType = Exiv2::invalidTypeId;
std::string key(line.substr(keyStart, keyEnd - keyStart)); std::string key(line.substr(keyStart, keyEnd - keyStart));
MetadataId metadataId = invalidMetadataId; MetadataId metadataId = MetadataId::invalid;
if (cmdId != reg) { if (cmdId != CmdId::reg) {
try { try {
Exiv2::IptcKey iptcKey(key); Exiv2::IptcKey iptcKey(key);
metadataId = iptc; metadataId = MetadataId::iptc;
defaultType = Exiv2::IptcDataSets::dataSetType(iptcKey.tag(), iptcKey.record()); defaultType = Exiv2::IptcDataSets::dataSetType(iptcKey.tag(), iptcKey.record());
} catch (const Exiv2::Error&) { } catch (const Exiv2::Error&) {
} }
if (metadataId == invalidMetadataId) { if (metadataId == MetadataId::invalid) {
try { try {
Exiv2::ExifKey exifKey(key); Exiv2::ExifKey exifKey(key);
metadataId = exif; metadataId = MetadataId::exif;
defaultType = exifKey.defaultTypeId(); defaultType = exifKey.defaultTypeId();
} catch (const Exiv2::Error&) { } catch (const Exiv2::Error&) {
} }
} }
if (metadataId == invalidMetadataId) { if (metadataId == MetadataId::invalid) {
try { try {
Exiv2::XmpKey xmpKey(key); Exiv2::XmpKey xmpKey(key);
metadataId = xmp; metadataId = MetadataId::xmp;
defaultType = Exiv2::XmpProperties::propertyType(xmpKey); defaultType = Exiv2::XmpProperties::propertyType(xmpKey);
} catch (const Exiv2::Error&) { } catch (const Exiv2::Error&) {
} }
} }
if (metadataId == invalidMetadataId) { if (metadataId == MetadataId::invalid) {
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage,
Exiv2::toString(num) + ": " + _("Invalid key") + " `" + key + "'"); Exiv2::toString(num) + ": " + _("Invalid key") + " `" + key + "'");
} }
@ -1373,7 +1367,7 @@ bool parseLine(ModifyCmd& modifyCmd, const std::string& line, int num) {
std::string value; std::string value;
Exiv2::TypeId type = defaultType; Exiv2::TypeId type = defaultType;
bool explicitType = false; bool explicitType = false;
if (cmdId != del) { if (cmdId != CmdId::del) {
// Get type and value // Get type and value
std::string::size_type typeStart = std::string::npos; std::string::size_type typeStart = std::string::npos;
if (keyEnd != std::string::npos) if (keyEnd != std::string::npos)
@ -1386,12 +1380,12 @@ bool parseLine(ModifyCmd& modifyCmd, const std::string& line, int num) {
if (valStart != std::string::npos) if (valStart != std::string::npos)
valEnd = line.find_last_not_of(delim); valEnd = line.find_last_not_of(delim);
if (cmdId == reg && (keyEnd == std::string::npos || valStart == std::string::npos)) { if (cmdId == CmdId::reg && (keyEnd == std::string::npos || valStart == std::string::npos)) {
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage,
Exiv2::toString(num) + ": " + _("Invalid command line") + " "); Exiv2::toString(num) + ": " + _("Invalid command line") + " ");
} }
if (cmdId != reg && typeStart != std::string::npos && typeEnd != std::string::npos) { if (cmdId != CmdId::reg && typeStart != std::string::npos && typeEnd != std::string::npos) {
std::string typeStr(line.substr(typeStart, typeEnd - typeStart)); std::string typeStr(line.substr(typeStart, typeEnd - typeStart));
Exiv2::TypeId tmpType = Exiv2::TypeInfo::typeId(typeStr); Exiv2::TypeId tmpType = Exiv2::TypeInfo::typeId(typeStr);
if (tmpType != Exiv2::invalidTypeId) { if (tmpType != Exiv2::invalidTypeId) {
@ -1421,7 +1415,7 @@ bool parseLine(ModifyCmd& modifyCmd, const std::string& line, int num) {
modifyCmd.explicitType_ = explicitType; modifyCmd.explicitType_ = explicitType;
modifyCmd.value_ = value; modifyCmd.value_ = value;
if (cmdId == reg) { if (cmdId == CmdId::reg) {
if (value.empty()) { if (value.empty()) {
throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage, throw Exiv2::Error(Exiv2::ErrorCode::kerErrorMessage,
Exiv2::toString(num) + ": " + _("Empty value for key") + +" `" + key + "'"); Exiv2::toString(num) + ": " + _("Empty value for key") + +" `" + key + "'");
@ -1436,11 +1430,8 @@ bool parseLine(ModifyCmd& modifyCmd, const std::string& line, int num) {
} // parseLine } // parseLine
CmdId commandId(const std::string& cmdString) { CmdId commandId(const std::string& cmdString) {
int i = 0; auto it = std::find_if(cmdIdAndString.begin(), cmdIdAndString.end(), [&](auto cs) { return cs.second == cmdString; });
while (cmdIdAndString[i].first != invalidCmdId && cmdIdAndString[i].second != cmdString) { return it != cmdIdAndString.end() ? it->first : CmdId::invalid;
++i;
}
return cmdIdAndString[i].first;
} }
std::string parseEscapes(const std::string& input) { std::string parseEscapes(const std::string& input) {
@ -1452,7 +1443,7 @@ std::string parseEscapes(const std::string& input) {
continue; continue;
} }
size_t escapeStart = i; size_t escapeStart = i;
if (!(input.length() - 1 > i)) { if (input.length() - 1 <= i) {
result.push_back(ch); result.push_back(ch);
continue; continue;
} }
@ -1473,7 +1464,7 @@ std::string parseEscapes(const std::string& input) {
break; break;
case 'u': // Escaping of unicode case 'u': // Escaping of unicode
if (input.length() >= 4 && input.length() - 4 > i) { if (input.length() >= 4 && input.length() - 4 > i) {
int acc = 0; uint32_t acc = 0;
for (int j = 0; j < 4; ++j) { for (int j = 0; j < 4; ++j) {
++i; ++i;
acc <<= 4; acc <<= 4;
@ -1484,19 +1475,19 @@ std::string parseEscapes(const std::string& input) {
} else if (input[i] >= 'A' && input[i] <= 'F') { } else if (input[i] >= 'A' && input[i] <= 'F') {
acc |= input[i] - 'A' + 10; acc |= input[i] - 'A' + 10;
} else { } else {
acc = -1; acc = 0xFFFFFFFF;
break; break;
} }
} }
if (acc == -1) { if (acc == 0xFFFFFFFF) {
result.push_back('\\'); result.push_back('\\');
i = escapeStart; i = escapeStart;
break; break;
} }
std::string ucs2toUtf8; std::string ucs2toUtf8;
ucs2toUtf8.push_back(static_cast<char>((acc & 0xff00) >> 8)); ucs2toUtf8.push_back(static_cast<char>((acc & 0xff00U) >> 8));
ucs2toUtf8.push_back(static_cast<char>(acc & 0x00ff)); ucs2toUtf8.push_back(static_cast<char>(acc & 0x00ffU));
if (Exiv2::convertStringCharset(ucs2toUtf8, "UCS-2BE", "UTF-8")) { if (Exiv2::convertStringCharset(ucs2toUtf8, "UCS-2BE", "UTF-8")) {
result.append(ucs2toUtf8); result.append(ucs2toUtf8);

@ -21,28 +21,40 @@
#include <set> #include <set>
//! Command identifiers //! Command identifiers
enum CmdId { enum class CmdId {
invalidCmdId, invalid,
add, add,
set, set,
del, del,
reg, reg,
}; };
//! Metadata identifiers //! Metadata identifiers
enum MetadataId { enum class MetadataId : uint32_t {
invalidMetadataId = Exiv2::mdNone, // 0 invalid = Exiv2::mdNone, // 0
exif = Exiv2::mdExif, // 1 exif = Exiv2::mdExif, // 1
iptc = Exiv2::mdIptc, // 2 iptc = Exiv2::mdIptc, // 2
xmp = Exiv2::mdXmp, // 8 xmp = Exiv2::mdXmp, // 8
}; };
inline MetadataId operator&(MetadataId x, MetadataId y) {
return static_cast<MetadataId>(static_cast<uint32_t>(x) & static_cast<uint32_t>(y));
}
inline MetadataId operator|(MetadataId x, MetadataId y) {
return static_cast<MetadataId>(static_cast<uint32_t>(x) | static_cast<uint32_t>(y));
}
inline MetadataId& operator|=(MetadataId& x, MetadataId y) {
return x = x | y;
}
//! Structure for one parsed modification command //! Structure for one parsed modification command
struct ModifyCmd { struct ModifyCmd {
//! C'tor //! C'tor
ModifyCmd() = default; ModifyCmd() = default;
CmdId cmdId_{invalidCmdId}; //!< Command identifier CmdId cmdId_{CmdId::invalid}; //!< Command identifier
std::string key_; //!< Exiv2 key string std::string key_; //!< Exiv2 key string
MetadataId metadataId_{invalidMetadataId}; //!< Metadata identifier MetadataId metadataId_{MetadataId::invalid}; //!< Metadata identifier
Exiv2::TypeId typeId_{Exiv2::invalidTypeId}; //!< Exiv2 type identifier Exiv2::TypeId typeId_{Exiv2::invalidTypeId}; //!< Exiv2 type identifier
//! Flag to indicate if the type was explicitly specified (true) //! Flag to indicate if the type was explicitly specified (true)
bool explicitType_{false}; bool explicitType_{false};
@ -51,7 +63,7 @@ struct ModifyCmd {
//! Container for modification commands //! Container for modification commands
using ModifyCmds = std::vector<ModifyCmd>; using ModifyCmds = std::vector<ModifyCmd>;
//! Structure to link command identifiers to strings //! Structure to link command identifiers to strings
using CmdIdAndString = std::pair<CmdId, std::string>; using CmdIdAndString = std::pair<CmdId, std::string_view>;
/*! /*!
@brief Implements the command line handling for the program. @brief Implements the command line handling for the program.
@ -110,7 +122,9 @@ class Params : public Util::Getopt {
static Params& instance(); static Params& instance();
//! Prevent copy-construction: not implemented. //! Prevent copy-construction: not implemented.
~Params() override = default;
Params(const Params&) = delete; Params(const Params&) = delete;
Params& operator=(const Params&) = delete;
//! Enumerates print modes //! Enumerates print modes
enum PrintMode { enum PrintMode {
@ -125,7 +139,7 @@ class Params : public Util::Getopt {
}; };
//! Individual items to print, bitmap //! Individual items to print, bitmap
enum PrintItem { enum PrintItem : uint32_t {
prTag = 1, prTag = 1,
prGroup = 2, prGroup = 2,
prKey = 4, prKey = 4,
@ -137,11 +151,12 @@ class Params : public Util::Getopt {
prValue = 256, prValue = 256,
prTrans = 512, prTrans = 512,
prHex = 1024, prHex = 1024,
prSet = 2048 prSet = 2048,
prDesc = 4096
}; };
//! Enumerates common targets, bitmap //! Enumerates common targets, bitmap
enum CommonTarget { enum CommonTarget : uint32_t {
ctExif = 1, ctExif = 1,
ctIptc = 2, ctIptc = 2,
ctComment = 4, ctComment = 4,
@ -173,7 +188,7 @@ class Params : public Util::Getopt {
struct YodAdjust { struct YodAdjust {
bool flag_; //!< Adjustment flag. bool flag_; //!< Adjustment flag.
const char* option_; //!< Adjustment option string. const char* option_; //!< Adjustment option string.
long adjustment_; //!< Adjustment value. int64_t adjustment_; //!< Adjustment value.
}; };
bool help_{false}; //!< Help option flag. bool help_{false}; //!< Help option flag.
@ -188,14 +203,14 @@ class Params : public Util::Getopt {
FileExistsPolicy fileExistsPolicy_{askPolicy}; //!< What to do if file to rename exists. FileExistsPolicy fileExistsPolicy_{askPolicy}; //!< What to do if file to rename exists.
bool adjust_{false}; //!< Adjustment flag. bool adjust_{false}; //!< Adjustment flag.
PrintMode printMode_{pmSummary}; //!< Print mode. PrintMode printMode_{pmSummary}; //!< Print mode.
unsigned long printItems_{0}; //!< Print items. PrintItem printItems_{0}; //!< Print items.
unsigned long printTags_{Exiv2::mdNone}; //!< Print tags (bitmap of MetadataId flags). MetadataId printTags_{Exiv2::mdNone}; //!< Print tags (bitmap of MetadataId flags).
//! %Action (integer rather than TaskType to avoid dependency). //! %Action (integer rather than TaskType to avoid dependency).
int action_{0}; int action_{0};
int target_; //!< What common target to process. CommonTarget target_; //!< What common target to process.
long adjustment_{0}; //!< Adjustment in seconds. int64_t adjustment_{0}; //!< Adjustment in seconds.
YodAdjust yodAdjust_[3]; //!< Year, month and day adjustment info. std::array<YodAdjust, 3> yodAdjust_; //!< Year, month and day adjustment info.
std::string format_; //!< Filename format (-r option arg). std::string format_; //!< Filename format (-r option arg).
bool formatSet_{false}; //!< Whether the format is set with -r bool formatSet_{false}; //!< Whether the format is set with -r
CmdFiles cmdFiles_; //!< Names of the modification command files CmdFiles cmdFiles_; //!< Names of the modification command files
@ -270,4 +285,20 @@ class Params : public Util::Getopt {
}; // class Params }; // class Params
inline Params::CommonTarget operator|(Params::CommonTarget x, Params::CommonTarget y) {
return static_cast<Params::CommonTarget>(static_cast<uint32_t>(x) | static_cast<uint32_t>(y));
}
inline Params::CommonTarget& operator|=(Params::CommonTarget& x, Params::CommonTarget y) {
return x = x | y;
}
inline Params::PrintItem operator|(Params::PrintItem x, Params::PrintItem y) {
return static_cast<Params::PrintItem>(static_cast<uint32_t>(x) | static_cast<uint32_t>(y));
}
inline Params::PrintItem& operator|=(Params::PrintItem& x, Params::PrintItem y) {
return x = x | y;
}
#endif // #ifndef EXIV2APP_HPP_ #endif // #ifndef EXIV2APP_HPP_

@ -62,10 +62,10 @@
/* Define to the version of this package. */ /* Define to the version of this package. */
#cmakedefine EXV_PACKAGE_VERSION "@PROJECT_VERSION@" #cmakedefine EXV_PACKAGE_VERSION "@PROJECT_VERSION@"
#define EXIV2_MAJOR_VERSION (@PROJECT_VERSION_MAJOR@) #define EXIV2_MAJOR_VERSION (@PROJECT_VERSION_MAJOR@U)
#define EXIV2_MINOR_VERSION (@PROJECT_VERSION_MINOR@) #define EXIV2_MINOR_VERSION (@PROJECT_VERSION_MINOR@U)
#define EXIV2_PATCH_VERSION (@PROJECT_VERSION_PATCH@) #define EXIV2_PATCH_VERSION (@PROJECT_VERSION_PATCH@U)
#define EXIV2_TWEAK_VERSION (@PROJECT_VERSION_TWEAK@) #define EXIV2_TWEAK_VERSION (@PROJECT_VERSION_TWEAK@U)
// Definition to enable translation of Nikon lens names. // Definition to enable translation of Nikon lens names.
#cmakedefine EXV_HAVE_LENSDATA #cmakedefine EXV_HAVE_LENSDATA

@ -1,5 +1,24 @@
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
if (CONAN_AUTO_INSTALL)
# Download automatically the cmake-conan integration file
if(NOT EXISTS "${CMAKE_BINARY_DIR}/conan.cmake")
message(STATUS "Downloading conan.cmake from https://github.com/conan-io/cmake-conan")
file(DOWNLOAD "https://raw.githubusercontent.com/conan-io/cmake-conan/master/conan.cmake"
"${CMAKE_BINARY_DIR}/conan.cmake"
TLS_VERIFY ON)
endif()
include(${CMAKE_BINARY_DIR}/conan.cmake)
conan_cmake_autodetect(settings)
conan_cmake_install(PATH_OR_REFERENCE ..
BUILD missing
REMOTE conancenter
OPTIONS webready=True
SETTINGS ${settings})
endif()
if (APPLE) if (APPLE)
# On Apple, we use the conan cmake_paths generator # On Apple, we use the conan cmake_paths generator
if (EXISTS ${CMAKE_BINARY_DIR}/conan_paths.cmake) if (EXISTS ${CMAKE_BINARY_DIR}/conan_paths.cmake)

@ -21,10 +21,10 @@ class Exiv2Conan(ConanFile):
self.options['gtest'].shared = False self.options['gtest'].shared = False
def requirements(self): def requirements(self):
self.requires('zlib/1.2.11') self.requires('zlib/1.2.12')
if self.options.webready: if self.options.webready:
self.requires('libcurl/7.79.0') self.requires('libcurl/7.80.0')
if os_info.is_windows and self.options.iconv: if os_info.is_windows and self.options.iconv:
self.requires('libiconv/1.16') self.requires('libiconv/1.16')
@ -37,7 +37,7 @@ class Exiv2Conan(ConanFile):
if self.options.xmp: if self.options.xmp:
self.requires('XmpSdk/2016.7@piponazo/stable') # from conan-piponazo self.requires('XmpSdk/2016.7@piponazo/stable') # from conan-piponazo
else: else:
self.requires('expat/2.4.1') self.requires('expat/2.4.8')
def imports(self): def imports(self):
self.copy('*.dll', dst='bin', src='bin') self.copy('*.dll', dst='bin', src='bin')

@ -566,6 +566,7 @@ as well as data columns included in the print output. Valid flags are:
| g | Group name (e.g., for Exif.Photo.UserComment, outputs Photo) | | g | Group name (e.g., for Exif.Photo.UserComment, outputs Photo) |
| k | Key (e.g., Exif.Photo.UserComment) | | k | Key (e.g., Exif.Photo.UserComment) |
| l | Tag label (human-readable tagname, e.g., for Exif.Photo.UserComment, outputs 'User comment') | | l | Tag label (human-readable tagname, e.g., for Exif.Photo.UserComment, outputs 'User comment') |
| d | Tag description |
| n | Tag name (e.g., for Exif.Photo.UserComment, outputs UserComment) | | n | Tag name (e.g., for Exif.Photo.UserComment, outputs UserComment) |
| y | Type (for available types, see [Exif/IPTC/XMP types](#exiv2_types)) | | y | Type (for available types, see [Exif/IPTC/XMP types](#exiv2_types)) |
| c | Number of components (for single entry types, the number of **sizeof('type')** in 'size'. For multi-entry types, the number of entries. See [Exif/IPTC/XMP types](#exiv2_types)) | | c | Number of components (for single entry types, the number of **sizeof('type')** in 'size'. For multi-entry types, the number of entries. See [Exif/IPTC/XMP types](#exiv2_types)) |
@ -575,25 +576,23 @@ as well as data columns included in the print output. Valid flags are:
| t | Interpreted (translated) human-readable data values (includes plain vanilla values) | | t | Interpreted (translated) human-readable data values (includes plain vanilla values) |
| h | Hex dump of the data | | h | Hex dump of the data |
**--Print** *flgs* can be combined with [--grep str](#grep_str) or
[--key key](#key_key) to further filter the output.
<div id="Print_flgs_order"> <div id="Print_flgs_order">
The order of the values in *flgs* is not respected. For example, the order The order of the values in *flgs* is not respected and is output as follows:
of the columns, using some tags from *Stonehenge.jpg*, is as follows:
``` | Tag number<br>(x) | Plain 'set'<br>(V) | Group<br>(g) | Key<br>(k) | Tagname<br>(n) | Tagname label<br>(l) |Description<br>(d) | Type<br>(y) | Comp<br>(c) | Size<br>(s) | Value<br>(v) | Translated<br>(t) |
$ curl --silent -O https://www.exiv2.org/Stonehenge.jpg |:------ |:---- |:------ |:------ |:------ |:------ |:------ |:------ |:------ |:------ |:--- |:------ |
$ exiv2 --Print xgknlycst Stonehenge.jpg
```
| Tag number<br>(x) | Plain 'set'<br>(V) | Group<br>(g) | Key<br>(k) | Tagname<br>(n) | Tagname label<br>(l) | Type<br>(y) | Comp<br>(c) | Size<br>(s) | Value<br>(E, I, X, v, t) | Translated<br>(t) | For example,
|:------ |:---- |:------ |:------ |:------ |:------ |:------ |:------ |:------ |:------ |:------ |
| 0x0110 | set | Image | Exif.Image.Model | Model | Model | Ascii | 12 | 12 | NIKON D5300 | NIKON D5300 |
| 0x0006 | set | NikonIi | Exif.NikonIi.ISO2 | ISO2 | ISO 2 | Byte | 1 | 1 | 72 | 200 |
| 0x0000 | set | xmp | Xmp.xmp.Rating | Rating | Rating | XmpText | 1 | 1 | 0 | 0 |
| 0x0000 | set | dc | Xmp.dc.Family | Family | Family | XmpBag | 1 | 5 | Robin | Robin |
**--Print** *flgs* can be combined with [--grep str](#grep_str) or ```bash
[--key key](#key_key) to further filter the output. $ curl --silent -O https://www.exiv2.org/Stonehenge.jpg
$ exiv2 --Print xVgknldycsvt -K Exif.Nikon3.Quality Stonehenge.jpg
0x0004 set Nikon3 Exif.Nikon3.Quality Quality Quality Image quality setting Ascii 8 8 NORMAL NORMAL
```
<div id="delete_tgt1"> <div id="delete_tgt1">

@ -198,10 +198,9 @@ class EXIV2API BasicIo {
//@{ //@{
/*! /*!
@brief Get the current IO position. @brief Get the current IO position.
@return Offset from the start of IO if successful;<BR> @return Offset from the start of IO
-1 if failure;
*/ */
[[nodiscard]] virtual long tell() const = 0; [[nodiscard]] virtual size_t tell() const = 0;
/*! /*!
@brief Get the current size of the IO source in bytes. @brief Get the current size of the IO source in bytes.
@return Size of the IO source in bytes;<BR> @return Size of the IO source in bytes;<BR>
@ -439,10 +438,9 @@ class EXIV2API FileIo : public BasicIo {
//@{ //@{
/*! /*!
@brief Get the current file position. @brief Get the current file position.
@return Offset from the start of the file if successful;<BR> @return Offset from the start of the file
-1 if failure;
*/ */
[[nodiscard]] long tell() const override; [[nodiscard]] size_t tell() const override;
/*! /*!
@brief Flush any buffered writes and get the current file size @brief Flush any buffered writes and get the current file size
in bytes. in bytes.
@ -624,7 +622,7 @@ class EXIV2API MemIo : public BasicIo {
@brief Get the current IO position. @brief Get the current IO position.
@return Offset from the start of the memory block @return Offset from the start of the memory block
*/ */
[[nodiscard]] long tell() const override; [[nodiscard]] size_t tell() const override;
/*! /*!
@brief Get the current memory buffer size in bytes. @brief Get the current memory buffer size in bytes.
@return Size of the in memory data in bytes;<BR> @return Size of the in memory data in bytes;<BR>
@ -695,12 +693,12 @@ class EXIV2API XPathIo : public FileIo {
@brief The extension of the temporary file which is created when getting input data @brief The extension of the temporary file which is created when getting input data
to read metadata. This file will be deleted in destructor. to read metadata. This file will be deleted in destructor.
*/ */
static constexpr std::string_view TEMP_FILE_EXT = ".exiv2_temp"; static constexpr auto TEMP_FILE_EXT = ".exiv2_temp";
/*! /*!
@brief The extension of the generated file which is created when getting input data @brief The extension of the generated file which is created when getting input data
to add or modify the metadata. to add or modify the metadata.
*/ */
static constexpr std::string_view GEN_FILE_EXT = ".exiv2"; static constexpr auto GEN_FILE_EXT = ".exiv2";
//! @name Creators //! @name Creators
//@{ //@{
@ -737,7 +735,7 @@ class EXIV2API XPathIo : public FileIo {
private: private:
// True if the file is a temporary file and it should be deleted in destructor. // True if the file is a temporary file and it should be deleted in destructor.
bool isTemp_; bool isTemp_{true};
std::string tempFilePath_; std::string tempFilePath_;
}; // class XPathIo }; // class XPathIo
#endif #endif
@ -874,7 +872,7 @@ class EXIV2API RemoteIo : public BasicIo {
@brief Get the current IO position. @brief Get the current IO position.
@return Offset from the start of the memory block @return Offset from the start of the memory block
*/ */
[[nodiscard]] long tell() const override; [[nodiscard]] size_t tell() const override;
/*! /*!
@brief Get the current memory buffer size in bytes. @brief Get the current memory buffer size in bytes.
@return Size of the in memory data in bytes;<BR> @return Size of the in memory data in bytes;<BR>

@ -14,7 +14,7 @@
// namespace extensions // namespace extensions
namespace Exiv2 { namespace Exiv2 {
EXIV2API bool enableBMFF(bool enable = true); EXIV2API bool enableBMFF(bool enable = true);
} } // namespace Exiv2
#ifdef EXV_ENABLE_BMFF #ifdef EXV_ENABLE_BMFF
namespace Exiv2 { namespace Exiv2 {
@ -97,15 +97,15 @@ class EXIV2API BmffImage : public Image {
//! @name Manipulators //! @name Manipulators
//@{ //@{
void readMetadata() override /* override */; void readMetadata() override;
void writeMetadata() override /* override */; void writeMetadata() override;
void setComment(std::string_view comment) override /* override */; void setComment(const std::string& comment) override;
void printStructure(std::ostream& out, Exiv2::PrintStructureOption option, int depth) override; void printStructure(std::ostream& out, Exiv2::PrintStructureOption option, int depth) override;
//@} //@}
//! @name Accessors //! @name Accessors
//@{ //@{
[[nodiscard]] std::string mimeType() const override /* override */; [[nodiscard]] std::string mimeType() const override;
[[nodiscard]] uint32_t pixelWidth() const override; [[nodiscard]] uint32_t pixelWidth() const override;
[[nodiscard]] uint32_t pixelHeight() const override; [[nodiscard]] uint32_t pixelHeight() const override;
//@} //@}
@ -122,13 +122,13 @@ class EXIV2API BmffImage : public Image {
@return address of next box @return address of next box
@warning This function should only be called by readMetadata() @warning This function should only be called by readMetadata()
*/ */
long boxHandler(std::ostream& out, Exiv2::PrintStructureOption option, long pbox_end, int depth); uint64_t boxHandler(std::ostream& out, Exiv2::PrintStructureOption option, uint64_t pbox_end, int depth);
[[nodiscard]] static std::string indent(int i) { [[nodiscard]] static std::string indent(int i) {
return std::string(2 * i, ' '); return std::string(2 * i, ' ');
} }
uint32_t fileType_{0}; uint32_t fileType_{0};
std::set<uint64_t> visits_; std::set<size_t> visits_;
uint64_t visits_max_{0}; uint64_t visits_max_{0};
uint16_t unknownID_{0xffff}; uint16_t unknownID_{0xffff};
uint16_t exifID_{0xffff}; uint16_t exifID_{0xffff};
@ -140,7 +140,7 @@ class EXIV2API BmffImage : public Image {
/*! /*!
@brief box utilities @brief box utilities
*/ */
static std::string toAscii(long n); static std::string toAscii(uint32_t n);
std::string boxName(uint32_t box); std::string boxName(uint32_t box);
static bool superBox(uint32_t box); static bool superBox(uint32_t box);
static bool fullBox(uint32_t box); static bool fullBox(uint32_t box);

@ -66,7 +66,7 @@ class EXIV2API BmpImage : public Image {
void setIptcData(const IptcData& iptcData) override; void setIptcData(const IptcData& iptcData) override;
/// @throws Error(ErrorCode::kerInvalidSettingForImage) /// @throws Error(ErrorCode::kerInvalidSettingForImage)
void setComment(std::string_view comment) override; void setComment(const std::string&) override;
//@} //@}
//! @name Accessors //! @name Accessors

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

@ -280,6 +280,7 @@ class EXIV2API IptcKey : public Key {
[[nodiscard]] std::string groupName() const override; [[nodiscard]] std::string groupName() const override;
[[nodiscard]] std::string tagName() const override; [[nodiscard]] std::string tagName() const override;
[[nodiscard]] std::string tagLabel() const override; [[nodiscard]] std::string tagLabel() const override;
[[nodiscard]] std::string tagDesc() const override;
[[nodiscard]] uint16_t tag() const override; [[nodiscard]] uint16_t tag() const override;
[[nodiscard]] UniquePtr clone() const; [[nodiscard]] UniquePtr clone() const;
//! Return the name of the record //! Return the name of the record

@ -65,7 +65,7 @@ class EXIV2API EpsImage : public Image {
@brief Not supported. @brief Not supported.
Calling this function will throw an instance of Error(ErrorCode::kerInvalidSettingForImage). Calling this function will throw an instance of Error(ErrorCode::kerInvalidSettingForImage).
*/ */
void setComment(std::string_view comment) override; void setComment(const std::string&) override;
//@} //@}
//! @name Accessors //! @name Accessors

@ -140,9 +140,10 @@ class EXIV2API Exifdatum : public Metadatum {
[[nodiscard]] std::string groupName() const override; [[nodiscard]] std::string groupName() const override;
[[nodiscard]] std::string tagName() const override; [[nodiscard]] std::string tagName() const override;
[[nodiscard]] std::string tagLabel() const override; [[nodiscard]] std::string tagLabel() const override;
[[nodiscard]] std::string tagDesc() const override;
[[nodiscard]] uint16_t tag() const override; [[nodiscard]] uint16_t tag() const override;
//! Return the IFD id as an integer. (Do not use, this is meant for library internal use.) //! Return the IFD id as an integer. (Do not use, this is meant for library internal use.)
[[nodiscard]] int ifdId() const; [[nodiscard]] IfdId ifdId() const;
//! Return the name of the IFD //! Return the name of the IFD
[[nodiscard]] const char* ifdName() const; [[nodiscard]] const char* ifdName() const;
//! Return the index (unique id of this key within the original IFD) //! Return the index (unique id of this key within the original IFD)

@ -31,7 +31,7 @@ EXIV2API std::string getEnv(int env_var);
@note Source: http://www.geekhideout.com/urlcode.shtml @note Source: http://www.geekhideout.com/urlcode.shtml
@todo This function can probably be hidden into the implementation details @todo This function can probably be hidden into the implementation details
*/ */
EXIV2API std::string urlencode(std::string_view str); EXIV2API std::string urlencode(const std::string& str);
/*! /*!
@brief Like urlencode(char* str) but accept the input url in the std::string and modify it. @brief Like urlencode(char* str) but accept the input url in the std::string and modify it.

@ -69,7 +69,7 @@ class EXIV2API GifImage : public Image {
@brief Not supported. Calling this function will throw an instance @brief Not supported. Calling this function will throw an instance
of Error(ErrorCode::kerInvalidSettingForImage). of Error(ErrorCode::kerInvalidSettingForImage).
*/ */
void setComment(std::string_view comment) override; void setComment(const std::string&) override;
//@} //@}
//! @name Accessors //! @name Accessors

@ -177,7 +177,7 @@ class EXIV2API Image {
virtual void clearXmpData(); virtual void clearXmpData();
/// @brief Set the image comment. The comment is written to the image when writeMetadata() is called. /// @brief Set the image comment. The comment is written to the image when writeMetadata() is called.
virtual void setComment(std::string_view comment); virtual void setComment(const std::string& comment);
/*! /*!
@brief Erase any buffered comment. Comment is not removed @brief Erase any buffered comment. Comment is not removed
@ -467,8 +467,8 @@ class EXIV2API Image {
DataBuf iccProfile_; //!< ICC buffer (binary data) DataBuf iccProfile_; //!< ICC buffer (binary data)
std::string comment_; //!< User comment std::string comment_; //!< User comment
std::string xmpPacket_; //!< XMP packet std::string xmpPacket_; //!< XMP packet
uint32_t pixelWidth_; //!< image pixel width uint32_t pixelWidth_{0}; //!< image pixel width
uint32_t pixelHeight_; //!< image pixel height uint32_t pixelHeight_{0}; //!< image pixel height
NativePreviewList nativePreviews_; //!< list of native previews NativePreviewList nativePreviews_; //!< list of native previews
//! Return tag name for given tag id. //! Return tag name for given tag id.
@ -482,10 +482,10 @@ class EXIV2API Image {
ImageType imageType_; //!< Image type ImageType imageType_; //!< Image type
uint16_t supportedMetadata_; //!< Bitmap with all supported metadata types uint16_t supportedMetadata_; //!< Bitmap with all supported metadata types
bool writeXmpFromPacket_; //!< Determines the source when writing XMP bool writeXmpFromPacket_; //!< Determines the source when writing XMP
ByteOrder byteOrder_; //!< Byte order ByteOrder byteOrder_{invalidByteOrder}; //!< Byte order
std::map<int, std::string> tags_; //!< Map of tags std::map<int, std::string> tags_; //!< Map of tags
bool init_; //!< Flag marking if map of tags needs to be initialized bool init_{true}; //!< Flag marking if map of tags needs to be initialized
}; // class Image }; // class Image

@ -113,6 +113,7 @@ class EXIV2API Iptcdatum : public Metadatum {
*/ */
[[nodiscard]] std::string tagName() const override; [[nodiscard]] std::string tagName() const override;
[[nodiscard]] std::string tagLabel() const override; [[nodiscard]] std::string tagLabel() const override;
[[nodiscard]] std::string tagDesc() const override;
//! Return the tag (aka dataset) number //! Return the tag (aka dataset) number
[[nodiscard]] uint16_t tag() const override; [[nodiscard]] uint16_t tag() const override;
[[nodiscard]] TypeId typeId() const override; [[nodiscard]] TypeId typeId() const override;

@ -56,7 +56,7 @@ class EXIV2API Jp2Image : public Image {
@brief Todo: Not supported yet(?). Calling this function will throw @brief Todo: Not supported yet(?). Calling this function will throw
an instance of Error(ErrorCode::kerInvalidSettingForImage). an instance of Error(ErrorCode::kerInvalidSettingForImage).
*/ */
void setComment(std::string_view comment) override; void setComment(const std::string&) override;
//@} //@}
//! @name Accessors //! @name Accessors

@ -52,6 +52,8 @@ class EXIV2API Key {
[[nodiscard]] virtual std::string tagName() const = 0; [[nodiscard]] virtual std::string tagName() const = 0;
//! Return a label for the tag //! Return a label for the tag
[[nodiscard]] virtual std::string tagLabel() const = 0; [[nodiscard]] virtual std::string tagLabel() const = 0;
//! Return a description for the tag
[[nodiscard]] virtual std::string tagDesc() const = 0;
//! Return the tag number //! Return the tag number
[[nodiscard]] virtual uint16_t tag() const = 0; [[nodiscard]] virtual uint16_t tag() const = 0;
/*! /*!
@ -181,6 +183,8 @@ class EXIV2API Metadatum {
[[nodiscard]] virtual std::string tagName() const = 0; [[nodiscard]] virtual std::string tagName() const = 0;
//! Return a label for the tag //! Return a label for the tag
[[nodiscard]] virtual std::string tagLabel() const = 0; [[nodiscard]] virtual std::string tagLabel() const = 0;
//! Return a description for the tag
[[nodiscard]] virtual std::string tagDesc() const = 0;
//! Return the tag //! Return the tag
[[nodiscard]] virtual uint16_t tag() const = 0; [[nodiscard]] virtual uint16_t tag() const = 0;
//! Return the type id of the value //! Return the type id of the value

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

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

@ -16,7 +16,7 @@ class IptcData;
/// @brief Helper class, has methods to deal with %Photoshop "Information Resource Blocks" (IRBs). /// @brief Helper class, has methods to deal with %Photoshop "Information Resource Blocks" (IRBs).
struct EXIV2API Photoshop { struct EXIV2API Photoshop {
// Todo: Public for now // Todo: Public for now
static constexpr std::array irbId_{"8BIM", "AgHg", "DCSR", "PHUT"}; //!< %Photoshop IRB markers static constexpr std::array<const char*, 4> irbId_{"8BIM", "AgHg", "DCSR", "PHUT"}; //!< %Photoshop IRB markers
static constexpr auto ps3Id_ = "Photoshop 3.0\0"; //!< %Photoshop marker static constexpr auto ps3Id_ = "Photoshop 3.0\0"; //!< %Photoshop marker
static constexpr uint16_t iptc_ = 0x0404; //!< %Photoshop IPTC marker static constexpr uint16_t iptc_ = 0x0404; //!< %Photoshop IPTC marker
static constexpr uint16_t preview_ = 0x040c; //!< %Photoshop preview marker static constexpr uint16_t preview_ = 0x040c; //!< %Photoshop preview marker

@ -8,6 +8,7 @@
// included header files // included header files
#include <mutex> #include <mutex>
#include "datasets.hpp" #include "datasets.hpp"
// ***************************************************************************** // *****************************************************************************
@ -262,6 +263,7 @@ class EXIV2API XmpKey : public Key {
[[nodiscard]] std::string groupName() const override; [[nodiscard]] std::string groupName() const override;
[[nodiscard]] std::string tagName() const override; [[nodiscard]] std::string tagName() const override;
[[nodiscard]] std::string tagLabel() const override; [[nodiscard]] std::string tagLabel() const override;
[[nodiscard]] std::string tagDesc() const override;
//! Properties don't have a tag number. Return 0. //! Properties don't have a tag number. Return 0.
[[nodiscard]] uint16_t tag() const override; [[nodiscard]] uint16_t tag() const override;

@ -53,7 +53,7 @@ class EXIV2API PsdImage : public Image {
/*! /*!
@brief Not supported. Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage). @brief Not supported. Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/ */
void setComment(std::string_view comment) override; void setComment(const std::string&) override;
//@} //@}
//! @name Accessors //! @name Accessors

@ -64,7 +64,7 @@ class EXIV2API RafImage : public Image {
@brief Not supported. RAF format does not contain a comment. @brief Not supported. RAF format does not contain a comment.
Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage). Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/ */
void setComment(std::string_view comment) override; void setComment(const std::string&) override;
//@} //@}
//! @name Accessors //! @name Accessors

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

@ -263,7 +263,7 @@ struct ContainerStorage {
using const_iterator = typename container::const_iterator; using const_iterator = typename container::const_iterator;
using value_type = std::remove_cv_t<typename container::value_type>; using value_type = typename std::remove_cv<typename container::value_type>::type;
/*! /*!
* @throw std::out_of_range when end is larger than the container's * @throw std::out_of_range when end is larger than the container's
@ -324,7 +324,7 @@ struct ContainerStorage {
*/ */
template <typename storage_type> template <typename storage_type>
struct PtrSliceStorage { struct PtrSliceStorage {
using value_type = std::remove_cv_t<std::remove_pointer_t<storage_type>>; using value_type = typename std::remove_cv<typename std::remove_pointer<storage_type>::type>::type;
using iterator = value_type*; using iterator = value_type*;
using const_iterator = const value_type*; using const_iterator = const value_type*;
@ -423,7 +423,7 @@ struct Slice : public Internal::MutableSliceBase<Internal::ContainerStorage, con
using const_iterator = typename container::const_iterator; using const_iterator = typename container::const_iterator;
using value_type = std::remove_cv_t<typename container::value_type>; using value_type = typename std::remove_cv<typename container::value_type>::type;
/*! /*!
* @brief Construct a slice of the container `cont` starting at `begin` * @brief Construct a slice of the container `cont` starting at `begin`
@ -476,7 +476,7 @@ struct Slice<const container> : public Internal::ConstSliceBase<Internal::Contai
using const_iterator = typename container::const_iterator; using const_iterator = typename container::const_iterator;
using value_type = std::remove_cv_t<typename container::value_type>; using value_type = typename std::remove_cv<typename container::value_type>::type;
Slice(const container& cont, size_t begin, size_t end) : Slice(const container& cont, size_t begin, size_t end) :
Internal::ConstSliceBase<Internal::ContainerStorage, const container>(cont, begin, end) { Internal::ConstSliceBase<Internal::ContainerStorage, const container>(cont, begin, end) {

@ -30,12 +30,161 @@ using TagListFct = const TagInfo* (*)();
// ***************************************************************************** // *****************************************************************************
// class definitions // class definitions
//! Type to specify the IFD to which a metadata belongs
enum class IfdId : uint32_t {
ifdIdNotSet,
ifd0Id,
ifd1Id,
ifd2Id,
ifd3Id,
exifId,
gpsId,
iopId,
mpfId,
subImage1Id,
subImage2Id,
subImage3Id,
subImage4Id,
subImage5Id,
subImage6Id,
subImage7Id,
subImage8Id,
subImage9Id,
subThumb1Id,
panaRawId,
mnId,
canonId,
canonAfCId,
canonAfMiAdjId,
canonAmId,
canonAsId,
canonCbId,
canonCiId,
canonCsId,
canonFilId,
canonFlId,
canonHdrId,
canonLeId,
canonMeId,
canonMoID,
canonMvId,
canonRawBId,
canonSiId,
canonCfId,
canonContrastId,
canonFcd1Id,
canonFcd2Id,
canonFcd3Id,
canonLiOpId,
canonMyColorID,
canonPiId,
canonPaId,
canonTiId,
canonFiId,
canonPrId,
canonPreID,
canonVigCorId,
canonVigCor2Id,
canonWbId,
casioId,
casio2Id,
fujiId,
minoltaId,
minoltaCs5DId,
minoltaCs7DId,
minoltaCsOldId,
minoltaCsNewId,
nikon1Id,
nikon2Id,
nikon3Id,
nikonPvId,
nikonVrId,
nikonPcId,
nikonWtId,
nikonIiId,
nikonAfId,
nikonAf21Id,
nikonAf22Id,
nikonAFTId,
nikonFiId,
nikonMeId,
nikonFl1Id,
nikonFl2Id,
nikonFl3Id,
nikonFl7Id,
nikonSi1Id,
nikonSi2Id,
nikonSi3Id,
nikonSi4Id,
nikonSi5Id,
nikonSi6Id,
nikonLd1Id,
nikonLd2Id,
nikonLd3Id,
nikonLd4Id,
nikonCb1Id,
nikonCb2Id,
nikonCb2aId,
nikonCb2bId,
nikonCb3Id,
nikonCb4Id,
olympusId,
olympus2Id,
olympusCsId,
olympusEqId,
olympusRdId,
olympusRd2Id,
olympusIpId,
olympusFiId,
olympusFe1Id,
olympusFe2Id,
olympusFe3Id,
olympusFe4Id,
olympusFe5Id,
olympusFe6Id,
olympusFe7Id,
olympusFe8Id,
olympusFe9Id,
olympusRiId,
panasonicId,
pentaxId,
pentaxDngId,
samsung2Id,
samsungPvId,
samsungPwId,
sigmaId,
sony1Id,
sony2Id,
sonyMltId,
sony1CsId,
sony1Cs2Id,
sony2CsId,
sony2Cs2Id,
sony2FpId,
sonyMisc1Id,
sonyMisc2bId,
sonyMisc3cId,
sonySInfo1Id,
sony2010eId,
sony1MltCs7DId,
sony1MltCsOldId,
sony1MltCsNewId,
sony1MltCsA100Id,
tagInfoMvId,
lastId,
ignoreId = lastId
};
inline std::ostream& operator<<(std::ostream& os, IfdId id) {
return os << static_cast<int>(id);
}
//! The details of an Exif group. Groups include IFDs and binary arrays. //! The details of an Exif group. Groups include IFDs and binary arrays.
struct EXIV2API GroupInfo { struct EXIV2API GroupInfo {
struct GroupName; struct GroupName;
bool operator==(int ifdId) const; //!< Comparison operator for IFD id bool operator==(IfdId ifdId) const; //!< Comparison operator for IFD id
bool operator==(const GroupName& groupName) const; //!< Comparison operator for group name bool operator==(const GroupName& groupName) const; //!< Comparison operator for group name
int ifdId_; //!< IFD id IfdId ifdId_; //!< IFD id
const char* ifdName_; //!< IFD name const char* ifdName_; //!< IFD name
const char* groupName_; //!< Group name, unique for each group. const char* groupName_; //!< Group name, unique for each group.
TagListFct tagList_; //!< Tag list TagListFct tagList_; //!< Tag list
@ -47,14 +196,43 @@ struct EXIV2API GroupInfo::GroupName {
std::string g_; //!< Group name std::string g_; //!< Group name
}; };
/*!
@brief Section identifiers to logically group tags. A section consists
of nothing more than a name, based on the Exif standard.
*/
enum class SectionId {
sectionIdNotSet,
imgStruct, // 4.6.4 A
recOffset, // 4.6.4 B
imgCharacter, // 4.6.4 C
otherTags, // 4.6.4 D
exifFormat, // 4.6.3
exifVersion, // 4.6.5 A
imgConfig, // 4.6.5 C
userInfo, // 4.6.5 D
relatedFile, // 4.6.5 E
dateTime, // 4.6.5 F
captureCond, // 4.6.5 G
gpsTags, // 4.6.6
iopTags, // 4.6.7
mpfTags,
makerTags, // MakerNote
dngTags, // DNG Spec
panaRaw,
tiffEp, // TIFF-EP Spec
tiffPm6,
adobeOpi,
lastSectionId
};
//! Tag information //! Tag information
struct EXIV2API TagInfo { struct EXIV2API TagInfo {
uint16_t tag_; //!< Tag uint16_t tag_; //!< Tag
const char* name_; //!< One word tag label const char* name_; //!< One word tag label
const char* title_; //!< Tag title const char* title_; //!< Tag title
const char* desc_; //!< Short tag description const char* desc_; //!< Short tag description
int ifdId_; //!< Link to the (preferred) IFD IfdId ifdId_; //!< Link to the (preferred) IFD
int sectionId_; //!< Section id SectionId sectionId_; //!< Section id
TypeId typeId_; //!< Type id TypeId typeId_; //!< Type id
int16_t count_; //!< The number of values (not bytes!), 0=any, -1=count not known. int16_t count_; //!< The number of values (not bytes!), 0=any, -1=count not known.
PrintFct printFct_; //!< Pointer to tag print function PrintFct printFct_; //!< Pointer to tag print function
@ -156,13 +334,12 @@ class EXIV2API ExifKey : public Key {
[[nodiscard]] std::string key() const override; [[nodiscard]] std::string key() const override;
[[nodiscard]] const char* familyName() const override; [[nodiscard]] const char* familyName() const override;
[[nodiscard]] std::string groupName() const override; [[nodiscard]] std::string groupName() const override;
//! Return the IFD id as an integer. (Do not use, this is meant for library internal use.) //! Return the IFD id. (Do not use, this is meant for library internal use.)
[[nodiscard]] int ifdId() const; [[nodiscard]] IfdId ifdId() const;
[[nodiscard]] std::string tagName() const override; [[nodiscard]] std::string tagName() const override;
[[nodiscard]] uint16_t tag() const override; [[nodiscard]] uint16_t tag() const override;
[[nodiscard]] std::string tagLabel() const override; [[nodiscard]] std::string tagLabel() const override;
//! Return the tag description. [[nodiscard]] std::string tagDesc() const override;
[[nodiscard]] std::string tagDesc() const; // Todo: should be in the base class
//! Return the default type id for this tag. //! Return the default type id for this tag.
[[nodiscard]] TypeId defaultTypeId() const; // Todo: should be in the base class [[nodiscard]] TypeId defaultTypeId() const; // Todo: should be in the base class

@ -68,7 +68,7 @@ class EXIV2API TgaImage : public Image {
@brief Not supported. Calling this function will throw an instance @brief Not supported. Calling this function will throw an instance
of Error(ErrorCode::kerInvalidSettingForImage). of Error(ErrorCode::kerInvalidSettingForImage).
*/ */
void setComment(std::string_view comment) override; void setComment(const std::string&) override;
//@} //@}
//! @name Accessors //! @name Accessors

@ -58,7 +58,7 @@ class EXIV2API TiffImage : public Image {
@brief Not supported. TIFF format does not contain a comment. @brief Not supported. TIFF format does not contain a comment.
Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage). Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/ */
void setComment(std::string_view comment) override; void setComment(const std::string&) override;
//@} //@}
//! @name Accessors //! @name Accessors
@ -87,8 +87,8 @@ class EXIV2API TiffImage : public Image {
// DATA // DATA
mutable std::string primaryGroup_; //!< The primary group mutable std::string primaryGroup_; //!< The primary group
mutable std::string mimeType_; //!< The MIME type mutable std::string mimeType_; //!< The MIME type
mutable uint32_t pixelWidthPrimary_; //!< Width of the primary image in pixels mutable uint32_t pixelWidthPrimary_{0}; //!< Width of the primary image in pixels
mutable uint32_t pixelHeightPrimary_; //!< Height of the primary image in pixels mutable uint32_t pixelHeightPrimary_{0}; //!< Height of the primary image in pixels
}; // class TiffImage }; // class TiffImage

@ -14,6 +14,7 @@
#include <cstring> #include <cstring>
#include <iomanip> #include <iomanip>
#include <map> #include <map>
#include <memory>
// ***************************************************************************** // *****************************************************************************
// namespace extensions // namespace extensions
@ -228,7 +229,7 @@ class EXIV2API Value {
*/ */
Value& operator=(const Value&) = default; Value& operator=(const Value&) = default;
// DATA // DATA
mutable bool ok_; //!< Indicates the status of the previous to<Type> conversion mutable bool ok_{true}; //!< Indicates the status of the previous to<Type> conversion
private: private:
//! Internal virtual copy constructor. //! Internal virtual copy constructor.
@ -647,8 +648,8 @@ class EXIV2API XmpValue : public Value {
private: private:
// DATA // DATA
XmpArrayType xmpArrayType_; //!< Type of XMP array XmpArrayType xmpArrayType_{xaNone}; //!< Type of XMP array
XmpStruct xmpStruct_; //!< XMP structure indicator XmpStruct xmpStruct_{xsNone}; //!< XMP structure indicator
}; // class XmpValue }; // class XmpValue
@ -931,16 +932,16 @@ class EXIV2API DateValue : public Value {
//! Default constructor. //! Default constructor.
DateValue(); DateValue();
//! Constructor //! Constructor
DateValue(int year, int month, int day); DateValue(int32_t year, int32_t month, int32_t day);
//! Virtual destructor. //! Virtual destructor.
~DateValue() override = default; ~DateValue() override = default;
//@} //@}
//! Simple Date helper structure //! Simple Date helper structure
struct EXIV2API Date { struct EXIV2API Date {
int year{0}; //!< Year int32_t year{0}; //!< Year
int month{0}; //!< Month int32_t month{0}; //!< Month
int day{0}; //!< Day int32_t day{0}; //!< Day
}; };
//! @name Manipulators //! @name Manipulators
@ -1024,7 +1025,7 @@ class EXIV2API TimeValue : public Value {
//! Default constructor. //! Default constructor.
TimeValue(); TimeValue();
//! Constructor //! Constructor
TimeValue(int hour, int minute, int second = 0, int tzHour = 0, int tzMinute = 0); TimeValue(int32_t hour, int32_t minute, int32_t second = 0, int32_t tzHour = 0, int32_t tzMinute = 0);
//! Virtual destructor. //! Virtual destructor.
~TimeValue() override = default; ~TimeValue() override = default;
@ -1034,11 +1035,11 @@ class EXIV2API TimeValue : public Value {
struct Time { struct Time {
Time() = default; Time() = default;
int hour{0}; //!< Hour int32_t hour{0}; //!< Hour
int minute{0}; //!< Minute int32_t minute{0}; //!< Minute
int second{0}; //!< Second int32_t second{0}; //!< Second
int tzHour{0}; //!< Hours ahead or behind UTC int32_t tzHour{0}; //!< Hours ahead or behind UTC
int tzMinute{0}; //!< Minutes ahead or behind UTC int32_t tzMinute{0}; //!< Minutes ahead or behind UTC
}; };
//! @name Manipulators //! @name Manipulators
@ -1260,7 +1261,8 @@ class ValueType : public Value {
//! Utility for toInt64, toUint32, etc. //! Utility for toInt64, toUint32, etc.
template <typename I> template <typename I>
inline I rational_to_integer_helper(size_t n) const { inline I rational_to_integer_helper(size_t n) const {
auto&& [a, b] = value_.at(n); auto a = value_.at(n).first;
auto b = value_.at(n).second;
// Protect against divide-by-zero. // Protect against divide-by-zero.
if (b <= 0) { if (b <= 0) {
@ -1268,16 +1270,16 @@ class ValueType : public Value {
} }
// Check for integer overflow. // Check for integer overflow.
if (std::is_signed_v<I> == std::is_signed_v<decltype(a)>) { if (std::is_signed<I>::value == std::is_signed<decltype(a)>::value) {
// conversion does not change sign // conversion does not change sign
const auto imin = std::numeric_limits<I>::min(); const auto imin = std::numeric_limits<I>::min();
const auto imax = std::numeric_limits<I>::max(); const auto imax = std::numeric_limits<I>::max();
if (imax < b || a < imin || imax < a) { if (imax < b || a < imin || imax < a) {
return 0; return 0;
} }
} else if (std::is_signed_v<I>) { } else if (std::is_signed<I>::value) {
// conversion is from unsigned to signed // conversion is from unsigned to signed
const auto imax = std::make_unsigned_t<I>(std::numeric_limits<I>::max()); const auto imax = typename std::make_unsigned<I>::type(std::numeric_limits<I>::max());
if (imax < b || imax < a) { if (imax < b || imax < a) {
return 0; return 0;
} }
@ -1288,8 +1290,8 @@ class ValueType : public Value {
return 0; return 0;
} }
// Inputs are not negative so convert them to unsigned. // Inputs are not negative so convert them to unsigned.
const auto a_u = std::make_unsigned_t<decltype(a)>(a); const auto a_u = typename std::make_unsigned<decltype(a)>::type(a);
const auto b_u = std::make_unsigned_t<decltype(b)>(b); const auto b_u = typename std::make_unsigned<decltype(b)>::type(b);
if (imax < b_u || imax < a_u) { if (imax < b_u || imax < a_u) {
return 0; return 0;
} }

@ -72,9 +72,9 @@
// namespace extensions // namespace extensions
namespace Exiv2 { namespace Exiv2 {
/*! /*!
@brief Return the version of %Exiv2 available at runtime as an integer. @brief Return the version of %Exiv2 available at runtime as a uint32_t.
*/ */
EXIV2API int versionNumber(); EXIV2API uint32_t versionNumber();
/*! /*!
@brief Return the version string Example: "0.25.0" (major.minor.patch) @brief Return the version string Example: "0.25.0" (major.minor.patch)
*/ */
@ -96,7 +96,7 @@ EXIV2API const char* version();
Versions are denoted using a triplet of integers: \em major.minor.patch . Versions are denoted using a triplet of integers: \em major.minor.patch .
The fourth version number is designated a "tweak" an used by Release Candidates The fourth version number is designated a "tweak" an used by Release Candidates
*/ */
EXIV2API bool testVersion(int major, int minor, int patch); EXIV2API bool testVersion(uint32_t major, uint32_t minor, uint32_t patch);
/*! /*!
@brief dumpLibraryInfo implements the exiv2 option --version --verbose @brief dumpLibraryInfo implements the exiv2 option --version --verbose
used by exiv2 test suite to inspect libraries loaded at run-time used by exiv2 test suite to inspect libraries loaded at run-time

@ -46,7 +46,7 @@ class EXIV2API WebPImage : public Image {
/*! /*!
@brief Not supported. Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage). @brief Not supported. Calling this function will throw an Error(ErrorCode::kerInvalidSettingForImage).
*/ */
void setComment(std::string_view comment) override; void setComment(const std::string&) override;
void setIptcData(const IptcData& /*iptcData*/) override; void setIptcData(const IptcData& /*iptcData*/) override;
//! @name Accessors //! @name Accessors
@ -54,6 +54,7 @@ class EXIV2API WebPImage : public Image {
[[nodiscard]] std::string mimeType() const override; [[nodiscard]] std::string mimeType() const override;
//@} //@}
~WebPImage() override = default;
//! Copy constructor //! Copy constructor
WebPImage(const WebPImage&) = delete; WebPImage(const WebPImage&) = delete;
//! Assignment operator //! Assignment operator
@ -62,13 +63,15 @@ class EXIV2API WebPImage : public Image {
private: private:
void doWriteMetadata(BasicIo& outIo); void doWriteMetadata(BasicIo& outIo);
//! @name NOT Implemented
//@{ //! Finds the offset of header in data. Returns std::string::npos if the header isn't found.
static long getHeaderOffset(const byte* data, size_t data_size, const byte* header, size_t header_size); static size_t getHeaderOffset(const byte* data, size_t data_size, const byte* header, size_t header_size);
static bool equalsWebPTag(Exiv2::DataBuf& buf, const char* str);
void debugPrintHex(byte* data, long size); static bool equalsWebPTag(const Exiv2::DataBuf& buf, const char* str);
void decodeChunks(long filesize); void debugPrintHex(byte* data, size_t size);
void inject_VP8X(BasicIo& iIo, bool has_xmp, bool has_exif, bool has_alpha, bool has_icc, int width, int height); void decodeChunks(uint32_t filesize);
void inject_VP8X(BasicIo& iIo, bool has_xmp, bool has_exif, bool has_alpha, bool has_icc, uint32_t width,
uint32_t height);
/* Misc. */ /* Misc. */
static constexpr byte WEBP_PAD_ODD = 0; static constexpr byte WEBP_PAD_ODD = 0;
static constexpr int WEBP_TAG_SIZE = 0x4; static constexpr int WEBP_TAG_SIZE = 0x4;

@ -58,16 +58,11 @@ class EXIV2API Xmpdatum : public Metadatum {
Calls setValue(const std::string&). Calls setValue(const std::string&).
*/ */
Xmpdatum& operator=(const std::string& value); Xmpdatum& operator=(const std::string& value);
/*!
@brief Assign const char* \em value to the %Xmpdatum.
Calls operator=(const std::string&).
*/
Xmpdatum& operator=(const char* value);
/*! /*!
@brief Assign a boolean \em value to the %Xmpdatum. @brief Assign a boolean \em value to the %Xmpdatum.
Translates the value to a string "true" or "false". Translates the value to a string "true" or "false".
*/ */
Xmpdatum& operator=(const bool& value); Xmpdatum& operator=(bool value);
/*! /*!
@brief Assign a \em value of any type with an output operator @brief Assign a \em value of any type with an output operator
to the %Xmpdatum. Calls operator=(const std::string&). to the %Xmpdatum. Calls operator=(const std::string&).
@ -108,6 +103,7 @@ class EXIV2API Xmpdatum : public Metadatum {
//! Return the property name. //! Return the property name.
[[nodiscard]] std::string tagName() const override; [[nodiscard]] std::string tagName() const override;
[[nodiscard]] std::string tagLabel() const override; [[nodiscard]] std::string tagLabel() const override;
[[nodiscard]] std::string tagDesc() const override;
//! Properties don't have a tag number. Return 0. //! Properties don't have a tag number. Return 0.
[[nodiscard]] uint16_t tag() const override; [[nodiscard]] uint16_t tag() const override;
[[nodiscard]] TypeId typeId() const override; [[nodiscard]] TypeId typeId() const override;
@ -227,23 +223,23 @@ class EXIV2API XmpData {
//! are we to use the packet? //! are we to use the packet?
[[nodiscard]] bool usePacket() const { [[nodiscard]] bool usePacket() const {
return usePacket_; return usePacket_;
}; }
//! set usePacket_ //! set usePacket_
bool usePacket(bool b) { bool usePacket(bool b) {
bool r = usePacket_; bool r = usePacket_;
usePacket_ = b; usePacket_ = b;
return r; return r;
}; }
//! setPacket //! setPacket
void setPacket(std::string xmpPacket) { void setPacket(std::string xmpPacket) {
xmpPacket_ = std::move(xmpPacket); xmpPacket_ = std::move(xmpPacket);
usePacket(false); usePacket(false);
}; }
// ! getPacket // ! getPacket
[[nodiscard]] const std::string& xmpPacket() const { [[nodiscard]] const std::string& xmpPacket() const {
return xmpPacket_; return xmpPacket_;
}; }
//@} //@}
@ -404,11 +400,7 @@ class EXIV2API XmpParser {
// ***************************************************************************** // *****************************************************************************
// free functions, template and inline definitions // free functions, template and inline definitions
inline Xmpdatum& Xmpdatum::operator=(const char* value) { inline Xmpdatum& Xmpdatum::operator=(bool value) {
return Xmpdatum::operator=(std::string(value));
}
inline Xmpdatum& Xmpdatum::operator=(const bool& value) {
return operator=(value ? "True" : "False"); return operator=(value ? "True" : "False");
} }

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

@ -670,8 +670,8 @@ msgstr ""
"Sadrzaj koda drzave je fokusiran na -- ili je drzava prikazana u vizuelom " "Sadrzaj koda drzave je fokusiran na -- ili je drzava prikazana u vizuelom "
"mediju ili je navedena u tekstualnom ili zvucnom mediju. Ovaj element je na " "mediju ili je navedena u tekstualnom ili zvucnom mediju. Ovaj element je na "
"vrhu/prvom nivou odozgo prema dole geografskoj hijerarhiji. Sifra treba biti " "vrhu/prvom nivou odozgo prema dole geografskoj hijerarhiji. Sifra treba biti "
"uzeta iz ISO 3166 dva ili tri slova. Puni naziv drzave treba ici u \"Drzava" "uzeta iz ISO 3166 dva ili tri slova. Puni naziv drzave treba ici u "
"\" element." "\"Drzava\" element."
#: src/properties.cpp:965 #: src/properties.cpp:965
#, fuzzy #, fuzzy
@ -2842,8 +2842,8 @@ msgstr "Alžir"
#: src/error.cpp:101 #: src/error.cpp:101
msgid "" msgid ""
"Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net `" "Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net "
"%1', `%2', `%3'" "`%1', `%2', `%3'"
msgstr "" msgstr ""
"Aliases nisu podržani. Molimo pošaljite ovaj XMP paket ahuggel@gmx.net '% " "Aliases nisu podržani. Molimo pošaljite ovaj XMP paket ahuggel@gmx.net '% "
"1', '% 2', '% 3'" "1', '% 2', '% 3'"
@ -13170,8 +13170,8 @@ msgstr ""
#: src/tags.cpp:2107 #: src/tags.cpp:2107
msgid "" msgid ""
"Indicates the unit used to express the distance to the destination point. \"K" "Indicates the unit used to express the distance to the destination point. "
"\", \"M\" and \"N\" represent kilometers, miles and knots." "\"K\", \"M\" and \"N\" represent kilometers, miles and knots."
msgstr "" msgstr ""
"Pokazuje jedinicu upotrijebljenu za izražavanje udaljenosti do krajnje " "Pokazuje jedinicu upotrijebljenu za izražavanje udaljenosti do krajnje "
"destinacije. \"K\",\"M\" i \"N\" predstavljaju kilometre, milje i čvorova." "destinacije. \"K\",\"M\" i \"N\" predstavljaju kilometre, milje i čvorova."
@ -13229,8 +13229,8 @@ msgid ""
"latitude. The ASCII value \"N\" indicates north latitude, and \"S\" is south " "latitude. The ASCII value \"N\" indicates north latitude, and \"S\" is south "
"latitude." "latitude."
msgstr "" msgstr ""
"Pokazuje da li je smjer destinacije sjeverno ili južno. ASCII vrijednost \"N" "Pokazuje da li je smjer destinacije sjeverno ili južno. ASCII vrijednost "
"\" označava sjevernu, a \"S\" južnu usmjerenost." "\"N\" označava sjevernu, a \"S\" južnu usmjerenost."
#: src/tags.cpp:2000 #: src/tags.cpp:2000
msgid "" msgid ""
@ -24184,8 +24184,8 @@ msgid ""
"\"Oktoberfest, Munich Germany\" For more accurate positioning, use the EXIF " "\"Oktoberfest, Munich Germany\" For more accurate positioning, use the EXIF "
"GPS values." "GPS values."
msgstr "" msgstr ""
"Naziv mjesta gdje je video snimljen. Naprimjer: \"Oktoberfest, Munich Germany" "Naziv mjesta gdje je video snimljen. Naprimjer: \"Oktoberfest, Munich "
"\". Za preciznije pozicioniranje, iskoristi EXIF GPS vrijednosti." "Germany\". Za preciznije pozicioniranje, iskoristi EXIF GPS vrijednosti."
#: src/properties.cpp:2293 #: src/properties.cpp:2293
msgid "" msgid ""

File diff suppressed because it is too large Load Diff

@ -2686,8 +2686,8 @@ msgstr "Justiere"
#: src/exiv2.cpp:1026 #: src/exiv2.cpp:1026
msgid "Adjust action requires at least one -a, -Y, -O or -D option\n" msgid "Adjust action requires at least one -a, -Y, -O or -D option\n"
msgstr "" msgstr ""
"Die Aktion \"justieren\" benötigt mindestens eine der Optionen \"-a\", \"-Y" "Die Aktion \"justieren\" benötigt mindestens eine der Optionen \"-a\", \"-"
"\", \"-O\" oder \"-D\"\n" "Y\", \"-O\" oder \"-D\"\n"
#: src/actions.cpp:1745 #: src/actions.cpp:1745
msgid "Adjusting" msgid "Adjusting"
@ -2894,8 +2894,8 @@ msgstr "Algier"
#: src/error.cpp:101 #: src/error.cpp:101
msgid "" msgid ""
"Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net `" "Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net "
"%1', `%2', `%3'" "`%1', `%2', `%3'"
msgstr "" msgstr ""
"Aliase werden nicht unterstützt. Bitte senden Sie dieses XMP-Packet an " "Aliase werden nicht unterstützt. Bitte senden Sie dieses XMP-Packet an "
"ahuggel@gmx.net `%1', `%2', `%3'" "ahuggel@gmx.net `%1', `%2', `%3'"
@ -13532,8 +13532,8 @@ msgstr ""
#: src/tags.cpp:2107 #: src/tags.cpp:2107
msgid "" msgid ""
"Indicates the unit used to express the distance to the destination point. \"K" "Indicates the unit used to express the distance to the destination point. "
"\", \"M\" and \"N\" represent kilometers, miles and knots." "\"K\", \"M\" and \"N\" represent kilometers, miles and knots."
msgstr "" msgstr ""
#: src/tags.cpp:1981 #: src/tags.cpp:1981

@ -2911,8 +2911,8 @@ msgstr "Argel"
#: src/error.cpp:101 #: src/error.cpp:101
msgid "" msgid ""
"Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net `" "Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net "
"%1', `%2', `%3'" "`%1', `%2', `%3'"
msgstr "" msgstr ""
"Los alias no están permitidos. Por favor envíe este paquete XMP a " "Los alias no están permitidos. Por favor envíe este paquete XMP a "
"ahuggel@gmx.net «%1», «%2», «%3»" "ahuggel@gmx.net «%1», «%2», «%3»"
@ -8800,8 +8800,8 @@ msgstr ""
#: src/error.cpp:78 #: src/error.cpp:78
msgid "Entry::setValue: Value too large (tag=%1, size=%2, requested=%3)" msgid "Entry::setValue: Value too large (tag=%1, size=%2, requested=%3)"
msgstr "" msgstr ""
"Entry::setValue: Valor demasiado grande (etiqueta=%1, tamaño=%2, solicitado=" "Entry::setValue: Valor demasiado grande (etiqueta=%1, tamaño=%2, "
"%3)" "solicitado=%3)"
#: src/datasets.cpp:108 #: src/datasets.cpp:108
msgid "Envelope Number" msgid "Envelope Number"
@ -13130,8 +13130,8 @@ msgstr ""
#: src/tags.cpp:2107 #: src/tags.cpp:2107
msgid "" msgid ""
"Indicates the unit used to express the distance to the destination point. \"K" "Indicates the unit used to express the distance to the destination point. "
"\", \"M\" and \"N\" represent kilometers, miles and knots." "\"K\", \"M\" and \"N\" represent kilometers, miles and knots."
msgstr "" msgstr ""
"Indica la unidad de medida empleada para expresar la distancia al punto de " "Indica la unidad de medida empleada para expresar la distancia al punto de "
"destino. «K», «M» y «N» representan kilómetros, millas y nudos, " "destino. «K», «M» y «N» representan kilómetros, millas y nudos, "
@ -23886,8 +23886,8 @@ msgid ""
"'/' character (ex.: \"City/Paris/Monument/Eiffel Tower\"." "'/' character (ex.: \"City/Paris/Monument/Eiffel Tower\"."
msgstr "" msgstr ""
"La lista de ruta de etiquetas completa como cadena. La jerarquía de la ruta " "La lista de ruta de etiquetas completa como cadena. La jerarquía de la ruta "
"se separa por el carácter «/» (ej.: «Ciudad/Madrid/Monumento/Museo del Prado" "se separa por el carácter «/» (ej.: «Ciudad/Madrid/Monumento/Museo del "
"\"." "Prado\"."
#: src/properties.cpp:212 #: src/properties.cpp:212
msgid "" msgid ""

@ -2664,8 +2664,8 @@ msgstr ""
#: src/error.cpp:101 #: src/error.cpp:101
msgid "" msgid ""
"Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net `" "Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net "
"%1', `%2', `%3'" "`%1', `%2', `%3'"
msgstr "" msgstr ""
#: src/nikonmn.cpp:1680 #: src/nikonmn.cpp:1680
@ -12977,8 +12977,8 @@ msgstr ""
#: src/tags.cpp:2107 #: src/tags.cpp:2107
msgid "" msgid ""
"Indicates the unit used to express the distance to the destination point. \"K" "Indicates the unit used to express the distance to the destination point. "
"\", \"M\" and \"N\" represent kilometers, miles and knots." "\"K\", \"M\" and \"N\" represent kilometers, miles and knots."
msgstr "" msgstr ""
#: src/tags.cpp:1981 #: src/tags.cpp:1981

@ -2856,8 +2856,8 @@ msgstr "Alger"
#: src/error.cpp:101 #: src/error.cpp:101
msgid "" msgid ""
"Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net `" "Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net "
"%1', `%2', `%3'" "`%1', `%2', `%3'"
msgstr "" msgstr ""
#: src/nikonmn.cpp:1680 #: src/nikonmn.cpp:1680
@ -13469,8 +13469,8 @@ msgstr ""
#: src/tags.cpp:2107 #: src/tags.cpp:2107
msgid "" msgid ""
"Indicates the unit used to express the distance to the destination point. \"K" "Indicates the unit used to express the distance to the destination point. "
"\", \"M\" and \"N\" represent kilometers, miles and knots." "\"K\", \"M\" and \"N\" represent kilometers, miles and knots."
msgstr "" msgstr ""
#: src/tags.cpp:1981 #: src/tags.cpp:1981

@ -2778,8 +2778,8 @@ msgstr "Alxeria"
#: src/error.cpp:101 #: src/error.cpp:101
msgid "" msgid ""
"Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net `" "Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net "
"%1', `%2', `%3'" "`%1', `%2', `%3'"
msgstr "" msgstr ""
"Non se admiten os alias. E envíe este paquete XMP a ahuggel@gmx.net «%1», " "Non se admiten os alias. E envíe este paquete XMP a ahuggel@gmx.net «%1», "
"«%2», «%3»" "«%2», «%3»"
@ -8744,14 +8744,14 @@ msgstr "Valores do mellorador"
#: src/error.cpp:79 #: src/error.cpp:79
msgid "Entry::setDataArea: Value too large (tag=%1, size=%2, requested=%3)" msgid "Entry::setDataArea: Value too large (tag=%1, size=%2, requested=%3)"
msgstr "" msgstr ""
"Entry::setDataArea: Valor grande de máis (etiqueta=%1, tamaño=%2, solicitado=" "Entry::setDataArea: Valor grande de máis (etiqueta=%1, tamaño=%2, "
"%3)" "solicitado=%3)"
#: src/error.cpp:78 #: src/error.cpp:78
msgid "Entry::setValue: Value too large (tag=%1, size=%2, requested=%3)" msgid "Entry::setValue: Value too large (tag=%1, size=%2, requested=%3)"
msgstr "" msgstr ""
"Entry::setValue: Valor grande de máis (etiqueta=%1, tamaño=%2, solicitado=" "Entry::setValue: Valor grande de máis (etiqueta=%1, tamaño=%2, "
"%3)" "solicitado=%3)"
#: src/datasets.cpp:108 #: src/datasets.cpp:108
msgid "Envelope Number" msgid "Envelope Number"
@ -13119,8 +13119,8 @@ msgstr ""
#: src/tags.cpp:2107 #: src/tags.cpp:2107
msgid "" msgid ""
"Indicates the unit used to express the distance to the destination point. \"K" "Indicates the unit used to express the distance to the destination point. "
"\", \"M\" and \"N\" represent kilometers, miles and knots." "\"K\", \"M\" and \"N\" represent kilometers, miles and knots."
msgstr "" msgstr ""
#: src/tags.cpp:1981 #: src/tags.cpp:1981

@ -2900,11 +2900,11 @@ msgstr "Algiers"
#: src/error.cpp:101 #: src/error.cpp:101
msgid "" msgid ""
"Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net `" "Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net "
"%1', `%2', `%3'" "`%1', `%2', `%3'"
msgstr "" msgstr ""
"Alias tidak disokong. Sila hantar paket XMP ini ke ahuggel@gmx.net `%1', `" "Alias tidak disokong. Sila hantar paket XMP ini ke ahuggel@gmx.net `%1', "
"%2', `%3'" "`%2', `%3'"
#: src/nikonmn.cpp:1680 #: src/nikonmn.cpp:1680
msgid "All 11 Points" msgid "All 11 Points"
@ -13169,11 +13169,11 @@ msgstr ""
#: src/tags.cpp:2107 #: src/tags.cpp:2107
msgid "" msgid ""
"Indicates the unit used to express the distance to the destination point. \"K" "Indicates the unit used to express the distance to the destination point. "
"\", \"M\" and \"N\" represent kilometers, miles and knots." "\"K\", \"M\" and \"N\" represent kilometers, miles and knots."
msgstr "" msgstr ""
"Menunjukkan unit yang digunakan untuk mengungkap jarak titik destinasi. \"K" "Menunjukkan unit yang digunakan untuk mengungkap jarak titik destinasi. "
"\", \"M\" dan \"N\" mewakili kilometer, batu dan knot." "\"K\", \"M\" dan \"N\" mewakili kilometer, batu dan knot."
#: src/tags.cpp:1981 #: src/tags.cpp:1981
msgid "" msgid ""
@ -25750,8 +25750,9 @@ msgid ""
"default \"look\" table. The data for this table is stored in the " "default \"look\" table. The data for this table is stored in the "
"ProfileLookTableData tag." "ProfileLookTableData tag."
msgstr "" msgstr ""
"Tag ini menyatakan bilangan sampel input dalam setiap dimensi jadual \"lihat" "Tag ini menyatakan bilangan sampel input dalam setiap dimensi jadual "
"\" lalai. Data bagi jadual ini disimpan dalam tag ProfileLookTableData." "\"lihat\" lalai. Data bagi jadual ini disimpan dalam tag "
"ProfileLookTableData."
#: src/tags.cpp:1256 #: src/tags.cpp:1256
msgid "" msgid ""

@ -2657,8 +2657,8 @@ msgstr ""
#: src/error.cpp:101 #: src/error.cpp:101
msgid "" msgid ""
"Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net `" "Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net "
"%1', `%2', `%3'" "`%1', `%2', `%3'"
msgstr "" msgstr ""
#: src/nikonmn.cpp:1680 #: src/nikonmn.cpp:1680
@ -12196,8 +12196,8 @@ msgstr ""
#: src/tags.cpp:2107 #: src/tags.cpp:2107
msgid "" msgid ""
"Indicates the unit used to express the distance to the destination point. \"K" "Indicates the unit used to express the distance to the destination point. "
"\", \"M\" and \"N\" represent kilometers, miles and knots." "\"K\", \"M\" and \"N\" represent kilometers, miles and knots."
msgstr "" msgstr ""
#: src/tags.cpp:1981 #: src/tags.cpp:1981

@ -23,8 +23,8 @@ msgstr ""
"X-Poedit-Country: POLAND\n" "X-Poedit-Country: POLAND\n"
"X-Poedit-Bookmarks: 991,1974,-1,-1,-1,-1,-1,-1,-1,-1\n" "X-Poedit-Bookmarks: 991,1974,-1,-1,-1,-1,-1,-1,-1,-1\n"
"X-Generator: KBabel 1.11.4\n" "X-Generator: KBabel 1.11.4\n"
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && "
"%100<10 || n%100>=20) ? 1 : 2);\n" "(n%100<10 || n%100>=20) ? 1 : 2);\n"
#: src/exiv2.cpp:262 #: src/exiv2.cpp:262
msgid "" msgid ""
@ -370,8 +370,8 @@ msgstr ""
msgid "" msgid ""
" -t Also set the file timestamp in 'rename' action (overrides -k).\n" " -t Also set the file timestamp in 'rename' action (overrides -k).\n"
msgstr "" msgstr ""
" -t Ustawia także znacznik czasowy pliku podczas akcji \"rename" " -t Ustawia także znacznik czasowy pliku podczas akcji "
"\" (nadpisuje opcję -k).\n" "\"rename\" (nadpisuje opcję -k).\n"
#: src/exiv2.cpp:287 #: src/exiv2.cpp:287
msgid " -u Show unknown tags.\n" msgid " -u Show unknown tags.\n"
@ -2814,8 +2814,8 @@ msgstr "Algier"
#: src/error.cpp:101 #: src/error.cpp:101
msgid "" msgid ""
"Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net `" "Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net "
"%1', `%2', `%3'" "`%1', `%2', `%3'"
msgstr "" msgstr ""
"Aliasy nie są obsługiwane. Prześlij proszę ten pakiet XMP do ahuggel@gmx.net " "Aliasy nie są obsługiwane. Prześlij proszę ten pakiet XMP do ahuggel@gmx.net "
"\"%1\", \"%2\", \"%3\"" "\"%1\", \"%2\", \"%3\""
@ -13280,8 +13280,8 @@ msgid ""
"Indicates the reference for giving the direction of the image when it is " "Indicates the reference for giving the direction of the image when it is "
"captured. \"T\" denotes true direction and \"M\" is magnetic direction." "captured. \"T\" denotes true direction and \"M\" is magnetic direction."
msgstr "" msgstr ""
"Oznaczenie rodzaju kierunku (namiaru) do obrazu podczas jego wykonywania. \"T" "Oznaczenie rodzaju kierunku (namiaru) do obrazu podczas jego wykonywania. "
"\" oznacza kierunek rzeczywisty, a \"M\" kierunek magnetyczny." "\"T\" oznacza kierunek rzeczywisty, a \"M\" kierunek magnetyczny."
#: src/tags.cpp:2099 #: src/tags.cpp:2099
msgid "" msgid ""
@ -13394,13 +13394,13 @@ msgid ""
"Indicates the unit used to express the GPS receiver speed of movement. \"K\" " "Indicates the unit used to express the GPS receiver speed of movement. \"K\" "
"\"M\" and \"N\" represents kilometers per hour, miles per hour, and knots." "\"M\" and \"N\" represents kilometers per hour, miles per hour, and knots."
msgstr "" msgstr ""
"Jednostka użyta do pomiaru prędkości ruchu odbiornika GPS. \"K\", \"M\" i \"N" "Jednostka użyta do pomiaru prędkości ruchu odbiornika GPS. \"K\", \"M\" i "
"\" oznaczają kilometry, mile i węzły." "\"N\" oznaczają kilometry, mile i węzły."
#: src/tags.cpp:2107 #: src/tags.cpp:2107
msgid "" msgid ""
"Indicates the unit used to express the distance to the destination point. \"K" "Indicates the unit used to express the distance to the destination point. "
"\", \"M\" and \"N\" represent kilometers, miles and knots." "\"K\", \"M\" and \"N\" represent kilometers, miles and knots."
msgstr "" msgstr ""
"Jednostki użyte do wyrażenia odległości do punktu docelowego. \"K\", \"M\" i " "Jednostki użyte do wyrażenia odległości do punktu docelowego. \"K\", \"M\" i "
"\"N\" oznaczają kilometry, mile i węzły." "\"N\" oznaczają kilometry, mile i węzły."
@ -13473,8 +13473,8 @@ msgid ""
"longitude. ASCII \"E\" indicates east longitude, and \"W\" is west longitude." "longitude. ASCII \"E\" indicates east longitude, and \"W\" is west longitude."
msgstr "" msgstr ""
"Określenie, czy długość geograficzna punktu docelowego jest wschodnia, czy " "Określenie, czy długość geograficzna punktu docelowego jest wschodnia, czy "
"zachodnia. Wartość ASCII \"E\" oznacza długość geograficzną wschodnią, a \"W" "zachodnia. Wartość ASCII \"E\" oznacza długość geograficzną wschodnią, a "
"\" zachodnią." "\"W\" zachodnią."
#: src/properties.cpp:1443 #: src/properties.cpp:1443
msgid "Indication of movie format (computer-generated, digitized, and so on)." msgid "Indication of movie format (computer-generated, digitized, and so on)."

@ -2822,8 +2822,8 @@ msgstr ""
#: src/error.cpp:101 #: src/error.cpp:101
msgid "" msgid ""
"Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net `" "Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net "
"%1', `%2', `%3'" "`%1', `%2', `%3'"
msgstr "" msgstr ""
#: src/nikonmn.cpp:1680 #: src/nikonmn.cpp:1680
@ -13520,8 +13520,8 @@ msgstr ""
#: src/tags.cpp:2107 #: src/tags.cpp:2107
msgid "" msgid ""
"Indicates the unit used to express the distance to the destination point. \"K" "Indicates the unit used to express the distance to the destination point. "
"\", \"M\" and \"N\" represent kilometers, miles and knots." "\"K\", \"M\" and \"N\" represent kilometers, miles and knots."
msgstr "" msgstr ""
#: src/tags.cpp:1981 #: src/tags.cpp:1981

@ -16,8 +16,8 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Generator: KBabel 1.10.2\n" "X-Generator: KBabel 1.10.2\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
#: src/exiv2.cpp:262 #: src/exiv2.cpp:262
msgid "" msgid ""
@ -2831,8 +2831,8 @@ msgstr ""
#: src/error.cpp:101 #: src/error.cpp:101
msgid "" msgid ""
"Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net `" "Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net "
"%1', `%2', `%3'" "`%1', `%2', `%3'"
msgstr "" msgstr ""
#: src/nikonmn.cpp:1680 #: src/nikonmn.cpp:1680
@ -13683,8 +13683,8 @@ msgstr ""
#: src/tags.cpp:2107 #: src/tags.cpp:2107
msgid "" msgid ""
"Indicates the unit used to express the distance to the destination point. \"K" "Indicates the unit used to express the distance to the destination point. "
"\", \"M\" and \"N\" represent kilometers, miles and knots." "\"K\", \"M\" and \"N\" represent kilometers, miles and knots."
msgstr "" msgstr ""
#: src/tags.cpp:1981 #: src/tags.cpp:1981

@ -2866,8 +2866,8 @@ msgstr "Algiers"
#: src/error.cpp:101 #: src/error.cpp:101
msgid "" msgid ""
"Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net `" "Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net "
"%1', `%2', `%3'" "`%1', `%2', `%3'"
msgstr "" msgstr ""
# AF = automatické zaostrenie # AF = automatické zaostrenie
@ -8957,8 +8957,8 @@ msgstr ""
#: src/error.cpp:78 #: src/error.cpp:78
msgid "Entry::setValue: Value too large (tag=%1, size=%2, requested=%3)" msgid "Entry::setValue: Value too large (tag=%1, size=%2, requested=%3)"
msgstr "" msgstr ""
"Entry::setValue: Hodnota je príliš veľká (značka=%1, veľkosť=%2, požadovaná=" "Entry::setValue: Hodnota je príliš veľká (značka=%1, veľkosť=%2, "
"%3)" "požadovaná=%3)"
#: src/datasets.cpp:108 #: src/datasets.cpp:108
msgid "Envelope Number" msgid "Envelope Number"
@ -13517,8 +13517,8 @@ msgstr ""
#: src/tags.cpp:2107 #: src/tags.cpp:2107
msgid "" msgid ""
"Indicates the unit used to express the distance to the destination point. \"K" "Indicates the unit used to express the distance to the destination point. "
"\", \"M\" and \"N\" represent kilometers, miles and knots." "\"K\", \"M\" and \"N\" represent kilometers, miles and knots."
msgstr "" msgstr ""
#: src/tags.cpp:1981 #: src/tags.cpp:1981

@ -3001,8 +3001,8 @@ msgstr "Alger"
#: src/error.cpp:101 #: src/error.cpp:101
msgid "" msgid ""
"Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net `" "Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net "
"%1', `%2', `%3'" "`%1', `%2', `%3'"
msgstr "" msgstr ""
"Alias stöds inte. Skicka detta XMP-paket till ahuggel@gmx.net ”%1”, ”%2”, " "Alias stöds inte. Skicka detta XMP-paket till ahuggel@gmx.net ”%1”, ”%2”, "
"”%3”" "”%3”"
@ -13244,8 +13244,8 @@ msgstr ""
#: src/tags.cpp:2107 #: src/tags.cpp:2107
msgid "" msgid ""
"Indicates the unit used to express the distance to the destination point. \"K" "Indicates the unit used to express the distance to the destination point. "
"\", \"M\" and \"N\" represent kilometers, miles and knots." "\"K\", \"M\" and \"N\" represent kilometers, miles and knots."
msgstr "" msgstr ""
"Visar enheten som används för att visa avstånd till destinationen. ”K”, ”M” " "Visar enheten som används för att visa avstånd till destinationen. ”K”, ”M” "
"och ”N” representerar kilometer, miles, och knop." "och ”N” representerar kilometer, miles, och knop."

@ -2664,8 +2664,8 @@ msgstr "ئالجىر"
#: src/error.cpp:101 #: src/error.cpp:101
msgid "" msgid ""
"Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net `" "Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net "
"%1', `%2', `%3'" "`%1', `%2', `%3'"
msgstr "" msgstr ""
#: src/nikonmn.cpp:1680 #: src/nikonmn.cpp:1680
@ -12824,8 +12824,8 @@ msgstr ""
#: src/tags.cpp:2107 #: src/tags.cpp:2107
msgid "" msgid ""
"Indicates the unit used to express the distance to the destination point. \"K" "Indicates the unit used to express the distance to the destination point. "
"\", \"M\" and \"N\" represent kilometers, miles and knots." "\"K\", \"M\" and \"N\" represent kilometers, miles and knots."
msgstr "" msgstr ""
#: src/tags.cpp:1981 #: src/tags.cpp:1981

@ -2765,8 +2765,8 @@ msgstr "Алжир"
#: src/error.cpp:101 #: src/error.cpp:101
msgid "" msgid ""
"Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net `" "Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net "
"%1', `%2', `%3'" "`%1', `%2', `%3'"
msgstr "" msgstr ""
"Псевдоніми не підтримуються. Будь ласка, відправте цей XMP пакунок за " "Псевдоніми не підтримуються. Будь ласка, відправте цей XMP пакунок за "
"адресою ahuggel@gmx.net `%1', `%2', `%3'" "адресою ahuggel@gmx.net `%1', `%2', `%3'"
@ -13078,8 +13078,8 @@ msgstr ""
#: src/tags.cpp:2107 #: src/tags.cpp:2107
msgid "" msgid ""
"Indicates the unit used to express the distance to the destination point. \"K" "Indicates the unit used to express the distance to the destination point. "
"\", \"M\" and \"N\" represent kilometers, miles and knots." "\"K\", \"M\" and \"N\" represent kilometers, miles and knots."
msgstr "" msgstr ""
#: src/tags.cpp:1981 #: src/tags.cpp:1981

@ -2706,8 +2706,8 @@ msgstr ""
#: src/error.cpp:101 #: src/error.cpp:101
msgid "" msgid ""
"Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net `" "Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net "
"%1', `%2', `%3'" "`%1', `%2', `%3'"
msgstr "" msgstr ""
#: src/nikonmn.cpp:1680 #: src/nikonmn.cpp:1680
@ -13077,8 +13077,8 @@ msgstr ""
#: src/tags.cpp:2107 #: src/tags.cpp:2107
msgid "" msgid ""
"Indicates the unit used to express the distance to the destination point. \"K" "Indicates the unit used to express the distance to the destination point. "
"\", \"M\" and \"N\" represent kilometers, miles and knots." "\"K\", \"M\" and \"N\" represent kilometers, miles and knots."
msgstr "" msgstr ""
#: src/tags.cpp:1981 #: src/tags.cpp:1981

@ -32,7 +32,7 @@ int main(int argc, char* const argv[]) {
// a given key already exists, its value is overwritten. Otherwise a new // a given key already exists, its value is overwritten. Otherwise a new
// tag is added. // tag is added.
exifData["Exif.Image.Model"] = "Test 1"; // AsciiValue exifData["Exif.Image.Model"] = "Test 1"; // AsciiValue
exifData["Exif.Image.SamplesPerPixel"] = uint16_t(162); // UShortValue exifData["Exif.Image.SamplesPerPixel"] = static_cast<uint16_t>(162); // UShortValue
exifData["Exif.Image.XResolution"] = -2; // LongValue exifData["Exif.Image.XResolution"] = -2; // LongValue
exifData["Exif.Image.YResolution"] = Exiv2::Rational(-2, 3); // RationalValue exifData["Exif.Image.YResolution"] = Exiv2::Rational(-2, 3); // RationalValue
std::cout << "Added a few tags the quick way.\n"; std::cout << "Added a few tags the quick way.\n";

@ -34,9 +34,9 @@ int main(int argc, char* const argv[]) {
std::cout << "Copy construction, non-intrusive changes\n"; std::cout << "Copy construction, non-intrusive changes\n";
Exiv2::ExifData ed1(ed); Exiv2::ExifData ed1(ed);
ed1["Exif.Image.DateTime"] = "Sunday, 11am"; ed1["Exif.Image.DateTime"] = "Sunday, 11am";
ed1["Exif.Image.Orientation"] = uint16_t(2); ed1["Exif.Image.Orientation"] = static_cast<uint16_t>(2);
ed1["Exif.Photo.DateTimeOriginal"] = "Sunday, 11am"; ed1["Exif.Photo.DateTimeOriginal"] = "Sunday, 11am";
ed1["Exif.Photo.MeteringMode"] = uint16_t(1); ed1["Exif.Photo.MeteringMode"] = static_cast<uint16_t>(1);
ed1["Exif.Iop.InteroperabilityIndex"] = "123"; ed1["Exif.Iop.InteroperabilityIndex"] = "123";
// ed1["Exif.Thumbnail.Orientation"] = uint16_t(2); // ed1["Exif.Thumbnail.Orientation"] = uint16_t(2);
write(file, ed1); write(file, ed1);
@ -61,11 +61,11 @@ int main(int argc, char* const argv[]) {
ed3["Exif.Thumbnail.Artist"] = "Test 6 Ifd1 tag"; ed3["Exif.Thumbnail.Artist"] = "Test 6 Ifd1 tag";
ed3 = ed; ed3 = ed;
ed3["Exif.Image.DateTime"] = "Sunday, 11am"; ed3["Exif.Image.DateTime"] = "Sunday, 11am";
ed3["Exif.Image.Orientation"] = uint16_t(2); ed3["Exif.Image.Orientation"] = static_cast<uint16_t>(2);
ed3["Exif.Photo.DateTimeOriginal"] = "Sunday, 11am"; ed3["Exif.Photo.DateTimeOriginal"] = "Sunday, 11am";
ed3["Exif.Photo.MeteringMode"] = uint16_t(1); ed3["Exif.Photo.MeteringMode"] = static_cast<uint16_t>(1);
ed3["Exif.Iop.InteroperabilityIndex"] = "123"; ed3["Exif.Iop.InteroperabilityIndex"] = "123";
ed3["Exif.Thumbnail.Orientation"] = uint16_t(2); ed3["Exif.Thumbnail.Orientation"] = static_cast<uint16_t>(2);
write(file, ed3); write(file, ed3);
print(file); print(file);
std::cout << "----------------------------------------------\n"; std::cout << "----------------------------------------------\n";
@ -78,9 +78,9 @@ int main(int argc, char* const argv[]) {
ed4["Exif.Image.DateTime"] = "Sunday, 11am and ten minutes"; ed4["Exif.Image.DateTime"] = "Sunday, 11am and ten minutes";
ed4["Exif.Image.Orientation"] = "2 3 4 5"; ed4["Exif.Image.Orientation"] = "2 3 4 5";
ed4["Exif.Photo.DateTimeOriginal"] = "Sunday, 11am and ten minutes"; ed4["Exif.Photo.DateTimeOriginal"] = "Sunday, 11am and ten minutes";
ed4["Exif.Photo.MeteringMode"] = uint16_t(1); ed4["Exif.Photo.MeteringMode"] = static_cast<uint16_t>(1);
ed4["Exif.Iop.InteroperabilityIndex"] = "123"; ed4["Exif.Iop.InteroperabilityIndex"] = "123";
ed4["Exif.Thumbnail.Orientation"] = uint16_t(2); ed4["Exif.Thumbnail.Orientation"] = static_cast<uint16_t>(2);
write(file, ed4); write(file, ed4);
print(file); print(file);

@ -23,7 +23,7 @@ int main(int argc, char* const argv[]) try {
iptcData["Iptc.Application2.Headline"] = "The headline I am"; iptcData["Iptc.Application2.Headline"] = "The headline I am";
iptcData["Iptc.Application2.Keywords"] = "Yet another keyword"; iptcData["Iptc.Application2.Keywords"] = "Yet another keyword";
iptcData["Iptc.Application2.DateCreated"] = "2004-8-3"; iptcData["Iptc.Application2.DateCreated"] = "2004-8-3";
iptcData["Iptc.Application2.Urgency"] = uint16_t(1); iptcData["Iptc.Application2.Urgency"] = static_cast<uint16_t>(1);
iptcData["Iptc.Envelope.ModelVersion"] = 42; iptcData["Iptc.Envelope.ModelVersion"] = 42;
iptcData["Iptc.Envelope.TimeSent"] = "14:41:0-05:00"; iptcData["Iptc.Envelope.TimeSent"] = "14:41:0-05:00";
iptcData["Iptc.Application2.RasterizedCaption"] = "230 42 34 2 90 84 23 146"; iptcData["Iptc.Application2.RasterizedCaption"] = "230 42 34 2 90 84 23 146";

@ -39,7 +39,7 @@ int main(int argc, char* const argv[]) {
exifData["Exif.Image.Copyright"] = "Exiv2"; // AsciiValue exifData["Exif.Image.Copyright"] = "Exiv2"; // AsciiValue
exifData["Exif.Image.Make"] = "Canon"; // AsciiValue exifData["Exif.Image.Make"] = "Canon"; // AsciiValue
exifData["Exif.Canon.OwnerName"] = "Tuan"; // UShortValue exifData["Exif.Canon.OwnerName"] = "Tuan"; // UShortValue
exifData["Exif.CanonCs.LensType"] = uint16_t(65535); // LongValue exifData["Exif.CanonCs.LensType"] = static_cast<uint16_t>(65535); // LongValue
Exiv2::Value::UniquePtr v = Exiv2::Value::create(Exiv2::asciiString); Exiv2::Value::UniquePtr v = Exiv2::Value::create(Exiv2::asciiString);
v->read("2013:06:09 14:30:30"); v->read("2013:06:09 14:30:30");
Exiv2::ExifKey key("Exif.Image.DateTime"); Exiv2::ExifKey key("Exif.Image.DateTime");

@ -61,7 +61,7 @@ void mini1(const char* path) {
enforce(wm == wmIntrusive, Exiv2::ErrorCode::kerErrorMessage, "encode returned an unexpected value"); enforce(wm == wmIntrusive, Exiv2::ErrorCode::kerErrorMessage, "encode returned an unexpected value");
std::cout << "Test 3: Wrote non-empty Exif data without original binary data:\n"; std::cout << "Test 3: Wrote non-empty Exif data without original binary data:\n";
exifData.clear(); exifData.clear();
ByteOrder bo = ExifParser::decode(exifData, &blob[0], blob.size()); ByteOrder bo = ExifParser::decode(exifData, blob.data(), blob.size());
enforce(bo == bigEndian, Exiv2::ErrorCode::kerErrorMessage, "decode returned an unexpected value"); enforce(bo == bigEndian, Exiv2::ErrorCode::kerErrorMessage, "decode returned an unexpected value");
print(exifData); print(exifData);
} }

@ -56,11 +56,11 @@ int main(int argc, char* const argv[]) {
edMn1["Exif.Image.Make"] = "Canon"; edMn1["Exif.Image.Make"] = "Canon";
edMn1["Exif.Image.Model"] = "Canon PowerShot S40"; edMn1["Exif.Image.Model"] = "Canon PowerShot S40";
edMn1["Exif.Canon.0xabcd"] = "A Canon makernote tag"; edMn1["Exif.Canon.0xabcd"] = "A Canon makernote tag";
edMn1["Exif.CanonCs.0x0002"] = uint16_t(41); edMn1["Exif.CanonCs.0x0002"] = static_cast<uint16_t>(41);
edMn1["Exif.CanonSi.0x0005"] = uint16_t(42); edMn1["Exif.CanonSi.0x0005"] = static_cast<uint16_t>(42);
edMn1["Exif.CanonCf.0x0001"] = uint16_t(43); edMn1["Exif.CanonCf.0x0001"] = static_cast<uint16_t>(43);
edMn1["Exif.CanonPi.0x0001"] = uint16_t(44); edMn1["Exif.CanonPi.0x0001"] = static_cast<uint16_t>(44);
edMn1["Exif.CanonPa.0x0001"] = uint16_t(45); edMn1["Exif.CanonPa.0x0001"] = static_cast<uint16_t>(45);
write(file, edMn1); write(file, edMn1);
print(file); print(file);
@ -69,8 +69,8 @@ int main(int argc, char* const argv[]) {
image->readMetadata(); image->readMetadata();
Exiv2::ExifData& rEd = image->exifData(); Exiv2::ExifData& rEd = image->exifData();
rEd["Exif.CanonCs.0x0001"] = uint16_t(88); rEd["Exif.CanonCs.0x0001"] = static_cast<uint16_t>(88);
rEd["Exif.CanonSi.0x0004"] = uint16_t(99); rEd["Exif.CanonSi.0x0004"] = static_cast<uint16_t>(99);
image->writeMetadata(); image->writeMetadata();
print(file); print(file);
@ -118,7 +118,7 @@ int main(int argc, char* const argv[]) {
Exiv2::ExifData edMn7; Exiv2::ExifData edMn7;
edMn7["Exif.Image.Make"] = "OLYMPUS CORPORATION"; edMn7["Exif.Image.Make"] = "OLYMPUS CORPORATION";
edMn7["Exif.Image.Model"] = "C8080WZ"; edMn7["Exif.Image.Model"] = "C8080WZ";
edMn7["Exif.Olympus.0x0201"] = uint16_t(1); edMn7["Exif.Olympus.0x0201"] = static_cast<uint16_t>(1);
write(file, edMn7); write(file, edMn7);
print(file); print(file);
@ -126,7 +126,7 @@ int main(int argc, char* const argv[]) {
Exiv2::ExifData edMn8; Exiv2::ExifData edMn8;
edMn8["Exif.Image.Make"] = "Panasonic"; edMn8["Exif.Image.Make"] = "Panasonic";
edMn8["Exif.Image.Model"] = "DMC-FZ5"; edMn8["Exif.Image.Model"] = "DMC-FZ5";
edMn8["Exif.Panasonic.0x0001"] = uint16_t(1); edMn8["Exif.Panasonic.0x0001"] = static_cast<uint16_t>(1);
write(file, edMn8); write(file, edMn8);
print(file); print(file);
@ -142,13 +142,13 @@ int main(int argc, char* const argv[]) {
Exiv2::ExifData edMn10; Exiv2::ExifData edMn10;
edMn10["Exif.Image.Make"] = "Minolta"; edMn10["Exif.Image.Make"] = "Minolta";
edMn10["Exif.Image.Model"] = "A fancy Minolta camera"; edMn10["Exif.Image.Model"] = "A fancy Minolta camera";
edMn10["Exif.Minolta.ColorMode"] = uint32_t(1); edMn10["Exif.Minolta.ColorMode"] = static_cast<uint32_t>(1);
edMn10["Exif.MinoltaCsNew.WhiteBalance"] = uint32_t(2); edMn10["Exif.MinoltaCsNew.WhiteBalance"] = static_cast<uint32_t>(2);
edMn10["Exif.MinoltaCs5D.WhiteBalance"] = uint16_t(3); edMn10["Exif.MinoltaCs5D.WhiteBalance"] = static_cast<uint16_t>(3);
edMn10["Exif.MinoltaCs5D.ColorTemperature"] = int16_t(-1); edMn10["Exif.MinoltaCs5D.ColorTemperature"] = static_cast<int16_t>(-1);
edMn10["Exif.MinoltaCs7D.WhiteBalance"] = uint16_t(4); edMn10["Exif.MinoltaCs7D.WhiteBalance"] = static_cast<uint16_t>(4);
edMn10["Exif.MinoltaCs7D.ExposureCompensation"] = int16_t(-2); edMn10["Exif.MinoltaCs7D.ExposureCompensation"] = static_cast<int16_t>(-2);
edMn10["Exif.MinoltaCs7D.ColorTemperature"] = int16_t(-3); edMn10["Exif.MinoltaCs7D.ColorTemperature"] = static_cast<int16_t>(-3);
write(file, edMn10); write(file, edMn10);
print(file); print(file);

@ -40,7 +40,7 @@ int main() try {
xmpData["Xmp.dc.one"] = -1; xmpData["Xmp.dc.one"] = -1;
xmpData["Xmp.dc.two"] = 3.1415; xmpData["Xmp.dc.two"] = 3.1415;
xmpData["Xmp.dc.three"] = Exiv2::Rational(5, 7); xmpData["Xmp.dc.three"] = Exiv2::Rational(5, 7);
xmpData["Xmp.dc.four"] = uint16_t(255); xmpData["Xmp.dc.four"] = static_cast<uint16_t>(255);
xmpData["Xmp.dc.five"] = 256; xmpData["Xmp.dc.five"] = 256;
xmpData["Xmp.dc.six"] = false; xmpData["Xmp.dc.six"] = false;

@ -458,8 +458,10 @@ int FileIo::seek(int64_t offset, Position pos) {
#endif #endif
} }
long FileIo::tell() const { size_t FileIo::tell() const {
return std::ftell(p_->fp_); const long pos = std::ftell(p_->fp_);
enforce(pos >= 0, ErrorCode::kerInputDataReadFailed);
return static_cast<size_t>(pos);
} }
size_t FileIo::size() const { size_t FileIo::size() const {
@ -786,8 +788,8 @@ int MemIo::munmap() {
return 0; return 0;
} }
long MemIo::tell() const { size_t MemIo::tell() const {
return static_cast<long>(p_->idx_); return p_->idx_;
} }
size_t MemIo::size() const { size_t MemIo::size() const {
@ -899,7 +901,7 @@ void XPathIo::ReadDataUri(const std::string& path) {
} }
#else #else
XPathIo::XPathIo(const std::string& orgPath) : FileIo(XPathIo::writeDataToFile(orgPath)), isTemp_(true) { XPathIo::XPathIo(const std::string& orgPath) : FileIo(XPathIo::writeDataToFile(orgPath)) {
tempFilePath_ = path(); tempFilePath_ = path();
} }
@ -994,13 +996,13 @@ class RemoteIo::Impl {
// DATA // DATA
std::string path_; //!< (Standard) path std::string path_; //!< (Standard) path
size_t blockSize_; //!< Size of the block memory. size_t blockSize_; //!< Size of the block memory.
BlockMap* blocksMap_; //!< An array contains all blocksMap BlockMap* blocksMap_{nullptr}; //!< An array contains all blocksMap
size_t size_; //!< The file size size_t size_{0}; //!< The file size
size_t idx_; //!< Index into the memory area size_t idx_{0}; //!< Index into the memory area
bool isMalloced_; //!< Was the blocksMap_ allocated? bool isMalloced_{false}; //!< Was the blocksMap_ allocated?
bool eof_; //!< EOF indicator bool eof_{false}; //!< EOF indicator
Protocol protocol_; //!< the protocol of url Protocol protocol_; //!< the protocol of url
size_t totalRead_; //!< bytes requested from host size_t totalRead_{0}; //!< bytes requested from host
// METHODS // METHODS
/*! /*!
@ -1042,15 +1044,7 @@ class RemoteIo::Impl {
}; // class RemoteIo::Impl }; // class RemoteIo::Impl
RemoteIo::Impl::Impl(const std::string& url, size_t blockSize) : RemoteIo::Impl::Impl(const std::string& url, size_t blockSize) :
path_(url), path_(url), blockSize_(blockSize), protocol_(fileProtocol(url)) {
blockSize_(blockSize),
blocksMap_(nullptr),
size_(0),
idx_(0),
isMalloced_(false),
eof_(false),
protocol_(fileProtocol(url)),
totalRead_(0) {
} }
size_t RemoteIo::Impl::populateBlocks(size_t lowBlock, size_t highBlock) { size_t RemoteIo::Impl::populateBlocks(size_t lowBlock, size_t highBlock) {
@ -1341,8 +1335,8 @@ int RemoteIo::munmap() {
return 0; return 0;
} }
long RemoteIo::tell() const { size_t RemoteIo::tell() const {
return static_cast<long>(p_->idx_); return p_->idx_;
} }
size_t RemoteIo::size() const { size_t RemoteIo::size() const {
@ -1473,7 +1467,7 @@ void HttpIo::HttpImpl::writeRemote(const byte* data, size_t size, size_t from, s
// standardize the path without "/" at the beginning. // standardize the path without "/" at the beginning.
std::size_t protocolIndex = scriptPath.find("://"); std::size_t protocolIndex = scriptPath.find("://");
if (protocolIndex == std::string::npos && scriptPath[0] != '/') { if (protocolIndex == std::string::npos && scriptPath.front() != '/') {
scriptPath = "/" + scriptPath; scriptPath = "/" + scriptPath;
} }
@ -1663,7 +1657,7 @@ void CurlIo::CurlImpl::writeRemote(const byte* data, size_t size, size_t from, s
// add the protocol and host to the path // add the protocol and host to the path
std::size_t protocolIndex = scriptPath.find("://"); std::size_t protocolIndex = scriptPath.find("://");
if (protocolIndex == std::string::npos) { if (protocolIndex == std::string::npos) {
if (scriptPath[0] != '/') if (scriptPath.front() != '/')
scriptPath = "/" + scriptPath; scriptPath = "/" + scriptPath;
scriptPath = hostInfo.Protocol + "://" + hostInfo.Host + scriptPath; scriptPath = hostInfo.Protocol + "://" + hostInfo.Host + scriptPath;
} }

@ -74,7 +74,7 @@ BmffImage::BmffImage(BasicIo::UniquePtr io, bool /* create */) :
Image(ImageType::bmff, mdExif | mdIptc | mdXmp, std::move(io)) { Image(ImageType::bmff, mdExif | mdIptc | mdXmp, std::move(io)) {
} // BmffImage::BmffImage } // BmffImage::BmffImage
std::string BmffImage::toAscii(long n) { std::string BmffImage::toAscii(uint32_t n) {
const auto p = reinterpret_cast<const char*>(&n); const auto p = reinterpret_cast<const char*>(&n);
std::string result; std::string result;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
@ -152,9 +152,9 @@ std::string BmffImage::uuidName(Exiv2::DataBuf& uuid) {
return result; return result;
} }
long BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintStructureOption option /* = kpsNone */, uint64_t BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintStructureOption option /* = kpsNone */,
long pbox_end, int depth) { uint64_t pbox_end, int depth) {
long address = io_->tell(); const size_t address = io_->tell();
// never visit a box twice! // never visit a box twice!
if (depth == 0) if (depth == 0)
visits_.clear(); visits_.clear();
@ -198,22 +198,22 @@ long BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintStruc
} }
// read data in box and restore file position // read data in box and restore file position
long restore = io_->tell(); const size_t restore = io_->tell();
enforce(box_length >= hdrsize, Exiv2::ErrorCode::kerCorruptedMetadata); enforce(box_length >= hdrsize, Exiv2::ErrorCode::kerCorruptedMetadata);
enforce(box_length - hdrsize <= static_cast<uint64_t>(pbox_end - restore), Exiv2::ErrorCode::kerCorruptedMetadata); enforce(box_length - hdrsize <= pbox_end - restore, Exiv2::ErrorCode::kerCorruptedMetadata);
const auto buffer_size = static_cast<size_t>(box_length - hdrsize); const auto buffer_size = box_length - hdrsize;
if (skipBox(box_type)) { if (skipBox(box_type)) {
if (bTrace) { if (bTrace) {
out << std::endl; out << std::endl;
} }
// The enforce() above checks that restore + buffer_size won't // The enforce() above checks that restore + buffer_size won't
// exceed pbox_end, and by implication, won't exceed LONG_MAX // exceed pbox_end, and by implication, won't exceed LONG_MAX
return restore + static_cast<long>(buffer_size); return restore + buffer_size;
} }
DataBuf data(buffer_size); DataBuf data(static_cast<size_t>(buffer_size));
const long box_end = restore + static_cast<long>(data.size()); const size_t box_end = restore + data.size();
io_->read(data.data(), data.size()); io_->read(data.data(), data.size());
io_->seek(restore, BasicIo::beg); io_->seek(restore, BasicIo::beg);
@ -437,10 +437,10 @@ long BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintStruc
parseTiff(Internal::Tag::cmt4, box_length); parseTiff(Internal::Tag::cmt4, box_length);
break; break;
case TAG_exif: case TAG_exif:
parseTiff(Internal::Tag::root, box_length, address + 8); parseTiff(Internal::Tag::root, buffer_size, io_->tell());
break; break;
case TAG_xml: case TAG_xml:
parseXmp(box_length, io_->tell()); parseXmp(buffer_size, io_->tell());
break; break;
case TAG_thmb: case TAG_thmb:
switch (version) { switch (version) {
@ -478,26 +478,25 @@ long BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintStruc
void BmffImage::parseTiff(uint32_t root_tag, uint64_t length, uint64_t start) { void BmffImage::parseTiff(uint32_t root_tag, uint64_t length, uint64_t start) {
enforce(start <= io_->size(), ErrorCode::kerCorruptedMetadata); enforce(start <= io_->size(), ErrorCode::kerCorruptedMetadata);
enforce(length <= io_->size() - start, ErrorCode::kerCorruptedMetadata); enforce(length <= io_->size() - start, ErrorCode::kerCorruptedMetadata);
enforce(start <= std::numeric_limits<uint64_t>::max(), ErrorCode::kerCorruptedMetadata); enforce(start <= static_cast<uint64_t>(std::numeric_limits<int64_t>::max()), ErrorCode::kerCorruptedMetadata);
enforce(length <= std::numeric_limits<uint64_t>::max(), ErrorCode::kerCorruptedMetadata); enforce(length <= std::numeric_limits<size_t>::max(), ErrorCode::kerCorruptedMetadata);
// read and parse exif data // read and parse exif data
long restore = io_->tell(); const size_t restore = io_->tell();
DataBuf exif(static_cast<size_t>(length)); DataBuf exif(static_cast<size_t>(length));
io_->seek(static_cast<long>(start), BasicIo::beg); io_->seek(static_cast<int64_t>(start), BasicIo::beg);
if (exif.size() > 8 && io_->read(exif.data(), exif.size()) == exif.size()) { if (exif.size() > 8 && io_->read(exif.data(), exif.size()) == exif.size()) {
// hunt for "II" or "MM" // hunt for "II" or "MM"
long eof = 0xffffffff; // impossible value for punt const size_t eof = std::numeric_limits<size_t>::max(); // impossible value for punt
long punt = eof; size_t punt = eof;
for (size_t i = 0; i < exif.size() - 8 && punt == eof; i += 2) { for (size_t i = 0; i < exif.size() - 8 && punt == eof; i += 2) {
if (exif.read_uint8(i) == exif.read_uint8(i + 1)) if (exif.read_uint8(i) == exif.read_uint8(i + 1))
if (exif.read_uint8(i) == 'I' || exif.read_uint8(i) == 'M') if (exif.read_uint8(i) == 'I' || exif.read_uint8(i) == 'M')
punt = static_cast<long>(i); punt = i;
} }
if (punt != eof) { if (punt != eof) {
Internal::TiffParserWorker::decode(exifData(), iptcData(), xmpData(), exif.c_data(punt), Internal::TiffParserWorker::decode(exifData(), iptcData(), xmpData(), exif.c_data(punt), exif.size() - punt,
static_cast<uint32_t>(exif.size() - punt), root_tag, root_tag, Internal::TiffMapping::findDecoder);
Internal::TiffMapping::findDecoder);
} }
} }
io_->seek(restore, BasicIo::beg); io_->seek(restore, BasicIo::beg);
@ -506,7 +505,7 @@ void BmffImage::parseTiff(uint32_t root_tag, uint64_t length, uint64_t start) {
void BmffImage::parseTiff(uint32_t root_tag, uint64_t length) { void BmffImage::parseTiff(uint32_t root_tag, uint64_t length) {
if (length > 8) { if (length > 8) {
enforce(length - 8 <= io_->size() - io_->tell(), ErrorCode::kerCorruptedMetadata); enforce(length - 8 <= io_->size() - io_->tell(), ErrorCode::kerCorruptedMetadata);
enforce(length - 8 <= std::numeric_limits<uint64_t>::max(), ErrorCode::kerCorruptedMetadata); enforce(length - 8 <= std::numeric_limits<size_t>::max(), ErrorCode::kerCorruptedMetadata);
DataBuf data(static_cast<size_t>(length - 8u)); DataBuf data(static_cast<size_t>(length - 8u));
const size_t bufRead = io_->read(data.data(), data.size()); const size_t bufRead = io_->read(data.data(), data.size());
@ -521,12 +520,11 @@ void BmffImage::parseTiff(uint32_t root_tag, uint64_t length) {
} }
void BmffImage::parseXmp(uint64_t length, uint64_t start) { void BmffImage::parseXmp(uint64_t length, uint64_t start) {
if (length > 8) {
enforce(start <= io_->size(), ErrorCode::kerCorruptedMetadata); enforce(start <= io_->size(), ErrorCode::kerCorruptedMetadata);
enforce(length <= io_->size() - start, ErrorCode::kerCorruptedMetadata); enforce(length <= io_->size() - start, ErrorCode::kerCorruptedMetadata);
long restore = io_->tell(); const size_t restore = io_->tell();
io_->seek(static_cast<long>(start), BasicIo::beg); io_->seek(static_cast<int64_t>(start), BasicIo::beg);
auto lengthSizeT = static_cast<size_t>(length); auto lengthSizeT = static_cast<size_t>(length);
DataBuf xmp(lengthSizeT + 1); DataBuf xmp(lengthSizeT + 1);
@ -543,15 +541,13 @@ void BmffImage::parseXmp(uint64_t length, uint64_t start) {
io_->seek(restore, BasicIo::beg); io_->seek(restore, BasicIo::beg);
} }
}
/// \todo instead of passing the last 4 parameters, pass just one and build the different offsets inside /// \todo instead of passing the last 4 parameters, pass just one and build the different offsets inside
void BmffImage::parseCr3Preview(DataBuf& data, std::ostream& out, bool bTrace, uint8_t version, size_t width_offset, void BmffImage::parseCr3Preview(DataBuf& data, std::ostream& out, bool bTrace, uint8_t version, size_t width_offset,
size_t height_offset, size_t size_offset, size_t relative_position) { size_t height_offset, size_t size_offset, size_t relative_position) {
// Derived from https://github.com/lclevy/canon_cr3 // Derived from https://github.com/lclevy/canon_cr3
long here = io_->tell(); const size_t here = io_->tell();
enforce(here >= 0 && here <= std::numeric_limits<long>::max() - static_cast<long>(relative_position), enforce(here <= std::numeric_limits<size_t>::max() - relative_position, ErrorCode::kerCorruptedMetadata);
ErrorCode::kerCorruptedMetadata);
NativePreview nativePreview; NativePreview nativePreview;
nativePreview.position_ = here + relative_position; nativePreview.position_ = here + relative_position;
nativePreview.width_ = data.read_uint16(width_offset, endian_); nativePreview.width_ = data.read_uint16(width_offset, endian_);
@ -569,12 +565,12 @@ void BmffImage::parseCr3Preview(DataBuf& data, std::ostream& out, bool bTrace, u
nativePreviews_.push_back(nativePreview); nativePreviews_.push_back(nativePreview);
if (bTrace) { if (bTrace) {
out << Internal::stringFormat("width,height,size = %u,%u,%u", nativePreview.width_, nativePreview.height_, out << Internal::stringFormat("width,height,size = %zu,%zu,%zu", nativePreview.width_, nativePreview.height_,
nativePreview.size_); nativePreview.size_);
} }
} }
void BmffImage::setComment(std::string_view /*comment*/) { void BmffImage::setComment(const std::string&) {
// bmff files are read-only // bmff files are read-only
throw(Error(ErrorCode::kerInvalidSettingForImage, "Image comment", "BMFF")); throw(Error(ErrorCode::kerInvalidSettingForImage, "Image comment", "BMFF"));
} }
@ -602,8 +598,8 @@ void BmffImage::readMetadata() {
exifID_ = unknownID_; exifID_ = unknownID_;
xmpID_ = unknownID_; xmpID_ = unknownID_;
long address = 0; uint64_t address = 0;
const auto file_end = static_cast<long>(io_->size()); const auto file_end = io_->size();
while (address < file_end) { while (address < file_end) {
io_->seek(address, BasicIo::beg); io_->seek(address, BasicIo::beg);
address = boxHandler(std::cout, kpsNone, file_end, 0); address = boxHandler(std::cout, kpsNone, file_end, 0);
@ -637,8 +633,8 @@ void BmffImage::printStructure(std::ostream& out, Exiv2::PrintStructureOption op
openOrThrow(); openOrThrow();
IoCloser closer(*io_); IoCloser closer(*io_);
long address = 0; uint64_t address = 0;
const auto file_end = static_cast<long>(io_->size()); const auto file_end = io_->size();
while (address < file_end) { while (address < file_end) {
io_->seek(address, BasicIo::beg); io_->seek(address, BasicIo::beg);
address = boxHandler(out, option, file_end, depth); address = boxHandler(out, option, file_end, depth);
@ -684,7 +680,7 @@ bool isBmffType(BasicIo& iIo, bool advance) {
bool const is_video = (buf[8] == 'q' && buf[9] == 't' && buf[10] == ' ' && buf[11] == ' '); bool const is_video = (buf[8] == 'q' && buf[9] == 't' && buf[10] == ' ' && buf[11] == ' ');
bool matched = is_jxl || (is_ftyp && !is_video); bool matched = is_jxl || (is_ftyp && !is_video);
if (!advance || !matched) { if (!advance || !matched) {
iIo.seek(static_cast<long>(0), BasicIo::beg); iIo.seek(0, BasicIo::beg);
} }
return matched; return matched;
} }

@ -35,7 +35,7 @@ void BmpImage::setIptcData(const IptcData& /*iptcData*/) {
throw(Error(ErrorCode::kerInvalidSettingForImage, "IPTC metadata", "BMP")); throw(Error(ErrorCode::kerInvalidSettingForImage, "IPTC metadata", "BMP"));
} }
void BmpImage::setComment(std::string_view /*comment*/) { void BmpImage::setComment(const std::string&) {
throw(Error(ErrorCode::kerInvalidSettingForImage, "Image comment", "BMP")); throw(Error(ErrorCode::kerInvalidSettingForImage, "Image comment", "BMP"));
} }

File diff suppressed because it is too large Load Diff

@ -80,43 +80,45 @@ constexpr TagDetails casioCCDSensitivity[] = {
// Casio MakerNote Tag Info // Casio MakerNote Tag Info
constexpr TagInfo CasioMakerNote::tagInfo_[] = { constexpr TagInfo CasioMakerNote::tagInfo_[] = {
{0x0001, "RecodingMode", N_("RecodingMode"), N_("Recording Mode"), casioId, makerTags, unsignedShort, -1, {0x0001, "RecodingMode", N_("RecodingMode"), N_("Recording Mode"), IfdId::casioId, SectionId::makerTags,
EXV_PRINT_TAG(casioRecordingMode)}, unsignedShort, -1, EXV_PRINT_TAG(casioRecordingMode)},
{0x0002, "Quality", N_("Quality"), N_("Quality"), casioId, makerTags, unsignedShort, -1, {0x0002, "Quality", N_("Quality"), N_("Quality"), IfdId::casioId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casioQuality)}, EXV_PRINT_TAG(casioQuality)},
{0x0003, "FocusMode", N_("Focus Mode"), N_("Focus Mode"), casioId, makerTags, unsignedShort, -1, {0x0003, "FocusMode", N_("Focus Mode"), N_("Focus Mode"), IfdId::casioId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casioFocusMode)}, EXV_PRINT_TAG(casioFocusMode)},
{0x0004, "FlashMode", N_("Flash Mode"), N_("Flash Mode"), casioId, makerTags, unsignedShort, -1, {0x0004, "FlashMode", N_("Flash Mode"), N_("Flash Mode"), IfdId::casioId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casioFlashMode)}, EXV_PRINT_TAG(casioFlashMode)},
{0x0005, "FlashIntensity", N_("Flash Intensity"), N_("Flash Intensity"), casioId, makerTags, unsignedShort, -1, {0x0005, "FlashIntensity", N_("Flash Intensity"), N_("Flash Intensity"), IfdId::casioId, SectionId::makerTags,
EXV_PRINT_TAG(casioFlashIntensity)}, unsignedShort, -1, EXV_PRINT_TAG(casioFlashIntensity)},
{0x0006, "ObjectDistance", N_("Object Distance"), N_("Distance to object"), casioId, makerTags, unsignedLong, -1, {0x0006, "ObjectDistance", N_("Object Distance"), N_("Distance to object"), IfdId::casioId, SectionId::makerTags,
print0x0006}, unsignedLong, -1, print0x0006},
{0x0007, "WhiteBalance", N_("White Balance"), N_("White balance settings"), casioId, makerTags, unsignedShort, -1, {0x0007, "WhiteBalance", N_("White Balance"), N_("White balance settings"), IfdId::casioId, SectionId::makerTags,
EXV_PRINT_TAG(casioWhiteBalance)}, unsignedShort, -1, EXV_PRINT_TAG(casioWhiteBalance)},
{0x000a, "DigitalZoom", N_("Digital Zoom"), N_("Digital zoom"), casioId, makerTags, unsignedLong, -1, {0x000a, "DigitalZoom", N_("Digital Zoom"), N_("Digital zoom"), IfdId::casioId, SectionId::makerTags, unsignedLong,
EXV_PRINT_TAG(casioDigitalZoom)}, -1, EXV_PRINT_TAG(casioDigitalZoom)},
{0x000b, "Sharpness", N_("Sharpness"), N_("Sharpness"), casioId, makerTags, unsignedShort, -1, {0x000b, "Sharpness", N_("Sharpness"), N_("Sharpness"), IfdId::casioId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casioSharpness)}, EXV_PRINT_TAG(casioSharpness)},
{0x000c, "Contrast", N_("Contrast"), N_("Contrast"), casioId, makerTags, unsignedShort, -1, {0x000c, "Contrast", N_("Contrast"), N_("Contrast"), IfdId::casioId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casioContrast)}, EXV_PRINT_TAG(casioContrast)},
{0x000d, "Saturation", N_("Saturation"), N_("Saturation"), casioId, makerTags, unsignedShort, -1, {0x000d, "Saturation", N_("Saturation"), N_("Saturation"), IfdId::casioId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casioSaturation)}, EXV_PRINT_TAG(casioSaturation)},
{0x0014, "ISO", N_("ISO"), N_("ISO"), casioId, makerTags, unsignedShort, -1, printValue}, {0x0014, "ISO", N_("ISO"), N_("ISO"), IfdId::casioId, SectionId::makerTags, unsignedShort, -1, printValue},
{0x0015, "FirmwareDate", N_("Firmware date"), N_("Firmware date"), casioId, makerTags, asciiString, -1, {0x0015, "FirmwareDate", N_("Firmware date"), N_("Firmware date"), IfdId::casioId, SectionId::makerTags,
print0x0015}, asciiString, -1, print0x0015},
{0x0016, "Enhancement", N_("Enhancement"), N_("Enhancement"), casioId, makerTags, unsignedShort, -1, {0x0016, "Enhancement", N_("Enhancement"), N_("Enhancement"), IfdId::casioId, SectionId::makerTags, unsignedShort,
EXV_PRINT_TAG(casioEnhancement)}, -1, EXV_PRINT_TAG(casioEnhancement)},
{0x0017, "ColorFilter", N_("Color Filter"), N_("Color Filter"), casioId, makerTags, unsignedShort, -1, {0x0017, "ColorFilter", N_("Color Filter"), N_("Color Filter"), IfdId::casioId, SectionId::makerTags, unsignedShort,
EXV_PRINT_TAG(casioColorFilter)}, -1, EXV_PRINT_TAG(casioColorFilter)},
{0x0018, "AFPoint", N_("AF Point"), N_("AF Point"), casioId, makerTags, unsignedShort, -1, printValue}, {0x0018, "AFPoint", N_("AF Point"), N_("AF Point"), IfdId::casioId, SectionId::makerTags, unsignedShort, -1,
{0x0019, "FlashIntensity2", N_("Flash Intensity"), N_("Flash Intensity"), casioId, makerTags, unsignedShort, -1, printValue},
EXV_PRINT_TAG(casioFlashIntensity2)}, {0x0019, "FlashIntensity2", N_("Flash Intensity"), N_("Flash Intensity"), IfdId::casioId, SectionId::makerTags,
{0x0020, "CCDSensitivity", N_("CCDSensitivity"), N_("CCDSensitivity"), casioId, makerTags, unsignedShort, -1, unsignedShort, -1, EXV_PRINT_TAG(casioFlashIntensity2)},
EXV_PRINT_TAG(casioCCDSensitivity)}, {0x0020, "CCDSensitivity", N_("CCDSensitivity"), N_("CCDSensitivity"), IfdId::casioId, SectionId::makerTags,
{0x0e00, "PrintIM", N_("Print IM"), N_("PrintIM information"), casioId, makerTags, undefined, -1, printValue}, unsignedShort, -1, EXV_PRINT_TAG(casioCCDSensitivity)},
{0xffff, "(UnknownCasioMakerNoteTag)", "(UnknownCasioMakerNoteTag)", N_("Unknown CasioMakerNote tag"), casioId, {0x0e00, "PrintIM", N_("Print IM"), N_("PrintIM information"), IfdId::casioId, SectionId::makerTags, undefined, -1,
makerTags, asciiString, -1, printValue}, printValue},
{0xffff, "(UnknownCasioMakerNoteTag)", "(UnknownCasioMakerNoteTag)", N_("Unknown CasioMakerNote tag"),
IfdId::casioId, SectionId::makerTags, asciiString, -1, printValue},
}; };
const TagInfo* CasioMakerNote::tagList() { const TagInfo* CasioMakerNote::tagList() {
@ -146,11 +148,10 @@ std::ostream& CasioMakerNote::print0x0015(std::ostream& os, const Value& value,
if (numbers.size() >= 10) { if (numbers.size() >= 10) {
// year // year
long l = (numbers[0] - 48) * 10 + (numbers[1] - 48); long l = (numbers[0] - 48) * 10 + (numbers[1] - 48);
if (l < 70) { if (l < 70)
l += 2000; l += 2000;
} else { else
l += 1900; l += 1900;
};
os << l << ":"; os << l << ":";
// month, day, hour, minutes // month, day, hour, minutes
os << numbers[2] << numbers[3] << ":" << numbers[4] << numbers[5] << " " << numbers[6] << numbers[7] << ":" os << numbers[2] << numbers[3] << ":" << numbers[4] << numbers[5] << " " << numbers[6] << numbers[7] << ":"
@ -158,10 +159,9 @@ std::ostream& CasioMakerNote::print0x0015(std::ostream& os, const Value& value,
// optional seconds // optional seconds
if (numbers.size() == 12) { if (numbers.size() == 12) {
os << ":" << numbers[10] << numbers[11]; os << ":" << numbers[10] << numbers[11];
}; }
} else { } else
os << value; os << value;
};
return os; return os;
} }
@ -273,98 +273,105 @@ constexpr TagDetails casio2VideoQuality[] = {
// Casio2 MakerNote Tag Info // Casio2 MakerNote Tag Info
constexpr TagInfo Casio2MakerNote::tagInfo_[] = { constexpr TagInfo Casio2MakerNote::tagInfo_[] = {
{0x0002, "PreviewImageSize", N_("Preview Image Size"), N_("Preview Image Size"), casio2Id, makerTags, unsignedShort, {0x0002, "PreviewImageSize", N_("Preview Image Size"), N_("Preview Image Size"), IfdId::casio2Id,
-1, printValue}, SectionId::makerTags, unsignedShort, -1, printValue},
{0x0003, "PreviewImageLength", N_("Preview Image Length"), N_("Preview Image Length"), casio2Id, makerTags, {0x0003, "PreviewImageLength", N_("Preview Image Length"), N_("Preview Image Length"), IfdId::casio2Id,
unsignedLong, -1, printValue}, SectionId::makerTags, unsignedLong, -1, printValue},
{0x0004, "PreviewImageStart", N_("Preview Image Start"), N_("Preview Image Start"), casio2Id, makerTags, {0x0004, "PreviewImageStart", N_("Preview Image Start"), N_("Preview Image Start"), IfdId::casio2Id,
unsignedLong, -1, printValue}, SectionId::makerTags, unsignedLong, -1, printValue},
{0x0008, "QualityMode", N_("Quality Mode"), N_("Quality Mode"), casio2Id, makerTags, unsignedShort, -1, {0x0008, "QualityMode", N_("Quality Mode"), N_("Quality Mode"), IfdId::casio2Id, SectionId::makerTags,
EXV_PRINT_TAG(casio2QualityMode)}, unsignedShort, -1, EXV_PRINT_TAG(casio2QualityMode)},
{0x0009, "ImageSize", N_("Image Size"), N_("Image Size"), casio2Id, makerTags, unsignedShort, -1, {0x0009, "ImageSize", N_("Image Size"), N_("Image Size"), IfdId::casio2Id, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2ImageSize)}, EXV_PRINT_TAG(casio2ImageSize)},
{0x000d, "FocusMode", N_("Focus Mode"), N_("Focus Mode"), casio2Id, makerTags, unsignedShort, -1, {0x000d, "FocusMode", N_("Focus Mode"), N_("Focus Mode"), IfdId::casio2Id, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2FocusMode)}, EXV_PRINT_TAG(casio2FocusMode)},
{0x0014, "ISOSpeed", N_("ISO Speed"), N_("ISO Speed"), casio2Id, makerTags, unsignedShort, -1, {0x0014, "ISOSpeed", N_("ISO Speed"), N_("ISO Speed"), IfdId::casio2Id, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2IsoSpeed)}, EXV_PRINT_TAG(casio2IsoSpeed)},
{0x0019, "WhiteBalance", N_("White Balance"), N_("White Balance Setting"), casio2Id, makerTags, unsignedShort, -1, {0x0019, "WhiteBalance", N_("White Balance"), N_("White Balance Setting"), IfdId::casio2Id, SectionId::makerTags,
EXV_PRINT_TAG(casio2WhiteBalance)}, unsignedShort, -1, EXV_PRINT_TAG(casio2WhiteBalance)},
{0x001d, "FocalLength", N_("Focal Length"), N_("Focal Length"), casio2Id, makerTags, unsignedRational, -1, {0x001d, "FocalLength", N_("Focal Length"), N_("Focal Length"), IfdId::casio2Id, SectionId::makerTags,
printValue}, unsignedRational, -1, printValue},
{0x001f, "Saturation", N_("Saturation"), N_("Saturation"), casio2Id, makerTags, unsignedShort, -1, {0x001f, "Saturation", N_("Saturation"), N_("Saturation"), IfdId::casio2Id, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2Saturation)}, EXV_PRINT_TAG(casio2Saturation)},
{0x0020, "Contrast", N_("Contrast"), N_("Contrast"), casio2Id, makerTags, unsignedShort, -1, {0x0020, "Contrast", N_("Contrast"), N_("Contrast"), IfdId::casio2Id, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2Contrast)}, EXV_PRINT_TAG(casio2Contrast)},
{0x0021, "Sharpness", N_("Sharpness"), N_("Sharpness"), casio2Id, makerTags, unsignedShort, -1, {0x0021, "Sharpness", N_("Sharpness"), N_("Sharpness"), IfdId::casio2Id, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2Sharpness)}, EXV_PRINT_TAG(casio2Sharpness)},
{0x0e00, "PrintIM", N_("Print IM"), N_("PrintIM information"), casio2Id, makerTags, undefined, -1, printValue}, {0x0e00, "PrintIM", N_("Print IM"), N_("PrintIM information"), IfdId::casio2Id, SectionId::makerTags, undefined, -1,
{0x2000, "PreviewImage", N_("Preview Image"), N_("Preview Image"), casio2Id, makerTags, undefined, -1, printValue}, printValue},
{0x2001, "FirmwareDate", N_("Firmware Date"), N_("Firmware Date"), casio2Id, makerTags, asciiString, -1, {0x2000, "PreviewImage", N_("Preview Image"), N_("Preview Image"), IfdId::casio2Id, SectionId::makerTags, undefined,
print0x2001},
{0x2011, "WhiteBalanceBias", N_("White Balance Bias"), N_("White Balance Bias"), casio2Id, makerTags, unsignedShort,
-1, printValue},
{0x2012, "WhiteBalance2", N_("White Balance"), N_("White Balance Setting"), casio2Id, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2WhiteBalance2)},
{0x2021, "AFPointPosition", N_("AF Point Position"), N_("AF Point Position"), casio2Id, makerTags, unsignedShort,
-1, printValue}, -1, printValue},
{0x2022, "ObjectDistance", N_("Object Distance"), N_("Object Distance"), casio2Id, makerTags, unsignedLong, -1, {0x2001, "FirmwareDate", N_("Firmware Date"), N_("Firmware Date"), IfdId::casio2Id, SectionId::makerTags,
print0x2022}, asciiString, -1, print0x2001},
{0x2034, "FlashDistance", N_("Flash Distance"), N_("Flash Distance"), casio2Id, makerTags, unsignedShort, -1, {0x2011, "WhiteBalanceBias", N_("White Balance Bias"), N_("White Balance Bias"), IfdId::casio2Id,
SectionId::makerTags, unsignedShort, -1, printValue},
{0x2012, "WhiteBalance2", N_("White Balance"), N_("White Balance Setting"), IfdId::casio2Id, SectionId::makerTags,
unsignedShort, -1, EXV_PRINT_TAG(casio2WhiteBalance2)},
{0x2021, "AFPointPosition", N_("AF Point Position"), N_("AF Point Position"), IfdId::casio2Id, SectionId::makerTags,
unsignedShort, -1, printValue},
{0x2022, "ObjectDistance", N_("Object Distance"), N_("Object Distance"), IfdId::casio2Id, SectionId::makerTags,
unsignedLong, -1, print0x2022},
{0x2034, "FlashDistance", N_("Flash Distance"), N_("Flash Distance"), IfdId::casio2Id, SectionId::makerTags,
unsignedShort, -1, printValue},
{0x2076, "SpecialEffectMode", N_("Special Effect Mode"), N_("Special Effect Mode"), IfdId::casio2Id,
SectionId::makerTags, unsignedByte, -1, printValue},
{0x2089, "FaceInfo", N_("Face Info"), N_("Face Info"), IfdId::casio2Id, SectionId::makerTags, undefined, -1,
printValue}, printValue},
{0x2076, "SpecialEffectMode", N_("Special Effect Mode"), N_("Special Effect Mode"), casio2Id, makerTags, {0x211c, "FacesDetected", N_("Faces detected"), N_("Faces detected"), IfdId::casio2Id, SectionId::makerTags,
unsignedByte, -1, printValue}, unsignedByte, -1, printValue},
{0x2089, "FaceInfo", N_("Face Info"), N_("Face Info"), casio2Id, makerTags, undefined, -1, printValue}, {0x3000, "RecordMode", N_("Record Mode"), N_("Record Mode"), IfdId::casio2Id, SectionId::makerTags, unsignedShort,
{0x211c, "FacesDetected", N_("Faces detected"), N_("Faces detected"), casio2Id, makerTags, unsignedByte, -1, -1, printValue},
printValue}, {0x3001, "ReleaseMode", N_("Release Mode"), N_("Release Mode"), IfdId::casio2Id, SectionId::makerTags,
{0x3000, "RecordMode", N_("Record Mode"), N_("Record Mode"), casio2Id, makerTags, unsignedShort, -1, printValue}, unsignedShort, -1, EXV_PRINT_TAG(casio2ReleaseMode)},
{0x3001, "ReleaseMode", N_("Release Mode"), N_("Release Mode"), casio2Id, makerTags, unsignedShort, -1, {0x3002, "Quality", N_("Quality"), N_("Quality"), IfdId::casio2Id, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2ReleaseMode)},
{0x3002, "Quality", N_("Quality"), N_("Quality"), casio2Id, makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2Quality)}, EXV_PRINT_TAG(casio2Quality)},
{0x3003, "FocusMode2", N_("Focus Mode2"), N_("Focus Mode2"), casio2Id, makerTags, unsignedShort, -1, {0x3003, "FocusMode2", N_("Focus Mode2"), N_("Focus Mode2"), IfdId::casio2Id, SectionId::makerTags, unsignedShort,
EXV_PRINT_TAG(casio2FocusMode2)}, -1, EXV_PRINT_TAG(casio2FocusMode2)},
{0x3006, "HometownCity", N_("Home town city"), N_("Home town city"), casio2Id, makerTags, asciiString, -1, {0x3006, "HometownCity", N_("Home town city"), N_("Home town city"), IfdId::casio2Id, SectionId::makerTags,
printValue}, asciiString, -1, printValue},
{0x3007, "BestShotMode", N_("Best Shot Mode"), N_("Best Shot Mode"), casio2Id, makerTags, unsignedShort, -1, {0x3007, "BestShotMode", N_("Best Shot Mode"), N_("Best Shot Mode"), IfdId::casio2Id, SectionId::makerTags,
printValue}, unsignedShort, -1, printValue},
{0x3008, "AutoISO", N_("Auto ISO"), N_("Auto ISO"), casio2Id, makerTags, unsignedShort, -1, {0x3008, "AutoISO", N_("Auto ISO"), N_("Auto ISO"), IfdId::casio2Id, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2AutoISO)}, EXV_PRINT_TAG(casio2AutoISO)},
{0x3009, "AFMode", N_("AF Mode"), N_("AF Mode"), casio2Id, makerTags, unsignedShort, -1, {0x3009, "AFMode", N_("AF Mode"), N_("AF Mode"), IfdId::casio2Id, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2AFMode)}, EXV_PRINT_TAG(casio2AFMode)},
{0x3011, "Sharpness2", N_("Sharpness"), N_("Sharpness"), casio2Id, makerTags, undefined, -1, printValue}, {0x3011, "Sharpness2", N_("Sharpness"), N_("Sharpness"), IfdId::casio2Id, SectionId::makerTags, undefined, -1,
{0x3012, "Contrast2", N_("Contrast"), N_("Contrast"), casio2Id, makerTags, undefined, -1, printValue}, printValue},
{0x3013, "Saturation2", N_("Saturation"), N_("Saturation"), casio2Id, makerTags, undefined, -1, printValue}, {0x3012, "Contrast2", N_("Contrast"), N_("Contrast"), IfdId::casio2Id, SectionId::makerTags, undefined, -1,
{0x3014, "ISO", N_("ISO"), N_("ISO"), casio2Id, makerTags, unsignedShort, -1, printValue}, printValue},
{0x3015, "ColorMode", N_("Color Mode"), N_("Color Mode"), casio2Id, makerTags, unsignedShort, -1, {0x3013, "Saturation2", N_("Saturation"), N_("Saturation"), IfdId::casio2Id, SectionId::makerTags, undefined, -1,
printValue},
{0x3014, "ISO", N_("ISO"), N_("ISO"), IfdId::casio2Id, SectionId::makerTags, unsignedShort, -1, printValue},
{0x3015, "ColorMode", N_("Color Mode"), N_("Color Mode"), IfdId::casio2Id, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2ColorMode)}, EXV_PRINT_TAG(casio2ColorMode)},
{0x3016, "Enhancement", N_("Enhancement"), N_("Enhancement"), casio2Id, makerTags, unsignedShort, -1, {0x3016, "Enhancement", N_("Enhancement"), N_("Enhancement"), IfdId::casio2Id, SectionId::makerTags, unsignedShort,
EXV_PRINT_TAG(casio2Enhancement)}, -1, EXV_PRINT_TAG(casio2Enhancement)},
{0x3017, "ColorFilter", N_("Color Filter"), N_("Color Filter"), casio2Id, makerTags, unsignedShort, -1, {0x3017, "ColorFilter", N_("Color Filter"), N_("Color Filter"), IfdId::casio2Id, SectionId::makerTags,
EXV_PRINT_TAG(casio2ColorFilter)}, unsignedShort, -1, EXV_PRINT_TAG(casio2ColorFilter)},
{0x301b, "ArtMode", N_("Art Mode"), N_("Art Mode"), casio2Id, makerTags, unsignedShort, -1, {0x301b, "ArtMode", N_("Art Mode"), N_("Art Mode"), IfdId::casio2Id, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2ArtMode)}, EXV_PRINT_TAG(casio2ArtMode)},
{0x301c, "SequenceNumber", N_("Sequence Number"), N_("Sequence Number"), casio2Id, makerTags, unsignedShort, -1, {0x301c, "SequenceNumber", N_("Sequence Number"), N_("Sequence Number"), IfdId::casio2Id, SectionId::makerTags,
printValue},
{0x3020, "ImageStabilization", N_("Image Stabilization"), N_("Image Stabilization"), casio2Id, makerTags,
unsignedShort, -1, printValue}, unsignedShort, -1, printValue},
{0x302a, "LightingMode", N_("Lighting Mode"), N_("Lighting Mode"), casio2Id, makerTags, unsignedShort, -1, {0x3020, "ImageStabilization", N_("Image Stabilization"), N_("Image Stabilization"), IfdId::casio2Id,
EXV_PRINT_TAG(casio2LightingMode)}, SectionId::makerTags, unsignedShort, -1, printValue},
{0x302b, "PortraitRefiner", N_("Portrait Refiner"), N_("Portrait Refiner settings"), casio2Id, makerTags, {0x302a, "LightingMode", N_("Lighting Mode"), N_("Lighting Mode"), IfdId::casio2Id, SectionId::makerTags,
unsignedShort, -1, EXV_PRINT_TAG(casio2PortraitRefiner)}, unsignedShort, -1, EXV_PRINT_TAG(casio2LightingMode)},
{0x3030, "SpecialEffectLevel", N_("Special Effect Level"), N_("Special Effect Level"), casio2Id, makerTags, {0x302b, "PortraitRefiner", N_("Portrait Refiner"), N_("Portrait Refiner settings"), IfdId::casio2Id,
unsignedShort, -1, printValue}, SectionId::makerTags, unsignedShort, -1, EXV_PRINT_TAG(casio2PortraitRefiner)},
{0x3031, "SpecialEffectSetting", N_("Special Effect Setting"), N_("Special Effect Setting"), casio2Id, makerTags, {0x3030, "SpecialEffectLevel", N_("Special Effect Level"), N_("Special Effect Level"), IfdId::casio2Id,
unsignedShort, -1, EXV_PRINT_TAG(casio2SpecialEffectSetting)}, SectionId::makerTags, unsignedShort, -1, printValue},
{0x3103, "DriveMode", N_("Drive Mode"), N_("Drive Mode"), casio2Id, makerTags, unsignedShort, -1, {0x3031, "SpecialEffectSetting", N_("Special Effect Setting"), N_("Special Effect Setting"), IfdId::casio2Id,
SectionId::makerTags, unsignedShort, -1, EXV_PRINT_TAG(casio2SpecialEffectSetting)},
{0x3103, "DriveMode", N_("Drive Mode"), N_("Drive Mode"), IfdId::casio2Id, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(casio2DriveMode)}, EXV_PRINT_TAG(casio2DriveMode)},
{0x310b, "ArtModeParameters", N_("Art Mode Parameters"), N_("Art Mode Parameters"), casio2Id, makerTags, undefined, {0x310b, "ArtModeParameters", N_("Art Mode Parameters"), N_("Art Mode Parameters"), IfdId::casio2Id,
-1, printValue}, SectionId::makerTags, undefined, -1, printValue},
{0x4001, "CaptureFrameRate", N_("Capture Frame Rate"), N_("Capture Frame Rate"), casio2Id, makerTags, unsignedShort, {0x4001, "CaptureFrameRate", N_("Capture Frame Rate"), N_("Capture Frame Rate"), IfdId::casio2Id,
-1, printValue}, SectionId::makerTags, unsignedShort, -1, printValue},
{0x4003, "VideoQuality", N_("Video Quality"), N_("Video Quality"), casio2Id, makerTags, unsignedShort, -1, {0x4003, "VideoQuality", N_("Video Quality"), N_("Video Quality"), IfdId::casio2Id, SectionId::makerTags,
EXV_PRINT_TAG(casio2VideoQuality)}, unsignedShort, -1, EXV_PRINT_TAG(casio2VideoQuality)},
{0xffff, "(UnknownCasio2MakerNoteTag)", "(UnknownCasio2MakerNoteTag)", N_("Unknown Casio2MakerNote tag"), casio2Id, {0xffff, "(UnknownCasio2MakerNoteTag)", "(UnknownCasio2MakerNoteTag)", N_("Unknown Casio2MakerNote tag"),
makerTags, asciiString, -1, printValue}, IfdId::casio2Id, SectionId::makerTags, asciiString, -1, printValue},
}; };
const TagInfo* Casio2MakerNote::tagList() { const TagInfo* Casio2MakerNote::tagList() {
@ -384,18 +391,16 @@ std::ostream& Casio2MakerNote::print0x2001(std::ostream& os, const Value& value,
if (numbers.size() >= 10) { if (numbers.size() >= 10) {
// year // year
long l = (numbers[0] - 48) * 10 + (numbers[1] - 48); long l = (numbers[0] - 48) * 10 + (numbers[1] - 48);
if (l < 70) { if (l < 70)
l += 2000; l += 2000;
} else { else
l += 1900; l += 1900;
};
os << l << ":"; os << l << ":";
// month, day, hour, minutes // month, day, hour, minutes
os << numbers[2] << numbers[3] << ":" << numbers[4] << numbers[5] << " " << numbers[6] << numbers[7] << ":" os << numbers[2] << numbers[3] << ":" << numbers[4] << numbers[5] << " " << numbers[6] << numbers[7] << ":"
<< numbers[8] << numbers[9]; << numbers[8] << numbers[9];
} else { } else
os << value; os << value;
};
return os; return os;
} }
@ -405,7 +410,7 @@ std::ostream& Casio2MakerNote::print0x2022(std::ostream& os, const Value& value,
os << N_("Inf"); os << N_("Inf");
os.flags(f); os.flags(f);
return os; return os;
}; }
std::ostringstream oss; std::ostringstream oss;
oss.copyfmt(os); oss.copyfmt(os);
os << std::fixed << std::setprecision(2) << value.toInt64() / 1000.0 << _(" m"); os << std::fixed << std::setprecision(2) << value.toInt64() / 1000.0 << _(" m");

@ -782,7 +782,7 @@ void Converter::cnvExifFlash(const char* from, const char* to) {
return; return;
if (!prepareXmpTarget(to)) if (!prepareXmpTarget(to))
return; return;
auto value = pos->toInt64(); auto value = pos->toUint32();
if (!pos->value().ok()) { if (!pos->value().ok()) {
#ifndef SUPPRESS_WARNINGS #ifndef SUPPRESS_WARNINGS
EXV_WARNING << "Failed to convert " << from << " to " << to << "\n"; EXV_WARNING << "Failed to convert " << from << " to " << to << "\n";
@ -1052,7 +1052,7 @@ void Converter::cnvXmpFlash(const char* from, const char* to) {
unsigned short value = 0; unsigned short value = 0;
if (pos != xmpData_->end() && pos->count() > 0) { if (pos != xmpData_->end() && pos->count() > 0) {
auto fired = pos->toInt64(); auto fired = pos->toUint32();
if (pos->value().ok()) if (pos->value().ok())
value |= fired & 1; value |= fired & 1;
#ifndef SUPPRESS_WARNINGS #ifndef SUPPRESS_WARNINGS
@ -1063,7 +1063,7 @@ void Converter::cnvXmpFlash(const char* from, const char* to) {
} }
pos = xmpData_->findKey(XmpKey(std::string(from) + "/exif:Return")); pos = xmpData_->findKey(XmpKey(std::string(from) + "/exif:Return"));
if (pos != xmpData_->end() && pos->count() > 0) { if (pos != xmpData_->end() && pos->count() > 0) {
auto ret = pos->toInt64(); auto ret = pos->toUint32();
if (pos->value().ok()) if (pos->value().ok())
value |= (ret & 3) << 1; value |= (ret & 3) << 1;
#ifndef SUPPRESS_WARNINGS #ifndef SUPPRESS_WARNINGS
@ -1074,7 +1074,7 @@ void Converter::cnvXmpFlash(const char* from, const char* to) {
} }
pos = xmpData_->findKey(XmpKey(std::string(from) + "/exif:Mode")); pos = xmpData_->findKey(XmpKey(std::string(from) + "/exif:Mode"));
if (pos != xmpData_->end() && pos->count() > 0) { if (pos != xmpData_->end() && pos->count() > 0) {
auto mode = pos->toInt64(); auto mode = pos->toUint32();
if (pos->value().ok()) if (pos->value().ok())
value |= (mode & 3) << 3; value |= (mode & 3) << 3;
#ifndef SUPPRESS_WARNINGS #ifndef SUPPRESS_WARNINGS
@ -1085,7 +1085,7 @@ void Converter::cnvXmpFlash(const char* from, const char* to) {
} }
pos = xmpData_->findKey(XmpKey(std::string(from) + "/exif:Function")); pos = xmpData_->findKey(XmpKey(std::string(from) + "/exif:Function"));
if (pos != xmpData_->end() && pos->count() > 0) { if (pos != xmpData_->end() && pos->count() > 0) {
auto function = pos->toInt64(); auto function = pos->toUint32();
if (pos->value().ok()) if (pos->value().ok())
value |= (function & 1) << 5; value |= (function & 1) << 5;
#ifndef SUPPRESS_WARNINGS #ifndef SUPPRESS_WARNINGS
@ -1097,7 +1097,7 @@ void Converter::cnvXmpFlash(const char* from, const char* to) {
pos = xmpData_->findKey(XmpKey(std::string(from) + "/exif:RedEyeMode")); pos = xmpData_->findKey(XmpKey(std::string(from) + "/exif:RedEyeMode"));
if (pos != xmpData_->end()) { if (pos != xmpData_->end()) {
if (pos->count() > 0) { if (pos->count() > 0) {
auto red = pos->toInt64(); auto red = pos->toUint32();
if (pos->value().ok()) if (pos->value().ok())
value |= (red & 1) << 6; value |= (red & 1) << 6;
#ifndef SUPPRESS_WARNINGS #ifndef SUPPRESS_WARNINGS
@ -1284,7 +1284,7 @@ std::string Converter::computeExifDigest(bool tiff) {
} }
#else #else
std::string Converter::computeExifDigest(bool) { std::string Converter::computeExifDigest(bool) {
return std::string(""); return {};
} }
#endif #endif
@ -1584,7 +1584,7 @@ bool convertStringCharsetIconv(std::string& str, const char* from, const char* t
size_t outbytesleft = sizeof(outbuf); size_t outbytesleft = sizeof(outbuf);
size_t rc = iconv(cd, &inptr, &inbytesleft, &outptr, &outbytesleft); size_t rc = iconv(cd, &inptr, &inbytesleft, &outptr, &outbytesleft);
const size_t outbytesProduced = sizeof(outbuf) - outbytesleft; const size_t outbytesProduced = sizeof(outbuf) - outbytesleft;
if (rc == size_t(-1) && errno != E2BIG) { if (rc == static_cast<size_t>(-1) && errno != E2BIG) {
#ifndef SUPPRESS_WARNINGS #ifndef SUPPRESS_WARNINGS
EXV_WARNING << "iconv: " << strError() << " inbytesleft = " << inbytesleft << "\n"; EXV_WARNING << "iconv: " << strError() << " inbytesleft = " << inbytesleft << "\n";
#endif #endif

@ -52,7 +52,7 @@ DataBuf Cr2Header::write() const {
bool Cr2Header::isImageTag(uint16_t tag, IfdId group, const PrimaryGroups* /*pPrimaryGroups*/) const { bool Cr2Header::isImageTag(uint16_t tag, IfdId group, const PrimaryGroups* /*pPrimaryGroups*/) const {
// CR2 image tags are all IFD2 and IFD3 tags // CR2 image tags are all IFD2 and IFD3 tags
if (group == ifd2Id || group == ifd3Id) if (group == IfdId::ifd2Id || group == IfdId::ifd3Id)
return true; return true;
// ...and any (IFD0) tag that is in the TIFF image tags list // ...and any (IFD0) tag that is in the TIFF image tags list
return isTiffImageTag(tag, group); return isTiffImageTag(tag, group);

@ -49,7 +49,7 @@ void Cr2Image::printStructure(std::ostream& out, Exiv2::PrintStructureOption opt
printTiffStructure(io(), out, option, depth - 1); printTiffStructure(io(), out, option, depth - 1);
} }
void Cr2Image::setComment(std::string_view /*comment*/) { void Cr2Image::setComment(const std::string&) {
// not supported // not supported
throw(Error(ErrorCode::kerInvalidSettingForImage, "Image comment", "CR2")); throw(Error(ErrorCode::kerInvalidSettingForImage, "Image comment", "CR2"));
} }
@ -81,9 +81,8 @@ void Cr2Image::writeMetadata() {
byte* pData = nullptr; byte* pData = nullptr;
size_t size = 0; size_t size = 0;
IoCloser closer(*io_); IoCloser closer(*io_);
if (io_->open() == 0) {
// Ensure that this is the correct image type // Ensure that this is the correct image type
if (isCr2Type(*io_, false)) { if (io_->open() == 0 && isCr2Type(*io_, false)) {
pData = io_->mmap(true); pData = io_->mmap(true);
size = io_->size(); size = io_->size();
Internal::Cr2Header cr2Header; Internal::Cr2Header cr2Header;
@ -91,7 +90,6 @@ void Cr2Image::writeMetadata() {
bo = cr2Header.byteOrder(); bo = cr2Header.byteOrder();
} }
} }
}
if (bo == invalidByteOrder) { if (bo == invalidByteOrder) {
bo = littleEndian; bo = littleEndian;
} }
@ -112,7 +110,7 @@ WriteMethod Cr2Parser::encode(BasicIo& io, const byte* pData, size_t size, ByteO
// Delete IFDs which do not occur in TIFF images // Delete IFDs which do not occur in TIFF images
static constexpr auto filteredIfds = std::array{ static constexpr auto filteredIfds = std::array{
Internal::panaRawId, IfdId::panaRawId,
}; };
for (auto&& filteredIfd : filteredIfds) { for (auto&& filteredIfd : filteredIfds) {
#ifdef EXIV2_DEBUG_MESSAGES #ifdef EXIV2_DEBUG_MESSAGES

@ -93,7 +93,7 @@ void CrwImage::writeMetadata() {
// Write new buffer to file // Write new buffer to file
MemIo tempIo; MemIo tempIo;
tempIo.write((!blob.empty() ? &blob[0] : nullptr), blob.size()); tempIo.write((!blob.empty() ? blob.data() : nullptr), blob.size());
io_->close(); io_->close();
io_->transfer(tempIo); // may throw io_->transfer(tempIo); // may throw
@ -108,7 +108,7 @@ void CrwParser::decode(CrwImage* pCrwImage, const byte* pData, size_t size) {
// a hack to get absolute offset of preview image inside CRW structure // a hack to get absolute offset of preview image inside CRW structure
auto preview = header.findComponent(0x2007, 0x0000); auto preview = header.findComponent(0x2007, 0x0000);
if (preview) { if (preview) {
(pCrwImage->exifData())["Exif.Image2.JPEGInterchangeFormat"] = uint32_t(preview->pData() - pData); (pCrwImage->exifData())["Exif.Image2.JPEGInterchangeFormat"] = static_cast<uint32_t>(preview->pData() - pData);
(pCrwImage->exifData())["Exif.Image2.JPEGInterchangeFormatLength"] = static_cast<uint32_t>(preview->size()); (pCrwImage->exifData())["Exif.Image2.JPEGInterchangeFormatLength"] = static_cast<uint32_t>(preview->size());
} }
} // CrwParser::decode } // CrwParser::decode

@ -78,31 +78,31 @@ namespace Exiv2::Internal {
const CrwMapping CrwMap::crwMapping_[] = { const CrwMapping CrwMap::crwMapping_[] = {
// CrwTag CrwDir Size ExifTag IfdId decodeFct encodeFct // CrwTag CrwDir Size ExifTag IfdId decodeFct encodeFct
// ------ ------ ---- ------- ----- --------- --------- // ------ ------ ---- ------- ----- --------- ---------
CrwMapping(0x0805, 0x300a, 0, 0, canonId, decode0x0805, encode0x0805), CrwMapping(0x0805, 0x300a, 0, 0, IfdId::canonId, decode0x0805, encode0x0805),
CrwMapping(0x080a, 0x2807, 0, 0, canonId, decode0x080a, encode0x080a), CrwMapping(0x080a, 0x2807, 0, 0, IfdId::canonId, decode0x080a, encode0x080a),
CrwMapping(0x080b, 0x3004, 0, 0x0007, canonId, decodeBasic, encodeBasic), CrwMapping(0x080b, 0x3004, 0, 0x0007, IfdId::canonId, decodeBasic, encodeBasic),
CrwMapping(0x0810, 0x2807, 0, 0x0009, canonId, decodeBasic, encodeBasic), CrwMapping(0x0810, 0x2807, 0, 0x0009, IfdId::canonId, decodeBasic, encodeBasic),
CrwMapping(0x0815, 0x2804, 0, 0x0006, canonId, decodeBasic, encodeBasic), CrwMapping(0x0815, 0x2804, 0, 0x0006, IfdId::canonId, decodeBasic, encodeBasic),
CrwMapping(0x1029, 0x300b, 0, 0x0002, canonId, decodeBasic, encodeBasic), CrwMapping(0x1029, 0x300b, 0, 0x0002, IfdId::canonId, decodeBasic, encodeBasic),
CrwMapping(0x102a, 0x300b, 0, 0x0004, canonId, decodeArray, encodeArray), CrwMapping(0x102a, 0x300b, 0, 0x0004, IfdId::canonId, decodeArray, encodeArray),
CrwMapping(0x102d, 0x300b, 0, 0x0001, canonId, decodeArray, encodeArray), CrwMapping(0x102d, 0x300b, 0, 0x0001, IfdId::canonId, decodeArray, encodeArray),
CrwMapping(0x1033, 0x300b, 0, 0x000f, canonId, decodeArray, encodeArray), CrwMapping(0x1033, 0x300b, 0, 0x000f, IfdId::canonId, decodeArray, encodeArray),
CrwMapping(0x1038, 0x300b, 0, 0x0012, canonId, decodeArray, encodeArray), CrwMapping(0x1038, 0x300b, 0, 0x0012, IfdId::canonId, decodeArray, encodeArray),
CrwMapping(0x10a9, 0x300b, 0, 0x00a9, canonId, decodeBasic, encodeBasic), CrwMapping(0x10a9, 0x300b, 0, 0x00a9, IfdId::canonId, decodeBasic, encodeBasic),
// Mapped to Exif.Photo.ColorSpace instead (see below) // Mapped to Exif.Photo.ColorSpace instead (see below)
// CrwMapping(0x10b4, 0x300b, 0, 0x00b4, canonId, decodeBasic, encodeBasic), // CrwMapping(0x10b4, 0x300b, 0, 0x00b4, IfdId::canonId, decodeBasic, encodeBasic),
CrwMapping(0x10b4, 0x300b, 0, 0xa001, exifId, decodeBasic, encodeBasic), CrwMapping(0x10b4, 0x300b, 0, 0xa001, IfdId::exifId, decodeBasic, encodeBasic),
CrwMapping(0x10b5, 0x300b, 0, 0x00b5, canonId, decodeBasic, encodeBasic), CrwMapping(0x10b5, 0x300b, 0, 0x00b5, IfdId::canonId, decodeBasic, encodeBasic),
CrwMapping(0x10c0, 0x300b, 0, 0x00c0, canonId, decodeBasic, encodeBasic), CrwMapping(0x10c0, 0x300b, 0, 0x00c0, IfdId::canonId, decodeBasic, encodeBasic),
CrwMapping(0x10c1, 0x300b, 0, 0x00c1, canonId, decodeBasic, encodeBasic), CrwMapping(0x10c1, 0x300b, 0, 0x00c1, IfdId::canonId, decodeBasic, encodeBasic),
CrwMapping(0x1807, 0x3002, 0, 0x9206, exifId, decodeBasic, encodeBasic), CrwMapping(0x1807, 0x3002, 0, 0x9206, IfdId::exifId, decodeBasic, encodeBasic),
CrwMapping(0x180b, 0x3004, 0, 0x000c, canonId, decodeBasic, encodeBasic), CrwMapping(0x180b, 0x3004, 0, 0x000c, IfdId::canonId, decodeBasic, encodeBasic),
CrwMapping(0x180e, 0x300a, 0, 0x9003, exifId, decode0x180e, encode0x180e), CrwMapping(0x180e, 0x300a, 0, 0x9003, IfdId::exifId, decode0x180e, encode0x180e),
CrwMapping(0x1810, 0x300a, 0, 0xa002, exifId, decode0x1810, encode0x1810), CrwMapping(0x1810, 0x300a, 0, 0xa002, IfdId::exifId, decode0x1810, encode0x1810),
CrwMapping(0x1817, 0x300a, 4, 0x0008, canonId, decodeBasic, encodeBasic), CrwMapping(0x1817, 0x300a, 4, 0x0008, IfdId::canonId, decodeBasic, encodeBasic),
// CrwMapping(0x1818, 0x3002, 0, 0x9204, exifId, decodeBasic, encodeBasic), // CrwMapping(0x1818, 0x3002, 0, 0x9204, IfdId::exifId, decodeBasic, encodeBasic),
CrwMapping(0x183b, 0x300b, 0, 0x0015, canonId, decodeBasic, encodeBasic), CrwMapping(0x183b, 0x300b, 0, 0x0015, IfdId::canonId, decodeBasic, encodeBasic),
CrwMapping(0x2008, 0x0000, 0, 0, ifd1Id, decode0x2008, encode0x2008), CrwMapping(0x2008, 0x0000, 0, 0, IfdId::ifd1Id, decode0x2008, encode0x2008),
}; // CrwMap::crwMapping_[] }; // CrwMap::crwMapping_[]
/* /*
@ -246,15 +246,11 @@ void CiffDirectory::readDirectory(const byte* pData, size_t size, ByteOrder byte
for (uint16_t i = 0; i < count; ++i) { for (uint16_t i = 0; i < count; ++i) {
uint16_t tag = getUShort(pData + o, byteOrder); uint16_t tag = getUShort(pData + o, byteOrder);
std::unique_ptr<CiffComponent> m; auto m = [this, tag]() -> std::unique_ptr<CiffComponent> {
switch (CiffComponent::typeId(tag)) { if (this->typeId(tag) == TypeId::directory)
case directory: return std::make_unique<CiffDirectory>();
m = std::make_unique<CiffDirectory>(); return std::make_unique<CiffEntry>();
break; }();
default:
m = std::make_unique<CiffEntry>();
break;
}
m->setDir(this->tag()); m->setDir(this->tag());
m->read(pData, size, o, byteOrder); m->read(pData, size, o, byteOrder);
add(std::move(m)); add(std::move(m));
@ -550,18 +546,16 @@ CiffComponent* CiffDirectory::doAdd(CrwDirs& crwDirs, uint16_t crwTagId) {
set value set value
*/ */
if (!crwDirs.empty()) { if (!crwDirs.empty()) {
auto [dir, parent] = crwDirs.top(); auto dir = crwDirs.top();
crwDirs.pop(); crwDirs.pop();
// Find the directory // Find the directory
for (auto&& component : components_) { auto it =
if (component->tag() == dir) { std::find_if(components_.begin(), components_.end(), [=](const auto& c) { return c->tag() == dir.first; });
cc_ = component; if (it != components_.end())
break; cc_ = *it;
}
}
if (!cc_) { if (!cc_) {
// Directory doesn't exist yet, add it // Directory doesn't exist yet, add it
m_ = std::make_unique<CiffDirectory>(dir, parent); m_ = std::make_unique<CiffDirectory>(dir.first, dir.second);
cc_ = m_.get(); cc_ = m_.get();
add(std::move(m_)); add(std::move(m_));
} }
@ -569,12 +563,10 @@ CiffComponent* CiffDirectory::doAdd(CrwDirs& crwDirs, uint16_t crwTagId) {
cc_ = cc_->add(crwDirs, crwTagId); cc_ = cc_->add(crwDirs, crwTagId);
} else { } else {
// Find the tag // Find the tag
for (auto&& component : components_) { auto it =
if (component->tagId() == crwTagId) { std::find_if(components_.begin(), components_.end(), [=](const auto& c) { return c->tagId() == crwTagId; });
cc_ = component; if (it != components_.end())
break; cc_ = *it;
}
}
if (!cc_) { if (!cc_) {
// Tag doesn't exist yet, add it // Tag doesn't exist yet, add it
m_ = std::make_unique<CiffEntry>(crwTagId, tag()); m_ = std::make_unique<CiffEntry>(crwTagId, tag());
@ -604,27 +596,23 @@ void CiffComponent::doRemove(CrwDirs& /*crwDirs*/, uint16_t /*crwTagId*/) {
void CiffDirectory::doRemove(CrwDirs& crwDirs, uint16_t crwTagId) { void CiffDirectory::doRemove(CrwDirs& crwDirs, uint16_t crwTagId) {
if (!crwDirs.empty()) { if (!crwDirs.empty()) {
auto [dir, _] = crwDirs.top(); auto dir = crwDirs.top();
crwDirs.pop(); crwDirs.pop();
// Find the directory // Find the directory
for (auto i = components_.begin(); i != components_.end(); ++i) { auto it =
if ((*i)->tag() == dir) { std::find_if(components_.begin(), components_.end(), [=](const auto& c) { return c->tag() == dir.first; });
if (it != components_.end()) {
// Recursive call to next lower level directory // Recursive call to next lower level directory
(*i)->remove(crwDirs, crwTagId); (*it)->remove(crwDirs, crwTagId);
if ((*i)->empty()) if ((*it)->empty())
components_.erase(i); components_.erase(it);
break;
}
} }
} else { } else {
// Find the tag // Find the tag
for (auto i = components_.begin(); i != components_.end(); ++i) { auto it = std::find_if(components_.begin(), components_.end(), [=](const auto& c) { return c->tag() == crwTagId; });
if ((*i)->tagId() == crwTagId) { if (it != components_.end()) {
// Remove the entry and abort the loop delete *it;
delete *i; components_.erase(it);
components_.erase(i);
break;
}
} }
} }
} // CiffDirectory::doRemove } // CiffDirectory::doRemove
@ -698,19 +686,19 @@ void CrwMap::decodeArray(const CiffComponent& ciffComponent, const CrwMapping* p
int64_t aperture = 0; int64_t aperture = 0;
int64_t shutterSpeed = 0; int64_t shutterSpeed = 0;
IfdId ifdId = ifdIdNotSet; IfdId ifdId = IfdId::ifdIdNotSet;
switch (pCrwMapping->tag_) { switch (pCrwMapping->tag_) {
case 0x0001: case 0x0001:
ifdId = canonCsId; ifdId = IfdId::canonCsId;
break; break;
case 0x0004: case 0x0004:
ifdId = canonSiId; ifdId = IfdId::canonSiId;
break; break;
case 0x000f: case 0x000f:
ifdId = canonCfId; ifdId = IfdId::canonCfId;
break; break;
case 0x0012: case 0x0012:
ifdId = canonPiId; ifdId = IfdId::canonPiId;
break; break;
} }
@ -725,18 +713,18 @@ void CrwMap::decodeArray(const CiffComponent& ciffComponent, const CrwMapping* p
uint16_t n = 1; uint16_t n = 1;
ExifKey key(c, groupName); ExifKey key(c, groupName);
UShortValue value; UShortValue value;
if (ifdId == canonCsId && c == 23 && component_size >= 52) if (ifdId == IfdId::canonCsId && c == 23 && component_size >= 52)
n = 3; n = 3;
value.read(ciffComponent.pData() + c * 2, n * 2, byteOrder); value.read(ciffComponent.pData() + c * 2, n * 2, byteOrder);
image.exifData().add(key, &value); image.exifData().add(key, &value);
if (ifdId == canonSiId && c == 21) if (ifdId == IfdId::canonSiId && c == 21)
aperture = value.toInt64(); aperture = value.toInt64();
if (ifdId == canonSiId && c == 22) if (ifdId == IfdId::canonSiId && c == 22)
shutterSpeed = value.toInt64(); shutterSpeed = value.toInt64();
c += n; c += n;
} }
if (ifdId == canonSiId) { if (ifdId == IfdId::canonSiId) {
// Exif.Photo.FNumber // Exif.Photo.FNumber
float f = fnumber(canonEv(aperture)); float f = fnumber(canonEv(aperture));
auto [r, s] = floatToRationalCast(f); auto [r, s] = floatToRationalCast(f);
@ -761,7 +749,7 @@ void CrwMap::decode0x180e(const CiffComponent& ciffComponent, const CrwMapping*
ULongValue v; ULongValue v;
v.read(ciffComponent.pData(), 8, byteOrder); v.read(ciffComponent.pData(), 8, byteOrder);
time_t t = v.value_.at(0); time_t t = v.value_.at(0);
struct tm* tm = std::localtime(&t); auto tm = std::localtime(&t);
if (tm) { if (tm) {
const size_t m = 20; const size_t m = 20;
char s[m]; char s[m];
@ -912,19 +900,19 @@ void CrwMap::encode0x080a(const Image& image, const CrwMapping* pCrwMapping, Cif
} }
void CrwMap::encodeArray(const Image& image, const CrwMapping* pCrwMapping, CiffHeader* pHead) { void CrwMap::encodeArray(const Image& image, const CrwMapping* pCrwMapping, CiffHeader* pHead) {
IfdId ifdId = ifdIdNotSet; IfdId ifdId = IfdId::ifdIdNotSet;
switch (pCrwMapping->tag_) { switch (pCrwMapping->tag_) {
case 0x0001: case 0x0001:
ifdId = canonCsId; ifdId = IfdId::canonCsId;
break; break;
case 0x0004: case 0x0004:
ifdId = canonSiId; ifdId = IfdId::canonSiId;
break; break;
case 0x000f: case 0x000f:
ifdId = canonCfId; ifdId = IfdId::canonCfId;
break; break;
case 0x0012: case 0x0012:
ifdId = canonPiId; ifdId = IfdId::canonPiId;
break; break;
} }
DataBuf buf = packIfdId(image.exifData(), ifdId, pHead->byteOrder()); DataBuf buf = packIfdId(image.exifData(), ifdId, pHead->byteOrder());
@ -970,7 +958,7 @@ void CrwMap::encode0x1810(const Image& image, const CrwMapping* pCrwMapping, Cif
const auto edO = exivData.findKey(kO); const auto edO = exivData.findKey(kO);
const auto edEnd = exivData.end(); const auto edEnd = exivData.end();
CiffComponent* cc = pHead->findComponent(pCrwMapping->crwTagId_, pCrwMapping->crwDir_); auto cc = pHead->findComponent(pCrwMapping->crwTagId_, pCrwMapping->crwDir_);
if (edX != edEnd || edY != edEnd || edO != edEnd) { if (edX != edEnd || edY != edEnd || edO != edEnd) {
size_t size = 28; size_t size = 28;
if (cc) { if (cc) {

@ -60,6 +60,8 @@ class CiffComponent {
//! Constructor taking a tag and directory //! Constructor taking a tag and directory
CiffComponent(uint16_t tag, uint16_t dir) : dir_(dir), tag_(tag) { CiffComponent(uint16_t tag, uint16_t dir) : dir_(dir), tag_(tag) {
} }
CiffComponent(const CiffComponent&) = delete;
CiffComponent& operator=(const CiffComponent&) = delete;
//! Virtual destructor. //! Virtual destructor.
virtual ~CiffComponent() = default; virtual ~CiffComponent() = default;
//@} //@}
@ -330,6 +332,9 @@ class CiffDirectory : public CiffComponent {
~CiffDirectory() override; ~CiffDirectory() override;
//@} //@}
CiffDirectory(const CiffDirectory&) = delete;
CiffDirectory& operator=(const CiffDirectory&) = delete;
//! @name Manipulators //! @name Manipulators
//@{ //@{
// Default assignment operator is fine // Default assignment operator is fine
@ -493,8 +498,8 @@ struct CrwMapping {
//! @name Creators //! @name Creators
//@{ //@{
//! Default constructor //! Default constructor
CrwMapping(uint16_t crwTagId, uint16_t crwDir, uint32_t size, uint16_t tag, Internal::IfdId ifdId, CrwMapping(uint16_t crwTagId, uint16_t crwDir, uint32_t size, uint16_t tag, IfdId ifdId, CrwDecodeFct toExif,
CrwDecodeFct toExif, CrwEncodeFct fromExif) : CrwEncodeFct fromExif) :
crwTagId_(crwTagId), crwTagId_(crwTagId),
crwDir_(crwDir), crwDir_(crwDir),
size_(size), size_(size),
@ -522,6 +527,7 @@ struct CrwMapping {
*/ */
class CrwMap { class CrwMap {
public: public:
~CrwMap() = delete;
//! @name Not implemented //! @name Not implemented
//@{ //@{
CrwMap(const CrwMap&) = delete; CrwMap(const CrwMap&) = delete;

@ -531,6 +531,10 @@ std::string IptcKey::tagLabel() const {
return IptcDataSets::dataSetTitle(tag_, record_); return IptcDataSets::dataSetTitle(tag_, record_);
} }
std::string IptcKey::tagDesc() const {
return IptcDataSets::dataSetDesc(tag_, record_);
}
uint16_t IptcKey::tag() const { uint16_t IptcKey::tag() const {
return tag_; return tag_;
} }

@ -11,6 +11,7 @@
#include "config.h" #include "config.h"
#include "basicio.hpp" #include "basicio.hpp"
#include "enforce.hpp"
#include "epsimage.hpp" #include "epsimage.hpp"
#include "error.hpp" #include "error.hpp"
#include "futils.hpp" #include "futils.hpp"
@ -101,13 +102,8 @@ void writeTemp(BasicIo& tempIo, const std::string& data) {
//! Get the current write position of temp file, taking care of errors //! Get the current write position of temp file, taking care of errors
uint32_t posTemp(const BasicIo& tempIo) { uint32_t posTemp(const BasicIo& tempIo) {
const long pos = tempIo.tell(); const size_t pos = tempIo.tell();
if (pos == -1) { enforce(pos <= std::numeric_limits<uint32_t>::max(), ErrorCode::kerImageWriteFailed);
#ifndef SUPPRESS_WARNINGS
EXV_WARNING << "Internal error while determining current write position in temporary file.\n";
#endif
throw Error(ErrorCode::kerImageWriteFailed);
}
return static_cast<uint32_t>(pos); return static_cast<uint32_t>(pos);
} }
@ -479,7 +475,7 @@ void readWriteEpsMetadata(BasicIo& io, std::string& xmpPacket, NativePreviewList
#endif #endif
// implicit comments // implicit comments
if (line == "%%EOF" || line == "%begin_xml_code" || if (line == "%%EOF" || line == "%begin_xml_code" ||
!(line.size() >= 2 && line[0] == '%' && '\x21' <= line[1] && line[1] <= '\x7e')) { !(line.size() >= 2 && line.front() == '%' && '\x21' <= line[1] && line[1] <= '\x7e')) {
if (posEndComments == posEndEps) { if (posEndComments == posEndEps) {
posEndComments = startPos; posEndComments = startPos;
#ifdef DEBUG #ifdef DEBUG
@ -496,20 +492,21 @@ void readWriteEpsMetadata(BasicIo& io, std::string& xmpPacket, NativePreviewList
#endif #endif
} }
if (posBeginPageSetup == posEndEps && if (posBeginPageSetup == posEndEps &&
(implicitPage || (posPage != posEndEps && !inRemovableEmbedding && !line.empty() && line[0] != '%'))) { (implicitPage || (posPage != posEndEps && !inRemovableEmbedding && !line.empty() && line.front() != '%'))) {
posBeginPageSetup = startPos; posBeginPageSetup = startPos;
implicitPageSetup = true; implicitPageSetup = true;
#ifdef DEBUG #ifdef DEBUG
EXV_DEBUG << "readWriteEpsMetadata: Found implicit BeginPageSetup at position: " << startPos << "\n"; EXV_DEBUG << "readWriteEpsMetadata: Found implicit BeginPageSetup at position: " << startPos << "\n";
#endif #endif
} }
if (posEndPageSetup == posEndEps && implicitPageSetup && !inRemovableEmbedding && !line.empty() && line[0] != '%') { if (posEndPageSetup == posEndEps && implicitPageSetup && !inRemovableEmbedding && !line.empty() &&
line.front() != '%') {
posEndPageSetup = startPos; posEndPageSetup = startPos;
#ifdef DEBUG #ifdef DEBUG
EXV_DEBUG << "readWriteEpsMetadata: Found implicit EndPageSetup at position: " << startPos << "\n"; EXV_DEBUG << "readWriteEpsMetadata: Found implicit EndPageSetup at position: " << startPos << "\n";
#endif #endif
} }
if (!line.empty() && line[0] != '%') if (!line.empty() && line.front() != '%')
continue; // performance optimization continue; // performance optimization
if (line == "%%EOF" || line == "%%Trailer" || line == "%%PageTrailer") { if (line == "%%EOF" || line == "%%Trailer" || line == "%%PageTrailer") {
if (posBeginPageSetup == posEndEps) { if (posBeginPageSetup == posEndEps) {
@ -1103,7 +1100,7 @@ std::string EpsImage::mimeType() const {
return "application/postscript"; return "application/postscript";
} }
void EpsImage::setComment(std::string_view /*comment*/) { void EpsImage::setComment(const std::string&) {
throw Error(ErrorCode::kerInvalidSettingForImage, "Image comment", "EPS"); throw Error(ErrorCode::kerInvalidSettingForImage, "Image comment", "EPS");
} }
@ -1167,7 +1164,7 @@ bool isEpsType(BasicIo& iIo, bool advance) {
bufSize = i.size(); bufSize = i.size();
} }
} }
const long restore = iIo.tell(); // save const size_t restore = iIo.tell(); // save
DataBuf buf = iIo.read(bufSize); DataBuf buf = iIo.read(bufSize);
if (iIo.error() || buf.size() != bufSize) { if (iIo.error() || buf.size() != bufSize) {
iIo.seek(restore, BasicIo::beg); iIo.seek(restore, BasicIo::beg);

@ -128,7 +128,7 @@ class JpegThumbnail : public Thumbnail {
int64_t sumToLong(const Exiv2::Exifdatum& md); int64_t sumToLong(const Exiv2::Exifdatum& md);
//! Helper function to delete all tags of a specific IFD from the metadata. //! Helper function to delete all tags of a specific IFD from the metadata.
void eraseIfd(Exiv2::ExifData& ed, Exiv2::Internal::IfdId ifdId); void eraseIfd(Exiv2::ExifData& ed, Exiv2::IfdId ifdId);
} // namespace } // namespace
@ -292,16 +292,20 @@ std::string Exifdatum::tagLabel() const {
return key_ ? key_->tagLabel() : ""; return key_ ? key_->tagLabel() : "";
} }
std::string Exifdatum::tagDesc() const {
return key_ ? key_->tagDesc() : "";
}
uint16_t Exifdatum::tag() const { uint16_t Exifdatum::tag() const {
return key_ ? key_->tag() : 0xffff; return key_ ? key_->tag() : 0xffff;
} }
int Exifdatum::ifdId() const { IfdId Exifdatum::ifdId() const {
return key_ ? key_->ifdId() : ifdIdNotSet; return key_ ? key_->ifdId() : IfdId::ifdIdNotSet;
} }
const char* Exifdatum::ifdName() const { const char* Exifdatum::ifdName() const {
return key_ ? Internal::ifdName(Internal::IfdId(key_->ifdId())) : ""; return key_ ? Internal::ifdName(static_cast<IfdId>(key_->ifdId())) : "";
} }
int Exifdatum::idx() const { int Exifdatum::idx() const {
@ -422,15 +426,15 @@ void ExifThumb::setJpegThumbnail(const std::string& path) {
} }
void ExifThumb::setJpegThumbnail(const byte* buf, size_t size) { void ExifThumb::setJpegThumbnail(const byte* buf, size_t size) {
exifData_["Exif.Thumbnail.Compression"] = uint16_t(6); exifData_["Exif.Thumbnail.Compression"] = static_cast<uint16_t>(6);
Exifdatum& format = exifData_["Exif.Thumbnail.JPEGInterchangeFormat"]; Exifdatum& format = exifData_["Exif.Thumbnail.JPEGInterchangeFormat"];
format = uint32_t(0); format = static_cast<uint32_t>(0);
format.setDataArea(buf, size); format.setDataArea(buf, size);
exifData_["Exif.Thumbnail.JPEGInterchangeFormatLength"] = uint32_t(size); exifData_["Exif.Thumbnail.JPEGInterchangeFormatLength"] = static_cast<uint32_t>(size);
} }
void ExifThumb::erase() { void ExifThumb::erase() {
eraseIfd(exifData_, ifd1Id); eraseIfd(exifData_, IfdId::ifd1Id);
} }
Exifdatum& ExifData::operator[](const std::string& key) { Exifdatum& ExifData::operator[](const std::string& key) {
@ -544,8 +548,9 @@ WriteMethod ExifParser::encode(Blob& blob, const byte* pData, size_t size, ByteO
// Delete IFDs which do not occur in JPEGs // Delete IFDs which do not occur in JPEGs
static constexpr auto filteredIfds = std::array{ static constexpr auto filteredIfds = std::array{
subImage1Id, subImage2Id, subImage3Id, subImage4Id, subImage5Id, subImage6Id, subImage7Id, IfdId::subImage1Id, IfdId::subImage2Id, IfdId::subImage3Id, IfdId::subImage4Id, IfdId::subImage5Id,
subImage8Id, subImage9Id, subThumb1Id, panaRawId, ifd2Id, ifd3Id, IfdId::subImage6Id, IfdId::subImage7Id, IfdId::subImage8Id, IfdId::subImage9Id, IfdId::subThumb1Id,
IfdId::panaRawId, IfdId::ifd2Id, IfdId::ifd3Id,
}; };
for (auto&& filteredIfd : filteredIfds) { for (auto&& filteredIfd : filteredIfds) {
#ifdef EXIV2_DEBUG_MESSAGES #ifdef EXIV2_DEBUG_MESSAGES
@ -676,26 +681,22 @@ WriteMethod ExifParser::encode(Blob& blob, const byte* pData, size_t size, ByteO
namespace { namespace {
//! @cond IGNORE //! @cond IGNORE
Thumbnail::UniquePtr Thumbnail::create(const Exiv2::ExifData& exifData) { Thumbnail::UniquePtr Thumbnail::create(const Exiv2::ExifData& exifData) {
std::unique_ptr<Thumbnail> thumbnail;
const Exiv2::ExifKey k1("Exif.Thumbnail.Compression"); const Exiv2::ExifKey k1("Exif.Thumbnail.Compression");
auto pos = exifData.findKey(k1); auto pos = exifData.findKey(k1);
if (pos != exifData.end()) { if (pos != exifData.end()) {
if (pos->count() == 0) if (pos->count() == 0)
return thumbnail; return nullptr;
auto compression = pos->toInt64(); auto compression = pos->toInt64();
if (compression == 6) { if (compression == 6)
thumbnail = std::make_unique<JpegThumbnail>(); return std::make_unique<JpegThumbnail>();
} else { return std::make_unique<TiffThumbnail>();
thumbnail = std::make_unique<TiffThumbnail>();
} }
} else {
const Exiv2::ExifKey k2("Exif.Thumbnail.JPEGInterchangeFormat"); const Exiv2::ExifKey k2("Exif.Thumbnail.JPEGInterchangeFormat");
pos = exifData.findKey(k2); pos = exifData.findKey(k2);
if (pos != exifData.end()) { if (pos != exifData.end())
thumbnail = std::make_unique<JpegThumbnail>(); return std::make_unique<JpegThumbnail>();
} return nullptr;
}
return thumbnail;
} }
const char* TiffThumbnail::mimeType() const { const char* TiffThumbnail::mimeType() const {

@ -365,191 +365,272 @@ std::ostream& printFujiFaceElementTypes(std::ostream& os, const Value& value, co
// Fujifilm MakerNote Tag Info // Fujifilm MakerNote Tag Info
constexpr TagInfo FujiMakerNote::tagInfo_[] = { constexpr TagInfo FujiMakerNote::tagInfo_[] = {
{0x0000, "Version", N_("Version"), N_("Fujifilm Makernote version"), fujiId, makerTags, undefined, -1, printValue}, {0x0000, "Version", N_("Version"), N_("Fujifilm Makernote version"), IfdId::fujiId, SectionId::makerTags, undefined,
-1, printValue},
{0x0010, "SerialNumber", N_("Serial Number"), {0x0010, "SerialNumber", N_("Serial Number"),
N_("This number is unique, and contains the date of manufacture, " N_("This number is unique, and contains the date of manufacture, "
"but is not the same as the number printed on the camera body."), "but is not the same as the number printed on the camera body."),
fujiId, makerTags, asciiString, -1, printValue}, IfdId::fujiId, SectionId::makerTags, asciiString, -1, printValue},
{0x1000, "Quality", N_("Quality"), N_("Image quality setting"), fujiId, makerTags, asciiString, -1, printValue}, {0x1000, "Quality", N_("Quality"), N_("Image quality setting"), IfdId::fujiId, SectionId::makerTags, asciiString, -1, printValue},
{0x1001, N_("Sharpness"), N_("Sharpness"), N_("Sharpness setting"), fujiId, makerTags, unsignedShort, -1, {0x1001, N_("Sharpness"), N_("Sharpness"), N_("Sharpness setting"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(fujiSharpness)}, EXV_PRINT_TAG(fujiSharpness)},
{0x1002, "WhiteBalance", N_("White Balance"), N_("White balance setting"), fujiId, makerTags, unsignedShort, -1, {0x1002, "WhiteBalance", N_("White Balance"), N_("White balance setting"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(fujiWhiteBalance)}, EXV_PRINT_TAG(fujiWhiteBalance)},
{0x1003, "Color", N_("Color"), N_("Chroma saturation setting"), fujiId, makerTags, unsignedShort, -1, {0x1003, "Color", N_("Color"), N_("Chroma saturation setting"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(fujiColor)}, EXV_PRINT_TAG(fujiColor)},
{0x1004, "Tone", N_("Tone"), N_("Tone (contrast) setting"), fujiId, makerTags, unsignedShort, -1, {0x1004, "Tone", N_("Tone"), N_("Tone (contrast) setting"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(fujiTone)}, EXV_PRINT_TAG(fujiTone)},
{0x1005, "ColorTemperature", N_("Color Temperature"), N_("Color temperature setting"), fujiId, makerTags, {0x1005, "ColorTemperature", N_("Color Temperature"), N_("Color temperature setting"), IfdId::fujiId, SectionId::makerTags,
unsignedShort, -1, printValue}, unsignedShort, -1, printValue},
{0x1006, "Contrast", N_("Contrast"), N_("Contrast setting"), fujiId, makerTags, unsignedShort, -1, {0x1006, "Contrast", N_("Contrast"), N_("Contrast setting"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(fujiContrast)}, EXV_PRINT_TAG(fujiContrast)},
{0x100a, "WhiteBalanceFineTune", N_("White Balance Fine Tune"), N_("White balance fine tune setting"), fujiId, {0x100a, "WhiteBalanceFineTune", N_("White Balance Fine Tune"), N_("White balance fine tune setting"), IfdId::fujiId,
makerTags, signedLong, -1, printFujiWhiteBalanceFineTune}, SectionId::makerTags, signedLong, -1, printFujiWhiteBalanceFineTune},
{0x100b, "NoiseReduction", N_("Noise Reduction"), N_("Noise reduction setting"), fujiId, makerTags, unsignedShort, {0x100b, "NoiseReduction", N_("Noise Reduction"), N_("Noise reduction setting"), IfdId::fujiId, SectionId::makerTags, unsignedShort,
-1, EXV_PRINT_TAG(fujiNoiseReduction)}, -1, EXV_PRINT_TAG(fujiNoiseReduction)},
{0x100e, "HighIsoNoiseReduction", N_("High ISO Noise Reduction"), N_("High ISO NR setting"), fujiId, makerTags, {0x100e, "HighIsoNoiseReduction", N_("High ISO Noise Reduction"), N_("High ISO NR setting"), IfdId::fujiId, SectionId::makerTags,
unsignedShort, -1, EXV_PRINT_TAG(fujiHighIsoNR)}, unsignedShort, -1, EXV_PRINT_TAG(fujiHighIsoNR)},
{0x100f, "Clarity", N_("Clarity"), N_("Clarity setting"), fujiId, makerTags, signedLong, -1, {0x100f, "Clarity", N_("Clarity"), N_("Clarity setting"), IfdId::fujiId, SectionId::makerTags, signedLong, -1,
EXV_PRINT_TAG(fujiClarity)}, EXV_PRINT_TAG(fujiClarity)},
{0x1010, "FlashMode", N_("Flash Mode"), N_("Flash firing mode setting"), fujiId, makerTags, unsignedShort, -1, {0x1010, "FlashMode", N_("Flash Mode"), N_("Flash firing mode setting"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(fujiFlashMode)}, EXV_PRINT_TAG(fujiFlashMode)},
{0x1011, "FlashStrength", N_("Flash Strength"), N_("Flash firing strength compensation setting"), fujiId, makerTags, {0x1011, "FlashStrength", N_("Flash Strength"), N_("Flash firing strength compensation setting"), IfdId::fujiId, SectionId::makerTags,
signedRational, -1, printValue}, signedRational, -1, printValue},
{0x1020, "Macro", N_("Macro"), N_("Macro mode setting"), fujiId, makerTags, unsignedShort, -1, {0x1020, "Macro", N_("Macro"), N_("Macro mode setting"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(fujiOffOn)}, EXV_PRINT_TAG(fujiOffOn)},
{0x1021, "FocusMode", N_("Focus Mode"), N_("Focusing mode setting"), fujiId, makerTags, unsignedShort, -1, {0x1021, "FocusMode", N_("Focus Mode"), N_("Focusing mode setting"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(fujiFocusMode)}, EXV_PRINT_TAG(fujiFocusMode)},
{0x1022, "FocusArea", "Focus Area", N_("Focus area setting"), fujiId, makerTags, unsignedShort, -1, {0x1022, "FocusArea", "Focus Area", N_("Focus area setting"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(fujiFocusArea)}, EXV_PRINT_TAG(fujiFocusArea)},
{0x1023, "FocusPoint", N_("Focus Point"), N_("X and Y coordinate of focus point"), fujiId, makerTags, unsignedShort, {0x1023, "FocusPoint", N_("Focus Point"), N_("X and Y coordinate of focus point"), IfdId::fujiId, SectionId::makerTags, unsignedShort,
-1, printValue}, -1, printValue},
{0x102b, "FocusPrioritySetting", N_("Focus Priority Setting"), N_("Focus priority setting"), fujiId, makerTags, {0x102b, "FocusPrioritySetting", N_("Focus Priority Setting"), N_("Focus priority setting"), IfdId::fujiId, SectionId::makerTags,
unsignedShort, -1, printValue}, unsignedShort, -1, printValue},
{0x102d, "FocusSetting", N_("Focus Setting"), N_("Focus setting"), fujiId, makerTags, unsignedLong, -1, printValue}, {0x102d, "FocusSetting", N_("Focus Setting"), N_("Focus setting"), IfdId::fujiId, SectionId::makerTags, unsignedLong, -1, printValue},
{0x102e, "ContinuousFocusSetting", N_("AF-C Focus Setting"), N_("AF-C focus setting"), fujiId, makerTags, {0x102e, "ContinuousFocusSetting", N_("AF-C Focus Setting"), N_("AF-C focus setting"), IfdId::fujiId, SectionId::makerTags,
unsignedLong, -1, printValue}, unsignedLong, -1, printValue},
{0x1030, "SlowSync", N_("Slow Sync"), N_("Slow synchro mode setting"), fujiId, makerTags, unsignedShort, -1, {0x1030, "SlowSync", N_("Slow Sync"), N_("Slow synchro mode setting"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(fujiOffOn)}, EXV_PRINT_TAG(fujiOffOn)},
{0x1031, "PictureMode", N_("Picture Mode"), N_("Picture mode setting"), fujiId, makerTags, unsignedShort, -1, {0x1031, "PictureMode", N_("Picture Mode"), N_("Picture mode setting"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(fujiPictureMode)}, EXV_PRINT_TAG(fujiPictureMode)},
{0x1032, "ExposureCount", "Exposure Count", N_("Number of exposures used for this image"), fujiId, makerTags, {0x1032, "ExposureCount", "Exposure Count", N_("Number of exposures used for this image"), IfdId::fujiId, SectionId::makerTags,
unsignedShort, -1, printValue}, unsignedShort, -1, printValue},
{0x1033, "EXRAuto", "EXR Auto", {0x1033, "EXRAuto", "EXR Auto",
N_("EXR Auto"), // TODO find description N_("EXR Auto"), // TODO find description
fujiId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiOffOn)}, IfdId::fujiId, SectionId::makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiOffOn)},
{0x1034, "EXRMode", "EXR Mode", {0x1034, "EXRMode", "EXR Mode",
N_("EXR Auto"), // TODO find description N_("EXR Auto"), // TODO find description
fujiId, makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiExrMode)}, IfdId::fujiId, SectionId::makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiExrMode)},
{0x1040, "ShadowTone", N_("Shadow Tone"), N_("Shadow tone"), fujiId, makerTags, signedLong, -1, {0x1040, "ShadowTone", N_("Shadow Tone"), N_("Shadow tone"), IfdId::fujiId, SectionId::makerTags, signedLong, -1,
EXV_PRINT_TAG(fujiSHTone)}, EXV_PRINT_TAG(fujiSHTone)},
{0x1041, "HighlightTone", N_("Highlight Tone"), N_("Highlight tone"), fujiId, makerTags, signedLong, -1, {0x1041, "HighlightTone", N_("Highlight Tone"), N_("Highlight tone"), IfdId::fujiId, SectionId::makerTags, signedLong, -1,
EXV_PRINT_TAG(fujiSHTone)}, EXV_PRINT_TAG(fujiSHTone)},
{0x1044, "DigitalZoom", N_("Digital Zoom"), N_("Digital zoom"), fujiId, makerTags, unsignedLong, -1, {0x1044, "DigitalZoom", N_("Digital Zoom"), N_("Digital zoom"), IfdId::fujiId, SectionId::makerTags, unsignedLong, -1,
printFujiDigitalZoom}, printFujiDigitalZoom},
{0x1045, "LensModulationOptimizer", N_("Lens Modulation Optimizer"), N_("Lens modulation optimizer setting"), {0x1045, "LensModulationOptimizer", N_("Lens Modulation Optimizer"), N_("Lens modulation optimizer setting"),
fujiId, makerTags, unsignedLong, -1, EXV_PRINT_TAG(fujiOffOn)}, IfdId::fujiId, SectionId::makerTags, unsignedLong, -1, EXV_PRINT_TAG(fujiOffOn)},
{0x1047, "GrainEffectRoughness", N_("Grain Effect Roughness"), N_("Grain effect roughness setting"), fujiId, {0x1047, "GrainEffectRoughness", N_("Grain Effect Roughness"), N_("Grain effect roughness setting"), IfdId::fujiId,
makerTags, signedLong, -1, EXV_PRINT_TAG(fujiOff0Weak32Strong64)}, SectionId::makerTags, signedLong, -1, EXV_PRINT_TAG(fujiOff0Weak32Strong64)},
{0x1048, "ColorChromeEffect", N_("Color Chrome Effect"), N_("Color Chrome Effect"), fujiId, makerTags, signedLong, {0x1048, "ColorChromeEffect", N_("Color Chrome Effect"), N_("Color Chrome Effect"), IfdId::fujiId, SectionId::makerTags, signedLong,
-1, EXV_PRINT_TAG(fujiOff0Weak32Strong64)}, -1, EXV_PRINT_TAG(fujiOff0Weak32Strong64)},
{0x1049, "MonochromaticColorWC", N_("Monochromatic Color (Warm-Cool)"), {0x1049, "MonochromaticColorWC", N_("Monochromatic Color (Warm-Cool)"),
N_("Monochromatic color (warm-cool) setting. High value results in warm color shift and low values in cold color " N_("Monochromatic color (warm-cool) setting. High value results in warm color shift and low values in cold color "
"shift."), "shift."),
fujiId, makerTags, unsignedByte, -1, printFujiMonochromaticColor}, IfdId::fujiId, SectionId::makerTags, unsignedByte, -1, printFujiMonochromaticColor},
{0x104b, "MonochromaticColorMG", N_("Monochromatic Color (Magenta-Green)"), {0x104b, "MonochromaticColorMG", N_("Monochromatic Color (Magenta-Green)"),
N_("Monochromatic color (magenta-green) setting. High value results in magenta color shift and low values in " N_("Monochromatic color (magenta-green) setting. High value results in magenta color shift and low values in "
"green color shift."), "green color shift."),
fujiId, makerTags, unsignedByte, -1, printFujiMonochromaticColor}, IfdId::fujiId, SectionId::makerTags, unsignedByte, -1, printFujiMonochromaticColor},
{0x104c, "GrainEffectSize", N_("Grain Effect Size"), N_("Grain effect size setting"), fujiId, makerTags, {0x104c, "GrainEffectSize", N_("Grain Effect Size"), N_("Grain effect size setting"), IfdId::fujiId, SectionId::makerTags,
unsignedShort, -1, EXV_PRINT_TAG(fujiOff0Weak32Strong64)}, unsignedShort, -1, EXV_PRINT_TAG(fujiOff0Weak32Strong64)},
{0x104d, "CropMode", N_("Crop Mode"), N_("Crop mode"), fujiId, makerTags, unsignedShort, -1, {0x104d, "CropMode", N_("Crop Mode"), N_("Crop mode"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(fujiCropMode)}, EXV_PRINT_TAG(fujiCropMode)},
{0x104e, "ColorChromeFXBlue", N_("Color Chrome FX Blue"), N_("Color Chrome FX Blue"), fujiId, makerTags, signedLong, {0x104e, "ColorChromeFXBlue", N_("Color Chrome FX Blue"), N_("Color Chrome FX Blue"), IfdId::fujiId, SectionId::makerTags, signedLong,
-1, EXV_PRINT_TAG(fujiOff0Weak32Strong64)}, -1, EXV_PRINT_TAG(fujiOff0Weak32Strong64)},
{0x1050, "ShutterType", N_("Shutter Type"), N_("Shutter type"), fujiId, makerTags, unsignedShort, -1, {0x1050, "ShutterType", N_("Shutter Type"), N_("Shutter type"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(fujiShutterType)}, EXV_PRINT_TAG(fujiShutterType)},
{0x1100, "Continuous", N_("Continuous"), N_("Continuous shooting or auto bracketing setting"), fujiId, makerTags, {0x1100, "Continuous", N_("Continuous"), N_("Continuous shooting or auto bracketing setting"), IfdId::fujiId, SectionId::makerTags,
unsignedShort, -1, EXV_PRINT_TAG(fujiContinuous)}, unsignedShort, -1, EXV_PRINT_TAG(fujiContinuous)},
{0x1101, "SequenceNumber", N_("Sequence Number"), N_("Sequence number"), fujiId, makerTags, unsignedShort, -1, {0x1101, "SequenceNumber", N_("Sequence Number"), N_("Sequence number"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
printValue}, printValue},
{0x1103, "DriveSetting", N_("Drive Setting"), N_("Drive setting"), fujiId, makerTags, unsignedShort, -1, {0x1103, "DriveSetting", N_("Drive Setting"), N_("Drive setting"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
printFujiDriveSetting}, printFujiDriveSetting},
{0x1105, "PixelShiftShots", N_("Pixel Shift Shots"), N_("Pixel shift shots"), fujiId, makerTags, unsignedShort, -1, {0x1105, "PixelShiftShots", N_("Pixel Shift Shots"), N_("Pixel shift shots"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
printValue}, printValue},
{0x1105, "PixelShiftOfffset", N_("Pixel Shift Offset"), N_("Pixel shift offset"), fujiId, makerTags, signedRational, {0x1105, "PixelShiftOfffset", N_("Pixel Shift Offset"), N_("Pixel shift offset"), IfdId::fujiId, SectionId::makerTags, signedRational,
-1, printValue}, -1, printValue},
{0x1153, "PanoramaAngle", N_("Panorama angle"), N_("Panorama angle"), fujiId, makerTags, unsignedShort, -1, {0x1153, "PanoramaAngle", N_("Panorama angle"), N_("Panorama angle"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
printValue}, printValue},
{0x1154, "PanoramaDirection", N_("Panorama direction"), N_("Panorama direction"), fujiId, makerTags, unsignedShort, {0x1154, "PanoramaDirection", N_("Panorama direction"), N_("Panorama direction"), IfdId::fujiId, SectionId::makerTags, unsignedShort,
-1, EXV_PRINT_TAG(fujiPanoramaDirection)}, -1, EXV_PRINT_TAG(fujiPanoramaDirection)},
{0x1200, "0x1200", "0x1200", N_("Unknown"), fujiId, makerTags, unsignedShort, -1, printValue}, {0x1200, "0x1200", "0x1200", N_("Unknown"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1, printValue},
{0x1201, "AdvancedFilter", N_("Advanced filter"), N_("Advanced filter setting"), fujiId, makerTags, unsignedLong, {0x1201, "AdvancedFilter", N_("Advanced filter"), N_("Advanced filter setting"), IfdId::fujiId, SectionId::makerTags, unsignedLong,
-1, EXV_PRINT_TAG(fujiAdvancedFilter)}, -1, EXV_PRINT_TAG(fujiAdvancedFilter)},
{0x1210, "FinePixColor", N_("FinePix Color"), N_("Fuji FinePix color setting"), fujiId, makerTags, unsignedShort, {0x1210, "FinePixColor", N_("FinePix Color"), N_("Fuji FinePix color setting"), IfdId::fujiId, SectionId::makerTags, unsignedShort,
-1, EXV_PRINT_TAG(fujiFinePixColor)}, -1, EXV_PRINT_TAG(fujiFinePixColor)},
{0x1300, "BlurWarning", N_("Blur Warning"), N_("Blur warning status"), fujiId, makerTags, unsignedShort, -1, {0x1300, "BlurWarning", N_("Blur Warning"), N_("Blur warning status"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(fujiOffOn)}, EXV_PRINT_TAG(fujiOffOn)},
{0x1301, "FocusWarning", N_("Focus Warning"), N_("Auto Focus warning status"), fujiId, makerTags, unsignedShort, -1, {0x1301, "FocusWarning", N_("Focus Warning"), N_("Auto Focus warning status"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(fujiOffOn)}, EXV_PRINT_TAG(fujiOffOn)},
{0x1302, "ExposureWarning", N_("Exposure Warning"), N_("Auto exposure warning status"), fujiId, makerTags, {0x1302, "ExposureWarning", N_("Exposure Warning"), N_("Auto exposure warning status"), IfdId::fujiId, SectionId::makerTags,
unsignedShort, -1, EXV_PRINT_TAG(fujiOffOn)}, unsignedShort, -1, EXV_PRINT_TAG(fujiOffOn)},
{0x1400, "DynamicRange", N_("Dynamic Range"), N_("Dynamic range"), fujiId, makerTags, unsignedShort, -1, {0x1400, "DynamicRange", N_("Dynamic Range"), N_("Dynamic range"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(fujiDynamicRange)}, EXV_PRINT_TAG(fujiDynamicRange)},
{0x1401, "FilmMode", N_("Film Mode"), N_("Film mode"), fujiId, makerTags, unsignedShort, -1, {0x1401, "FilmMode", N_("Film Mode"), N_("Film mode"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(fujiFilmMode)}, EXV_PRINT_TAG(fujiFilmMode)},
{0x1402, "DynamicRangeSetting", N_("Dynamic Range Setting"), N_("Dynamic range settings"), fujiId, makerTags, {0x1402, "DynamicRangeSetting", N_("Dynamic Range Setting"), N_("Dynamic range settings"), IfdId::fujiId, SectionId::makerTags,
unsignedShort, -1, EXV_PRINT_TAG(fujiDynamicRangeSetting)}, unsignedShort, -1, EXV_PRINT_TAG(fujiDynamicRangeSetting)},
{0x1403, "DevelopmentDynamicRange", N_("Development Dynamic Range"), N_("Development dynamic range"), fujiId, {0x1403, "DevelopmentDynamicRange", N_("Development Dynamic Range"), N_("Development dynamic range"), IfdId::fujiId,
makerTags, unsignedShort, -1, printValue}, SectionId::makerTags, unsignedShort, -1, printValue},
{0x1404, "MinFocalLength", N_("Minimum Focal Length"), N_("Minimum focal length"), fujiId, makerTags, {0x1404, "MinFocalLength", N_("Minimum Focal Length"), N_("Minimum focal length"), IfdId::fujiId, SectionId::makerTags,
unsignedRational, -1, printValue}, unsignedRational, -1, printValue},
{0x1405, "MaxFocalLength", N_("Maximum Focal Length"), N_("Maximum focal length"), fujiId, makerTags, {0x1405, "MaxFocalLength", N_("Maximum Focal Length"), N_("Maximum focal length"), IfdId::fujiId, SectionId::makerTags,
unsignedRational, -1, printValue}, unsignedRational, -1, printValue},
{0x1406, "MaxApertureAtMinFocal", N_("Maximum Aperture at Minimum Focal"), N_("Maximum aperture at minimum focal"), {0x1406, "MaxApertureAtMinFocal", N_("Maximum Aperture at Minimum Focal"), N_("Maximum aperture at minimum focal"),
fujiId, makerTags, unsignedRational, -1, printValue}, IfdId::fujiId, SectionId::makerTags, unsignedRational, -1, printValue},
{0x1407, "MaxApertureAtMaxFocal", N_("Maximum Aperture at Maximum Focal"), N_("Maximum aperture at maximum focal"), {0x1407, "MaxApertureAtMaxFocal", N_("Maximum Aperture at Maximum Focal"), N_("Maximum aperture at maximum focal"),
fujiId, makerTags, unsignedRational, -1, printValue}, IfdId::fujiId, SectionId::makerTags, unsignedRational, -1, printValue},
{0x140b, "AutoDynamicRange", N_("Auto Dynamic Range"), N_("Auto dynamic range"), fujiId, makerTags, unsignedShort, {0x140b, "AutoDynamicRange", N_("Auto Dynamic Range"), N_("Auto dynamic range"), IfdId::fujiId, SectionId::makerTags, unsignedShort,
-1, printValue}, -1, printValue},
{0x1422, "ImageStabilization", N_("Image Stabilization"), N_("Image stabilization"), fujiId, makerTags, {0x1422, "ImageStabilization", N_("Image Stabilization"), N_("Image stabilization"), IfdId::fujiId, SectionId::makerTags,
unsignedShort, -1, printValue}, unsignedShort, -1, printValue},
{0x1425, "SzeneRecognition", N_("Scene recognition"), N_("Scene recognition"), fujiId, makerTags, unsignedShort, -1, {0x1425, "SzeneRecognition", N_("Scene recognition"), N_("Scene recognition"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(fujiSceneRecognition)}, EXV_PRINT_TAG(fujiSceneRecognition)},
{0x1431, "Rating", N_("Rating"), N_("Rating"), fujiId, makerTags, unsignedLong, -1, printValue}, {0x1431, "Rating", N_("Rating"), N_("Rating"), IfdId::fujiId, SectionId::makerTags, unsignedLong, -1, printValue},
{0x1436, "ImageGeneration", N_("Image Generation"), N_("Image generation"), fujiId, makerTags, unsignedShort, -1, {0x1436, "ImageGeneration", N_("Image Generation"), N_("Image generation"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(fujiImageGeneration)}, EXV_PRINT_TAG(fujiImageGeneration)},
{0x1438, "ImageNumber", N_("Image Number"), N_("Image Number"), fujiId, makerTags, unsignedShort, -1, printValue}, {0x1438, "ImageNumber", N_("Image Number"), N_("Image Number"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1, printValue},
{0x1443, "DRangePriority", N_("D Range Priority"), N_("Dynamic range priority"), fujiId, makerTags, unsignedShort, {0x1443, "DRangePriority", N_("D Range Priority"), N_("Dynamic range priority"), IfdId::fujiId, SectionId::makerTags, unsignedShort,
-1, EXV_PRINT_TAG(fujiDRangePriority)}, -1, EXV_PRINT_TAG(fujiDRangePriority)},
{0x1444, "DRangePriorityFixed", N_("D Range Priority Fixed"), N_("Dynamic range priority fixed"), fujiId, makerTags, {0x1444, "DRangePriorityFixed", N_("D Range Priority Fixed"), N_("Dynamic range priority fixed"), IfdId::fujiId, SectionId::makerTags,
unsignedShort, -1, EXV_PRINT_TAG(fujiDRangePriorityFixed)}, unsignedShort, -1, EXV_PRINT_TAG(fujiDRangePriorityFixed)},
{0x1445, "DRangePriorityAuto", N_("D Range Priority Auto"), N_("Dynamic range priority auto"), fujiId, makerTags, {0x1445, "DRangePriorityAuto", N_("D Range Priority Auto"), N_("Dynamic range priority auto"), IfdId::fujiId, SectionId::makerTags,
unsignedShort, -1, EXV_PRINT_TAG(fujiDRangePriorityAuto)}, unsignedShort, -1, EXV_PRINT_TAG(fujiDRangePriorityAuto)},
{0x4005, "FaceElementSelected", N_("Face Element Selected"), N_("Face element selected"), fujiId, makerTags, {0x4005, "FaceElementSelected", N_("Face Element Selected"), N_("Face element selected"), IfdId::fujiId, SectionId::makerTags,
asciiString, -1, printValue}, asciiString, -1, printValue},
{0x4100, "FacesDetected", N_("Faces Detected"), N_("Faces detected"), fujiId, makerTags, asciiString, -1, {0x4100, "FacesDetected", N_("Faces Detected"), N_("Faces detected"), IfdId::fujiId, SectionId::makerTags, asciiString, -1,
printValue}, printValue},
{0x4103, "FacePositions", N_("Face Positions"), {0x4103, "FacePositions", N_("Face Positions"),
N_("Left, top, right and bottom coordinates in full-sized image for each face detected"), fujiId, makerTags, N_("Left, top, right and bottom coordinates in full-sized image for each face detected"), IfdId::fujiId, SectionId::makerTags,
asciiString, -1, printValue}, asciiString, -1, printValue},
{0x4200, "NumberFaceElements", N_("Number of Face Elements"), N_("Number of face elements"), fujiId, makerTags, {0x4200, "NumberFaceElements", N_("Number of Face Elements"), N_("Number of face elements"), IfdId::fujiId, SectionId::makerTags,
asciiString, -1, printValue}, asciiString, -1, printValue},
{0x4201, "FaceElementTypes", N_("Face Element Types"), N_("Type of every face element"), fujiId, makerTags, {0x4201, "FaceElementTypes", N_("Face Element Types"), N_("Type of every face element"), IfdId::fujiId, SectionId::makerTags,
asciiString, -1, printFujiFaceElementTypes}, asciiString, -1, printFujiFaceElementTypes},
{0x4203, "FaceElementPositions", N_("Face Element Positions"), {0x4203, "FaceElementPositions", N_("Face Element Positions"),
N_("Left, top, right and bottom coordinates in full-sized image for each face element)"), fujiId, makerTags, N_("Left, top, right and bottom coordinates in full-sized image for each face element)"), IfdId::fujiId, SectionId::makerTags,
asciiString, -1, printValue}, asciiString, -1, printValue},
{0x4282, "FaceRecInfo", N_("Face Recognition Information"), N_("Face Recognition Information"), fujiId, makerTags, {0x4282, "FaceRecInfo", N_("Face Recognition Information"), N_("Face Recognition Information"), IfdId::fujiId, SectionId::makerTags,
asciiString, -1, printValue}, asciiString, -1, printValue},
{0x8000, "FileSource", N_("File Source"), N_("File source"), fujiId, makerTags, asciiString, -1, printValue}, {0x8000, "FileSource", N_("File Source"), N_("File source"), IfdId::fujiId, SectionId::makerTags, asciiString, -1, printValue},
{0x8002, "OrderNumber", N_("Order Number"), N_("Order number"), fujiId, makerTags, unsignedLong, -1, printValue}, {0x8002, "OrderNumber", N_("Order Number"), N_("Order number"), IfdId::fujiId, SectionId::makerTags, unsignedLong, -1, printValue},
{0x8003, "FrameNumber", N_("Frame Number"), N_("Frame number"), fujiId, makerTags, unsignedShort, -1, printValue}, {0x8003, "FrameNumber", N_("Frame Number"), N_("Frame number"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1, printValue},
// #1402 // #1402
{0xf000, "FujiIFD", N_("FujiIFD"), N_("Fujifilm IFD"), fujiId, makerTags, undefined, -1, printValue}, {0xf000, "FujiIFD", N_("FujiIFD"), N_("Fujifilm IFD"), IfdId::fujiId, SectionId::makerTags, undefined, -1, printValue},
{0xf001, "RawImageFullWidth", N_("Raw Image Full Width"), N_("Raw Image Full Width"), fujiId, makerTags, undefined, {0xf001, "RawImageFullWidth", N_("Raw Image Full Width"), N_("Raw Image Full Width"), IfdId::fujiId, SectionId::makerTags, undefined,
-1, printValue}, -1, printValue},
{0xf002, "RawImageFullHeight", N_("Raw Image Full Height"), N_("Raw Image Full Height"), fujiId, makerTags, {0x1001, N_("Sharpness"), N_("Sharpness"), N_("Sharpness setting"), IfdId::fujiId, SectionId::makerTags,
undefined, -1, printValue}, unsignedShort, -1, EXV_PRINT_TAG(fujiSharpness)},
{0xf003, "BitsPerSample", N_("Bits Per Sample"), N_("Bits Per Sample"), fujiId, makerTags, undefined, -1, {0x1002, "WhiteBalance", N_("White Balance"), N_("White balance setting"), IfdId::fujiId, SectionId::makerTags,
unsignedShort, -1, EXV_PRINT_TAG(fujiWhiteBalance)},
{0x1003, "Color", N_("Color"), N_("Chroma saturation setting"), IfdId::fujiId, SectionId::makerTags, unsignedShort,
-1, EXV_PRINT_TAG(fujiColor)},
{0x1004, "Tone", N_("Tone"), N_("Tone (contrast) setting"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(fujiTone)},
{0x1010, "FlashMode", N_("Flash Mode"), N_("Flash firing mode setting"), IfdId::fujiId, SectionId::makerTags,
unsignedShort, -1, EXV_PRINT_TAG(fujiFlashMode)},
{0x1011, "FlashStrength", N_("Flash Strength"), N_("Flash firing strength compensation setting"), IfdId::fujiId,
SectionId::makerTags, signedRational, -1, printValue},
{0x1020, "Macro", N_("Macro"), N_("Macro mode setting"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(fujiOffOn)},
{0x1021, "FocusMode", N_("Focus Mode"), N_("Focusing mode setting"), IfdId::fujiId, SectionId::makerTags,
unsignedShort, -1, EXV_PRINT_TAG(fujiFocusMode)},
{0x1022, "0x1022", "0x1022", N_("Unknown"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1, printValue},
{0x1030, "SlowSync", N_("Slow Sync"), N_("Slow synchro mode setting"), IfdId::fujiId, SectionId::makerTags,
unsignedShort, -1, EXV_PRINT_TAG(fujiOffOn)},
{0x1031, "PictureMode", N_("Picture Mode"), N_("Picture mode setting"), IfdId::fujiId, SectionId::makerTags,
unsignedShort, -1, EXV_PRINT_TAG(fujiPictureMode)},
{0x1032, "0x1032", "0x1032", N_("Unknown"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1, printValue},
{0x1040, "ShadowTone", N_("Shadow Tone"), N_("Shadow tone"), IfdId::fujiId, SectionId::makerTags, signedLong, -1,
EXV_PRINT_TAG(fujiSHTone)},
{0x1041, "HighlightTone", N_("Highlight Tone"), N_("Highlight tone"), IfdId::fujiId, SectionId::makerTags,
signedLong, -1, EXV_PRINT_TAG(fujiSHTone)},
{0x104d, "CropMode", N_("Crop Mode"), N_("Crop mode"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(fujiCropMode)},
{0x1100, "Continuous", N_("Continuous"), N_("Continuous shooting or auto bracketing setting"), IfdId::fujiId,
SectionId::makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiContinuous)},
{0x1101, "SequenceNumber", N_("Sequence Number"), N_("Sequence number"), IfdId::fujiId, SectionId::makerTags,
unsignedShort, -1, printValue},
{0x1200, "0x1200", "0x1200", N_("Unknown"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1, printValue},
{0x1210, "FinePixColor", N_("FinePix Color"), N_("Fuji FinePix color setting"), IfdId::fujiId, SectionId::makerTags,
unsignedShort, -1, EXV_PRINT_TAG(fujiFinePixColor)},
{0x1300, "BlurWarning", N_("Blur Warning"), N_("Blur warning status"), IfdId::fujiId, SectionId::makerTags,
unsignedShort, -1, EXV_PRINT_TAG(fujiOffOn)},
{0x1301, "FocusWarning", N_("Focus Warning"), N_("Auto Focus warning status"), IfdId::fujiId, SectionId::makerTags,
unsignedShort, -1, EXV_PRINT_TAG(fujiOffOn)},
{0x1302, "ExposureWarning", N_("Exposure Warning"), N_("Auto exposure warning status"), IfdId::fujiId,
SectionId::makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiOffOn)},
{0x1400, "DynamicRange", N_("Dynamic Range"), N_("Dynamic range"), IfdId::fujiId, SectionId::makerTags,
unsignedShort, -1, EXV_PRINT_TAG(fujiDynamicRange)},
{0x1401, "FilmMode", N_("Film Mode"), N_("Film mode"), IfdId::fujiId, SectionId::makerTags, unsignedShort, -1,
EXV_PRINT_TAG(fujiFilmMode)},
{0x1402, "DynamicRangeSetting", N_("Dynamic Range Setting"), N_("Dynamic range settings"), IfdId::fujiId,
SectionId::makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiDynamicRangeSetting)},
{0x1403, "DevelopmentDynamicRange", N_("Development Dynamic Range"), N_("Development dynamic range"), IfdId::fujiId,
SectionId::makerTags, unsignedShort, -1, printValue},
{0x1404, "MinFocalLength", N_("Minimum Focal Length"), N_("Minimum focal length"), IfdId::fujiId,
SectionId::makerTags, unsignedRational, -1, printValue},
{0x1405, "MaxFocalLength", N_("Maximum Focal Length"), N_("Maximum focal length"), IfdId::fujiId,
SectionId::makerTags, unsignedRational, -1, printValue},
{0x1406, "MaxApertureAtMinFocal", N_("Maximum Aperture at Minimum Focal"), N_("Maximum aperture at minimum focal"),
IfdId::fujiId, SectionId::makerTags, unsignedRational, -1, printValue},
{0x1407, "MaxApertureAtMaxFocal", N_("Maximum Aperture at Maximum Focal"), N_("Maximum aperture at maximum focal"),
IfdId::fujiId, SectionId::makerTags, unsignedRational, -1, printValue},
{0x1431, "Rating", N_("Rating"), N_("Rating"), IfdId::fujiId, SectionId::makerTags, unsignedLong, -1, printValue},
{0x1443, "DRangePriority", N_("D Range Priority"), N_("Dynamic range priority"), IfdId::fujiId,
SectionId::makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiDRangePriority)},
{0x1444, "DRangePriorityFixed", N_("D Range Priority Fixed"), N_("Dynamic range priority fixed"), IfdId::fujiId,
SectionId::makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiDRangePriorityFixed)},
{0x1445, "DRangePriorityAuto", N_("D Range Priority Auto"), N_("Dynamic range priority auto"), IfdId::fujiId,
SectionId::makerTags, unsignedShort, -1, EXV_PRINT_TAG(fujiDRangePriorityAuto)},
{0x8000, "FileSource", N_("File Source"), N_("File source"), IfdId::fujiId, SectionId::makerTags, asciiString, -1,
printValue}, printValue},
{0xf007, "StripOffsets", N_("Strip Offsets"), N_("Strip Offsets"), fujiId, makerTags, undefined, -1, printValue}, {0x8002, "OrderNumber", N_("Order Number"), N_("Order number"), IfdId::fujiId, SectionId::makerTags, unsignedLong,
{0xf008, "StripByteCounts", N_("Strip Byte Counts"), N_("Strip Byte Counts"), fujiId, makerTags, undefined, -1, -1, printValue},
{0x8003, "FrameNumber", N_("Frame Number"), N_("Frame number"), IfdId::fujiId, SectionId::makerTags, unsignedShort,
-1, printValue},
// #1402
{0xf000, "FujiIFD", N_("FujiIFD"), N_("Fujifilm IFD"), IfdId::fujiId, SectionId::makerTags, undefined, -1,
printValue}, printValue},
{0xf00a, "BlackLevel", N_("Black Level"), N_("Black Level"), fujiId, makerTags, undefined, -1, printValue}, {0xf001, "RawImageFullWidth", N_("Raw Image Full Width"), N_("Raw Image Full Width"), IfdId::fujiId,
{0xf00b, "GeometricDistortionParams", N_("Geometric Distortion Params"), N_("Geometric Distortion Params"), fujiId, SectionId::makerTags, undefined, -1, printValue},
makerTags, undefined, -1, printValue}, {0xf002, "RawImageFullHeight", N_("Raw Image Full Height"), N_("Raw Image Full Height"), IfdId::fujiId,
{0xf00c, "WB_GRBLevelsStandard", N_("WB GRB Levels Standard"), N_("WB GRB Levels Standard"), fujiId, makerTags, SectionId::makerTags, undefined, -1, printValue},
{0xf003, "BitsPerSample", N_("Bits Per Sample"), N_("Bits Per Sample"), IfdId::fujiId, SectionId::makerTags,
undefined, -1, printValue}, undefined, -1, printValue},
{0xf00d, "WB_GRBLevelsAuto", N_("WB GRB Levels Auto"), N_("WB GRB Levels Auto"), fujiId, makerTags, undefined, -1, {0xf007, "StripOffsets", N_("Strip Offsets"), N_("Strip Offsets"), IfdId::fujiId, SectionId::makerTags, undefined,
printValue}, -1, printValue},
{0xf00e, "WB_GRBLevels", N_("WB GRB Levels"), N_("WB GRB Levels"), fujiId, makerTags, undefined, -1, printValue}, {0xf008, "StripByteCounts", N_("Strip Byte Counts"), N_("Strip Byte Counts"), IfdId::fujiId, SectionId::makerTags,
{0xf00f, "ChromaticAberrationParams", N_("Chromatic Aberration Params"), N_("Chromatic Aberration Params"), fujiId, undefined, -1, printValue},
makerTags, undefined, -1, printValue}, {0xf00a, "BlackLevel", N_("Black Level"), N_("Black Level"), IfdId::fujiId, SectionId::makerTags, undefined, -1,
{0xf010, "VignettingParams", N_("Vignetting Params"), N_("Vignetting Params"), fujiId, makerTags, undefined, -1,
printValue}, printValue},
{0xf00b, "GeometricDistortionParams", N_("Geometric Distortion Params"), N_("Geometric Distortion Params"),
IfdId::fujiId, SectionId::makerTags, undefined, -1, printValue},
{0xf00c, "WB_GRBLevelsStandard", N_("WB GRB Levels Standard"), N_("WB GRB Levels Standard"), IfdId::fujiId,
SectionId::makerTags, undefined, -1, printValue},
{0xf00d, "WB_GRBLevelsAuto", N_("WB GRB Levels Auto"), N_("WB GRB Levels Auto"), IfdId::fujiId,
SectionId::makerTags, undefined, -1, printValue},
{0xf00e, "WB_GRBLevels", N_("WB GRB Levels"), N_("WB GRB Levels"), IfdId::fujiId, SectionId::makerTags, undefined,
-1, printValue},
{0xf00f, "ChromaticAberrationParams", N_("Chromatic Aberration Params"), N_("Chromatic Aberration Params"),
IfdId::fujiId, SectionId::makerTags, undefined, -1, printValue},
{0xf010, "VignettingParams", N_("Vignetting Params"), N_("Vignetting Params"), IfdId::fujiId, SectionId::makerTags,
undefined, -1, printValue},
// End of list marker // End of list marker
{0xffff, "(UnknownFujiMakerNoteTag)", "(UnknownFujiMakerNoteTag)", N_("Unknown FujiMakerNote tag"), fujiId, {0xffff, "(UnknownFujiMakerNoteTag)", "(UnknownFujiMakerNoteTag)", N_("Unknown FujiMakerNote tag"), IfdId::fujiId,
makerTags, asciiString, -1, printValue}}; SectionId::makerTags, asciiString, -1, printValue},
};
const TagInfo* FujiMakerNote::tagList() { const TagInfo* FujiMakerNote::tagList() {
return tagInfo_; return tagInfo_;

@ -79,7 +79,7 @@ char from_hex(char ch) {
return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10; return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
} }
std::string urlencode(std::string_view str) { std::string urlencode(const std::string& str) {
std::string encoded; std::string encoded;
encoded.reserve(str.size() * 3); encoded.reserve(str.size() * 3);
for (uint8_t c : str) { for (uint8_t c : str) {
@ -259,22 +259,20 @@ void Uri::Decode(Uri& uri) {
Uri Uri::Parse(const std::string& uri) { Uri Uri::Parse(const std::string& uri) {
Uri result; Uri result;
using iterator_t = std::string::const_iterator;
if (!uri.length()) if (!uri.length())
return result; return result;
iterator_t uriEnd = uri.end(); auto uriEnd = uri.end();
// get query start // get query start
iterator_t queryStart = std::find(uri.begin(), uriEnd, '?'); auto queryStart = std::find(uri.begin(), uriEnd, '?');
// protocol // protocol
iterator_t protocolStart = uri.begin(); auto protocolStart = uri.begin();
iterator_t protocolEnd = std::find(protocolStart, uriEnd, ':'); //"://"); auto protocolEnd = std::find(protocolStart, uriEnd, ':'); //"://");
if (protocolEnd != uriEnd) { if (protocolEnd != uriEnd) {
std::string prot = &*(protocolEnd); auto prot = std::string(protocolEnd, uriEnd);
if ((prot.length() > 3) && (prot.substr(0, 3) == "://")) { if ((prot.length() > 3) && (prot.substr(0, 3) == "://")) {
result.Protocol = std::string(protocolStart, protocolEnd); result.Protocol = std::string(protocolStart, protocolEnd);
protocolEnd += 3; // :// protocolEnd += 3; // ://
@ -284,11 +282,11 @@ Uri Uri::Parse(const std::string& uri) {
protocolEnd = uri.begin(); // no protocol protocolEnd = uri.begin(); // no protocol
// username & password // username & password
iterator_t authStart = protocolEnd; auto authStart = protocolEnd;
iterator_t authEnd = std::find(protocolEnd, uriEnd, '@'); auto authEnd = std::find(protocolEnd, uriEnd, '@');
if (authEnd != uriEnd) { if (authEnd != uriEnd) {
iterator_t userStart = authStart; auto userStart = authStart;
iterator_t userEnd = std::find(authStart, authEnd, ':'); auto userEnd = std::find(authStart, authEnd, ':');
if (userEnd != authEnd) { if (userEnd != authEnd) {
result.Username = std::string(userStart, userEnd); result.Username = std::string(userStart, userEnd);
++userEnd; ++userEnd;
@ -302,19 +300,19 @@ Uri Uri::Parse(const std::string& uri) {
} }
// host // host
iterator_t hostStart = authEnd; auto hostStart = authEnd;
iterator_t pathStart = std::find(hostStart, uriEnd, '/'); // get pathStart auto pathStart = std::find(hostStart, uriEnd, '/'); // get pathStart
iterator_t hostEnd = std::find(authEnd, (pathStart != uriEnd) ? pathStart : queryStart, auto hostEnd = std::find(authEnd, (pathStart != uriEnd) ? pathStart : queryStart,
':'); // check for port ':'); // check for port
result.Host = std::string(hostStart, hostEnd); result.Host = std::string(hostStart, hostEnd);
// port // port
if ((hostEnd != uriEnd) && ((&*(hostEnd))[0] == ':')) // we have a port if ((hostEnd != uriEnd) && (*hostEnd == ':')) // we have a port
{ {
++hostEnd; ++hostEnd;
iterator_t portEnd = (pathStart != uriEnd) ? pathStart : queryStart; auto portEnd = (pathStart != uriEnd) ? pathStart : queryStart;
result.Port = std::string(hostEnd, portEnd); result.Port = std::string(hostEnd, portEnd);
} }
if (!result.Port.length() && result.Protocol == "http") if (!result.Port.length() && result.Protocol == "http")
@ -378,7 +376,7 @@ std::string getProcessPath() {
ret = std::filesystem::read_symlink("/proc/self/exe"); ret = std::filesystem::read_symlink("/proc/self/exe");
#endif #endif
const size_t idxLastSeparator = ret.find_last_of(EXV_SEPARATOR_STR); const size_t idxLastSeparator = ret.find_last_of(EXV_SEPARATOR_CHR);
return ret.substr(0, idxLastSeparator); return ret.substr(0, idxLastSeparator);
} }
} // namespace Exiv2 } // namespace Exiv2

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

@ -336,7 +336,7 @@ int Exiv2::http(Exiv2::Dictionary& request, Exiv2::Dictionary& response, std::st
if (n != FINISH || !OK(status)) { if (n != FINISH || !OK(status)) {
snprintf(buffer, sizeof buffer, "wsa_error = %d,n = %d,sleep_ = %d status = %d", WSAGetLastError(), n, snprintf(buffer, sizeof buffer, "wsa_error = %d,n = %d,sleep_ = %d status = %d", WSAGetLastError(), n,
int(sleep_.count()), status); static_cast<int>(sleep_.count()), status);
error(errors, buffer, nullptr, nullptr, 0); error(errors, buffer, nullptr, nullptr, 0);
} else if (bSearching && OK(status)) { } else if (bSearching && OK(status)) {
if (end) { if (end) {

@ -99,8 +99,6 @@ constexpr auto registry = std::array{
#ifdef EXV_ENABLE_BMFF #ifdef EXV_ENABLE_BMFF
Registry{ImageType::bmff, newBmffInstance, isBmffType, amRead, amRead, amRead, amNone}, Registry{ImageType::bmff, newBmffInstance, isBmffType, amRead, amRead, amRead, amNone},
#endif // EXV_ENABLE_BMFF #endif // EXV_ENABLE_BMFF
// End of list marker
Registry{ImageType::none, nullptr, nullptr, amNone, amNone, amNone, amNone},
}; };
std::string pathOfFileUrl(const std::string& url) { std::string pathOfFileUrl(const std::string& url) {
@ -116,17 +114,13 @@ std::string pathOfFileUrl(const std::string& url) {
namespace Exiv2 { namespace Exiv2 {
Image::Image(ImageType type, uint16_t supportedMetadata, BasicIo::UniquePtr io) : Image::Image(ImageType type, uint16_t supportedMetadata, BasicIo::UniquePtr io) :
io_(std::move(io)), io_(std::move(io)),
pixelWidth_(0),
pixelHeight_(0),
imageType_(type), imageType_(type),
supportedMetadata_(supportedMetadata), supportedMetadata_(supportedMetadata),
#ifdef EXV_HAVE_XMP_TOOLKIT #ifdef EXV_HAVE_XMP_TOOLKIT
writeXmpFromPacket_(false), writeXmpFromPacket_(false) {
#else #else
writeXmpFromPacket_(true), writeXmpFromPacket_(true) {
#endif #endif
byteOrder_(invalidByteOrder),
init_(true) {
} }
void Image::printStructure(std::ostream&, PrintStructureOption, int /*depth*/) { void Image::printStructure(std::ostream&, PrintStructureOption, int /*depth*/) {
@ -190,17 +184,17 @@ uint64_t Image::byteSwap(uint64_t value, bool bSwap) {
uint32_t Image::byteSwap(uint32_t value, bool bSwap) { uint32_t Image::byteSwap(uint32_t value, bool bSwap) {
uint32_t result = 0; uint32_t result = 0;
result |= (value & 0x000000FF) << 24; result |= (value & 0x000000FFU) << 24;
result |= (value & 0x0000FF00) << 8; result |= (value & 0x0000FF00U) << 8;
result |= (value & 0x00FF0000) >> 8; result |= (value & 0x00FF0000U) >> 8;
result |= (value & 0xFF000000) >> 24; result |= (value & 0xFF000000U) >> 24;
return bSwap ? result : value; return bSwap ? result : value;
} }
uint16_t Image::byteSwap(uint16_t value, bool bSwap) { uint16_t Image::byteSwap(uint16_t value, bool bSwap) {
uint16_t result = 0; uint16_t result = 0;
result |= (value & 0x00FF) << 8; result |= (value & 0x00FFU) << 8;
result |= (value & 0xFF00) >> 8; result |= (value & 0xFF00U) >> 8;
return bSwap ? result : value; return bSwap ? result : value;
} }
@ -287,7 +281,7 @@ static bool typeValid(uint16_t type) {
return type >= 1 && type <= 13; return type >= 1 && type <= 13;
} }
static std::set<long> visits; // #547 static std::set<size_t> visits; // #547
void Image::printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStructureOption option, size_t start, void Image::printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStructureOption option, size_t start,
bool bSwap, char c, int depth) { bool bSwap, char c, int depth) {
@ -370,7 +364,7 @@ void Image::printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStruct
const bool bOffsetIsPointer = count_x_size > 4; const bool bOffsetIsPointer = count_x_size > 4;
if (bOffsetIsPointer) { // read into buffer if (bOffsetIsPointer) { // read into buffer
const long restore = io.tell(); // save const size_t restore = io.tell(); // save
io.seekOrThrow(offset, BasicIo::beg, ErrorCode::kerCorruptedMetadata); // position io.seekOrThrow(offset, BasicIo::beg, ErrorCode::kerCorruptedMetadata); // position
io.readOrThrow(buf.data(), count_x_size, ErrorCode::kerCorruptedMetadata); // read io.readOrThrow(buf.data(), count_x_size, ErrorCode::kerCorruptedMetadata); // read
io.seekOrThrow(restore, BasicIo::beg, ErrorCode::kerCorruptedMetadata); // restore io.seekOrThrow(restore, BasicIo::beg, ErrorCode::kerCorruptedMetadata); // restore
@ -381,7 +375,7 @@ void Image::printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStruct
const std::string offsetString = bOffsetIsPointer ? Internal::stringFormat("%10u", offset) : ""; const std::string offsetString = bOffsetIsPointer ? Internal::stringFormat("%10u", offset) : "";
out << Internal::indent(depth) out << Internal::indent(depth)
<< Internal::stringFormat("%8u | %#06x %-28s |%10s |%9u |%10s | ", address, tag, tagName(tag).c_str(), << Internal::stringFormat("%8zu | %#06x %-28s |%10s |%9u |%10s | ", address, tag, tagName(tag).c_str(),
typeName(type), count, offsetString.c_str()); typeName(type), count, offsetString.c_str());
if (isShortType(type)) { if (isShortType(type)) {
for (size_t k = 0; k < kount; k++) { for (size_t k = 0; k < kount; k++) {
@ -410,7 +404,7 @@ void Image::printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStruct
if (option == kpsRecursive && (tag == 0x8769 /* ExifTag */ || tag == 0x014a /*SubIFDs*/ || type == tiffIfd)) { if (option == kpsRecursive && (tag == 0x8769 /* ExifTag */ || tag == 0x014a /*SubIFDs*/ || type == tiffIfd)) {
for (size_t k = 0; k < count; k++) { for (size_t k = 0; k < count; k++) {
const long restore = io.tell(); const size_t restore = io.tell();
offset = byteSwap4(buf, k * size, bSwap); offset = byteSwap4(buf, k * size, bSwap);
printIFDStructure(io, out, option, offset, bSwap, c, depth); printIFDStructure(io, out, option, offset, bSwap, c, depth);
io.seekOrThrow(restore, BasicIo::beg, ErrorCode::kerCorruptedMetadata); io.seekOrThrow(restore, BasicIo::beg, ErrorCode::kerCorruptedMetadata);
@ -421,17 +415,17 @@ void Image::printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStruct
throw Error(ErrorCode::kerCorruptedMetadata); throw Error(ErrorCode::kerCorruptedMetadata);
} }
const long restore = io.tell(); const size_t restore = io.tell();
io.seekOrThrow(offset, BasicIo::beg, ErrorCode::kerCorruptedMetadata); // position io.seekOrThrow(offset, BasicIo::beg, ErrorCode::kerCorruptedMetadata); // position
std::vector<byte> bytes(count); // allocate memory std::vector<byte> bytes(count); // allocate memory
// TODO: once we have C++11 use bytes.data() // TODO: once we have C++11 use bytes.data()
io.readOrThrow(&bytes[0], count, ErrorCode::kerCorruptedMetadata); io.readOrThrow(bytes.data(), count, ErrorCode::kerCorruptedMetadata);
io.seekOrThrow(restore, BasicIo::beg, ErrorCode::kerCorruptedMetadata); io.seekOrThrow(restore, BasicIo::beg, ErrorCode::kerCorruptedMetadata);
// TODO: once we have C++11 use bytes.data() // TODO: once we have C++11 use bytes.data()
IptcData::printStructure(out, makeSliceUntil(&bytes[0], count), depth); IptcData::printStructure(out, makeSliceUntil(bytes.data(), count), depth);
} }
} else if (option == kpsRecursive && tag == 0x927c /* MakerNote */ && count > 10) { } else if (option == kpsRecursive && tag == 0x927c /* MakerNote */ && count > 10) {
const long restore = io.tell(); // save const size_t restore = io.tell(); // save
uint32_t jump = 10; uint32_t jump = 10;
byte bytes[20]; byte bytes[20];
@ -597,7 +591,7 @@ void Image::clearComment() {
comment_.erase(); comment_.erase();
} }
void Image::setComment(std::string_view comment) { void Image::setComment(const std::string& comment) {
comment_ = comment; comment_ = comment;
} }
@ -755,9 +749,9 @@ ImageType ImageFactory::getType(BasicIo& io) {
if (io.open() != 0) if (io.open() != 0)
return ImageType::none; return ImageType::none;
IoCloser closer(io); IoCloser closer(io);
for (unsigned int i = 0; registry[i].imageType_ != ImageType::none; ++i) { for (const auto& r : registry) {
if (registry[i].isThisType_(io, false)) { if (r.isThisType_(io, false)) {
return registry[i].imageType_; return r.imageType_;
} }
} }
return ImageType::none; return ImageType::none;
@ -802,9 +796,9 @@ Image::UniquePtr ImageFactory::open(BasicIo::UniquePtr io) {
if (io->open() != 0) { if (io->open() != 0) {
throw Error(ErrorCode::kerDataSourceOpenFailed, io->path(), strError()); throw Error(ErrorCode::kerDataSourceOpenFailed, io->path(), strError());
} }
for (unsigned int i = 0; registry[i].imageType_ != ImageType::none; ++i) { for (const auto& r : registry) {
if (registry[i].isThisType_(*io, false)) { if (r.isThisType_(*io, false)) {
return registry[i].newInstance_(std::move(io), false); return r.newInstance_(std::move(io), false);
} }
} }
return nullptr; return nullptr;

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save