Compare commits

..

2 Commits

Author SHA1 Message Date
Matthew b7e091ce77 移除对pthread的依赖 9 months ago
Matthew 1d3009d723 修复 c++ 17下auto_ptr错误 9 months ago

@ -1,24 +0,0 @@
---
# Indentation for all files
ColumnLimit: 120
# C++ Options
Language: Cpp
BasedOnStyle: Google
# Force pointers to the type for C++.
DerivePointerAlignment: false
PointerAlignment: Left
# Useful for sorting the project inclusions and standard library inclusions separately
IncludeBlocks: Preserve
# Constructor initializers better formatted in presence of preprocessor conditions (see image.cpp)
BreakConstructorInitializers: AfterColon
# Do not allow SingleLine statements (to improve coverage statistics)
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
...

@ -0,0 +1,28 @@
---
BasedOnStyle: Google
Language: Cpp
Standard: Cpp03
TabWidth: 4
UseTab: Never
ColumnLimit: 120
NamespaceIndentation: All
AccessModifierOffset: -4
ContinuationIndentWidth: 4
IndentWidth: 4
BreakBeforeBraces: Custom
BraceWrapping:
AfterStruct: true
AfterClass: true
AfterFunction: true
AfterControlStatement: false
AfterEnum: true
AfterNamespace: true
AllowShortFunctionsOnASingleLine: None
AllowShortBlocksOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
...

@ -1,17 +0,0 @@
with section("format"):
# How wide to allow formatted cmake files
line_width = 150
# How many spaces to tab for indent
tab_size = 2
# If true, separate flow control names from their parentheses with a space
separate_ctrl_name_with_space = False
# If true, separate function names from parentheses with a space
separate_fn_name_with_space = False
# If a statement is wrapped to more than one line, than dangle the closing
# parenthesis on its own line.
dangle_parens = True

@ -1,6 +0,0 @@
[*]
charset = utf-8
insert_final_newline = true
indent_style = space
indent_size = 2
trim_trailing_whitespace=true

@ -1,4 +0,0 @@
# ignore global clang-format
30bf563f4d71ff284b5f42d45f77226200a2e571
# fic formatting followup from #2158
a3cb054746beed514679592ffec9378acc9e5d41

@ -1,29 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
#### **Describe the bug**
A clear and concise description of the bug, including your use case for exiv2.
#### **To Reproduce**
Steps to reproduce the behavior:
1. Provide the file with which you observed the issue (commonly named PoC). Explain the status of the file (e.g., direct from camera, edited with darktable), whether you own the copyright and if you allow the file to be added to exiv2 under the [project's license](https://github.com/Exiv2/exiv2/blob/main/COPYING)
2. List the exact commands/functions to reproduce the issue and include any related output
3. Mention the branch and commit in which you observed the issue (e.g., `main, commit 9f721b40`, `0.27-maintenance, latest`)
#### **Expected behavior**
A short description of what you expected to happen.
#### **Desktop (please complete the following information):**
- OS and version: (e.g., Linux (Fedora 36), macOS 12.5, Windows 11)
- Exiv2 version and source: (e.g., 0.27.5 from exiv2.org)
- Compiler and version: (e.g., Gcc 12.2, Clang 14.0.0, MSVC 2022)
- Compilation mode and/or compiler flags: (e.g., debug, `-O3`)
#### **Additional context**
Add any other information about the problem here.

@ -1,25 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: request
assignees: ''
---
#### **Is your feature request related to a problem?**
A clear and concise description of the problem, including your use case for exiv2 and any impact on your workflow.
#### **Describe the solution you would like**
A short description of what you want to happen.
#### **Describe alternatives you have considered**
A simple explanation of any alternative solutions (e.g., using ExifTool) or features you have considered (e.g., convert the file to JPEG).
#### **Desktop**
- OS and version: (e.g., Linux (Fedora 36), macOS 12.5, Windows 11)
- Exiv2 version and source: (e.g., 0.27.5 from exiv2.org)
- Any software using exiv2 and source: (e.g., darktable 4.0 from darktable.org)
#### **Additional context**
Add any other information about the feature request here (e.g. screenshots, URLs, test files).

@ -1,3 +0,0 @@
# Reusing existing QL Pack
- import: codeql-suites/cpp-code-scanning.qls
from: codeql-cpp

@ -1,23 +0,0 @@
<!DOCTYPE qhelp SYSTEM "qhelp.dtd">
<qhelp>
<overview>
<p>
A C++ iterator is a lot like a C pointer: if you dereference it without
first checking that it's valid then it can cause a crash.
</p>
</overview>
<recommendation>
<p>
Always check that the iterator is valid before derefencing it.
</p>
</recommendation>
<example>
<p>
<a href="https://github.com/Exiv2/exiv2/issues/1763">Issue 1763</a> was caused by
<a href="https://github.com/Exiv2/exiv2/blob/9b3ed3f9564b4ea51b43c78671435bde6b862e08/src/canonmn_int.cpp#L2755">this
dereference</a> of the iterator <tt>pos</tt>.
The bug was <a href="https://github.com/Exiv2/exiv2/pull/1767">fixed</a> by not dereferencing
<tt>pos</tt> if <tt>pos == metadata->end()</tt>.
</p>
</example>
</qhelp>

@ -1,47 +0,0 @@
/**
* @name NULL iterator deref
* @description Dereferencing an iterator without checking that it's valid could cause a crash.
* @kind problem
* @problem.severity warning
* @id cpp/null-iterator-deref
* @tags security
* external/cwe/cwe-476
*/
import cpp
import semmle.code.cpp.controlflow.Guards
import semmle.code.cpp.dataflow.DataFlow
// Holds if `cond` is a condition like `use == table.end()`.
// `eq_is_true` is `true` for `==`, `false` for '!=`.
// Note: the `==` is actually an overloaded `operator==`.
predicate end_condition(GuardCondition cond, Expr use, FunctionCall endCall, boolean eq_is_true) {
exists(FunctionCall eq |
exists(string opName | eq.getTarget().getName() = opName |
opName = "operator==" and eq_is_true = true
or
opName = "operator!=" and eq_is_true = false
) and
DataFlow::localExprFlow(use, eq.getAnArgument()) and
DataFlow::localExprFlow(endCall, eq.getAnArgument()) and
endCall.getTarget().getName() = "end" and
DataFlow::localExprFlow(eq, cond)
)
}
from FunctionCall call, Expr use
where
call.getTarget().getName() = "findKey" and
DataFlow::localExprFlow(call, use) and
use != call and
not use.(AssignExpr).getRValue() = call and
not end_condition(_, use, _, _) and
not exists(
Expr cond_use, FunctionCall endCall, GuardCondition cond, BasicBlock block, boolean branch
|
end_condition(cond, cond_use, endCall, branch) and
DataFlow::localExprFlow(call, cond_use) and
cond.controls(block, branch.booleanNot()) and
block.contains(use)
)
select call, "Iterator returned by findKey might cause a null deref $@.", use, "here"

@ -1,65 +0,0 @@
/**
* @name Null metadata in print function
* @description Print functions need to check that the metadata isn't null before calling methods on it.
* @kind problem
* @problem.severity warning
* @id cpp/null-metadata-in-print
*/
import cpp
import semmle.code.cpp.controlflow.Guards
import semmle.code.cpp.controlflow.Nullness
import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
// Find all the print functions by looking for TagInfo initializers
// like this one:
// https://github.com/Exiv2/exiv2/blob/6b186a4cd276ac11b3ea69951c2112f4c4814b9a/src/canonmn_int.cpp#L660-L679
class PrintFunction extends Function {
PrintFunction() {
exists(Initializer i, Field f |
i.getExpr().(ArrayAggregateLiteral).getAChild().(ClassAggregateLiteral).getAFieldExpr(f) =
this.getAnAccess() and
f.getName() = "printFct_"
)
}
}
predicate metadataDeref(Expr metadata) {
exists(Call call | call.getQualifier() = metadata)
or
exists(FunctionCall call, int argIndex, Function f |
call.getArgument(argIndex) = metadata and
f = call.getTarget() and
metadataDeref(f.getParameter(argIndex).getAnAccess())
)
}
predicate unsafePointerParam(Function f, int paramIndex, Expr use) {
exists(Parameter p |
p = f.getParameter(paramIndex) and
use = p.getAnAccess() and
unsafePointerExpr(use) and
not exists(GuardCondition nonNullCheck, BasicBlock block, boolean branch |
validCheckExpr(nonNullCheck, p) and
nonNullCheck.controls(block, branch) and
block.contains(use)
)
)
}
predicate unsafePointerExpr(Expr e) {
exists(Call call |
call.getQualifier() = e and
e.getType().getUnspecifiedType() instanceof PointerType
)
or
exists(FunctionCall call, int argIndex, Function f |
call.getArgument(argIndex) = e and
f = call.getTarget() and
unsafePointerParam(f, argIndex, _)
)
}
from PrintFunction printfcn, Parameter p, Expr metadata
where unsafePointerParam(printfcn, 2, metadata)
select metadata, "Print functions need to check that the metadata isn't null."

@ -1,4 +0,0 @@
name: exiv2-cpp-queries
version: 0.0.0
libraryPathDependencies: codeql-cpp
suites: exiv2-cpp-suite

@ -1,24 +0,0 @@
/**
* @name Signed shift
* @description Shifting a negative number is undefined behavior,
* so it is risky to shift a signed number.
* @kind problem
* @problem.severity warning
* @id cpp/signed-shift
* @tags security
* external/cwe/cwe-758
*/
// See the "Bitwise shift operators" section here:
// https://en.cppreference.com/w/cpp/language/operator_arithmetic
import cpp
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
from BinaryBitwiseOperation shift, Expr lhs
where
(shift instanceof LShiftExpr or shift instanceof RShiftExpr) and
lhs = shift.getLeftOperand().getFullyConverted() and
lowerBound(lhs) < 0
select shift,
"This signed shift could cause undefined behavior if the value is negative. Type of lhs: " +
lhs.getType().toString()

@ -1,30 +0,0 @@
<!DOCTYPE qhelp SYSTEM "qhelp.dtd">
<qhelp>
<overview>
<p>
The <a href="https://en.cppreference.com/w/cpp/container/vector/operator_at"><tt>operator[]</tt></a> method of <a href="https://en.cppreference.com/w/cpp/container/vector"><tt>std::vector</tt></a> does not do any bounds checking on the index. It is safer to use the <a href="https://en.cppreference.com/w/cpp/container/vector/at"><tt>at()</tt></a> method, which does do bounds checking.
</p>
</overview>
<recommendation>
<p>
Use the <a href="https://en.cppreference.com/w/cpp/container/vector/at"><tt>at()</tt></a> method, rather than <a href="https://en.cppreference.com/w/cpp/container/vector/operator_at"><tt>operator[]</tt></a>.
</p>
<p>
Some uses of <a href="https://en.cppreference.com/w/cpp/container/vector/operator_at"><tt>operator[]</tt></a> are safe because they are protected by a bounds check. The query recognises the following safe coding patterns:
</p>
<ul>
<li><tt>if (!x.empty()) { ...x[0]... }</tt></li>
<li><tt>if (x.length()) { ...x[0]... }</tt></li>
<li><tt>if (x.size() > 2) { ...x[2]... }</tt></li>
<li><tt>if (x.size() == 2) { ...x[1]... }</tt></li>
<li><tt>if (x.size() != 0) { ...x[0]... }</tt></li>
<li><tt>if (i < x.size()) { ... x[i] ... }</tt></li>
<li><tt>if (!x.empty()) { ... x[x.size() - 1] ... }</tt></li>
</ul>
</recommendation>
<example>
<p>
<a href="https://github.com/Exiv2/exiv2/issues/1706">#1706</a> was caused by a lack of bounds-checking on <a href="https://github.com/Exiv2/exiv2/blob/15098f4ef50cc721ad0018218acab2ff06e60beb/include/exiv2/value.hpp#L1639">this array access</a>. The bug was <a href="https://github.com/Exiv2/exiv2/pull/1735">fixed</a> calling the <a href="https://en.cppreference.com/w/cpp/container/vector/at"><tt>at()</tt></a> method instead.
</p>
</example>
</qhelp>

@ -1,181 +0,0 @@
/**
* @name Unsafe vector access
* @description std::vector::operator[] does not do any runtime
* bounds-checking, so it is safer to use std::vector::at()
* @kind problem
* @problem.severity warning
* @id cpp/unsafe-vector-access
* @tags security
* external/cwe/cwe-125
*/
import cpp
import semmle.code.cpp.controlflow.Guards
import semmle.code.cpp.dataflow.DataFlow
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
import semmle.code.cpp.valuenumbering.HashCons
// A call to `operator[]`.
class ArrayIndexCall extends FunctionCall {
ClassTemplateInstantiation ti;
TemplateClass tc;
ArrayIndexCall() {
this.getTarget().getName() = "operator[]" and
ti = this.getQualifier().getType().getUnspecifiedType() and
tc = ti.getTemplate() and
tc.getSimpleName() != "map" and
tc.getSimpleName() != "match_results"
}
ClassTemplateInstantiation getClassTemplateInstantiation() { result = ti }
TemplateClass getTemplateClass() { result = tc }
}
// A call to `size` or `length`.
class SizeCall extends FunctionCall {
string fname;
SizeCall() {
fname = this.getTarget().getName() and
(fname = "size" or fname = "length")
}
}
// `x[i]` is safe if `x` is a `std::array` (fixed-size array)
// and `i` within the bounds of the array.
predicate indexK_with_fixedarray(ClassTemplateInstantiation t, ArrayIndexCall call) {
t = call.getClassTemplateInstantiation() and
exists(Expr idx |
t.getSimpleName() = "array" and
idx = call.getArgument(0) and
lowerBound(idx) >= 0 and
upperBound(idx) < lowerBound(t.getTemplateArgument(1))
)
}
// Holds if `cond` is a Boolean condition that checks the size of
// the array. It handles the following code patterns:
//
// 1. `if (!x.empty()) { ... }`
// 2. `if (x.length()) { ... }`
// 3. `if (x.size() > 2) { ... }`
// 4. `if (x.size() == 2) { ... }`
// 5. `if (x.size() != 0) { ... }`
//
// If it safe to assume that `x.size() >= minsize` on the exit `branch`.
predicate minimum_size_cond(Expr cond, Expr arrayExpr, int minsize, boolean branch) {
// `if (!x.empty()) { ...x[0]... }`
exists(FunctionCall emptyCall |
cond = emptyCall and
arrayExpr = emptyCall.getQualifier() and
emptyCall.getTarget().getName() = "empty" and
minsize = 1 and
branch = false
)
or
// `if (x.length()) { ...x[0]... }`
exists(SizeCall sizeCall |
cond = sizeCall and
arrayExpr = sizeCall.getQualifier() and
minsize = 1 and
branch = true
)
or
// `if (x.size() > 2) { ...x[2]... }`
exists(SizeCall sizeCall, Expr k, RelationStrictness strict |
arrayExpr = sizeCall.getQualifier() and
relOpWithSwapAndNegate(cond, sizeCall, k, Greater(), strict, branch)
|
strict = Strict() and minsize = 1 + k.getValue().toInt()
or
strict = Nonstrict() and minsize = k.getValue().toInt()
)
or
// `if (x.size() == 2) { ...x[1]... }`
exists(SizeCall sizeCall, Expr k |
arrayExpr = sizeCall.getQualifier() and
eqOpWithSwapAndNegate(cond, sizeCall, k, true, branch) and
minsize = k.getValue().toInt()
)
or
// `if (x.size() != 0) { ...x[0]... }`
exists(SizeCall sizeCall, Expr k |
arrayExpr = sizeCall.getQualifier() and
eqOpWithSwapAndNegate(cond, sizeCall, k, false, branch) and
k.getValue().toInt() = 0 and
minsize = 1
)
}
// Array accesses like these are safe:
// `if (!x.empty()) { ... x[0] ... }`
// `if (x.size() > 2) { ... x[2] ... }`
predicate indexK_with_check(GuardCondition guard, ArrayIndexCall call) {
exists(Expr arrayExpr, BasicBlock block, int i, int minsize, boolean branch |
minimum_size_cond(guard, arrayExpr, minsize, branch) and
(
globalValueNumber(arrayExpr) = globalValueNumber(call.getQualifier()) or
hashCons(arrayExpr) = hashCons(call.getQualifier())
) and
guard.controls(block, branch) and
block.contains(call) and
i = call.getArgument(0).getValue().toInt() and
0 <= i and
i < minsize
)
}
// Array accesses like this are safe:
// `if (i < x.size()) { ... x[i] ... }`
predicate indexI_with_check(GuardCondition guard, ArrayIndexCall call) {
exists(Expr idx, SizeCall sizeCall, BasicBlock block, boolean branch |
relOpWithSwapAndNegate(guard, idx, sizeCall, Lesser(), Strict(), branch) and
(
globalValueNumber(sizeCall.getQualifier()) = globalValueNumber(call.getQualifier()) and
globalValueNumber(idx) = globalValueNumber(call.getArgument(0))
or
hashCons(sizeCall.getQualifier()) = hashCons(call.getQualifier()) and
hashCons(idx) = hashCons(call.getArgument(0))
) and
guard.controls(block, branch) and
block.contains(call)
)
}
// Array accesses like this are safe:
// `if (!x.empty()) { ... x[x.size() - 1] ... }`
predicate index_last_with_check(GuardCondition guard, ArrayIndexCall call) {
exists(Expr arrayExpr, SubExpr minusExpr, SizeCall sizeCall, BasicBlock block, boolean branch |
minimum_size_cond(guard, arrayExpr, _, branch) and
(
globalValueNumber(arrayExpr) = globalValueNumber(call.getQualifier()) or
hashCons(arrayExpr) = hashCons(call.getQualifier())
) and
guard.controls(block, branch) and
block.contains(call) and
minusExpr = call.getArgument(0) and
minusExpr.getRightOperand().getValue().toInt() = 1 and
DataFlow::localExprFlow(sizeCall, minusExpr.getLeftOperand()) and
(
globalValueNumber(sizeCall.getQualifier()) = globalValueNumber(call.getQualifier()) or
hashCons(sizeCall.getQualifier()) = hashCons(call.getQualifier())
)
)
}
from ArrayIndexCall call
where
not indexK_with_fixedarray(_, call) and
not indexK_with_check(_, call) and
not indexI_with_check(_, call) and
not index_last_with_check(_, call) and
// Ignore accesses like this: `vsnprintf(&buffer[0], buffer.size(), format, args)`
// That's pointer arithmetic, not a deref, so it's usually a false positive.
not exists(AddressOfExpr addrExpr | addrExpr.getOperand() = call) and
// Ignore results in the xmpsdk directory.
not call.getLocation().getFile().getRelativePath().matches("xmpsdk/%")
select call, "Unsafe use of operator[]. Use the at() method instead."

@ -1,5 +0,0 @@
name: "Exiv2 CodeQL config"
queries:
- uses: ./.github/codeql-queries/exiv2-code-scanning.qls
- uses: ./.github/codeql-queries/exiv2-cpp-queries

@ -1,6 +0,0 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"

@ -1,33 +0,0 @@
# OSS-Fuzz continuous integration:
# https://google.github.io/oss-fuzz/getting-started/continuous-integration/
name: CIFuzz
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
on:
pull_request:
paths-ignore:
- "*.md"
jobs:
Fuzzing:
runs-on: ubuntu-latest
steps:
- name: Build Fuzzers
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: 'exiv2'
dry-run: false
- name: Run Fuzzers
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'exiv2'
fuzz-seconds: 600
dry-run: false
- name: Upload Crash
uses: actions/upload-artifact@v4
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
path: ./out/artifacts

@ -1,73 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
name: "CodeQL"
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
on:
push:
branches: [0.28.x, main]
paths-ignore:
- "*.md"
pull_request:
# The branches below must be a subset of the branches above
branches: [0.28.x, main]
paths-ignore:
- "*.md"
workflow_dispatch:
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: [ 'cpp', 'javascript' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more...
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo eatmydata apt-get -y install libexpat1-dev zlib1g-dev libbrotli-dev libinih-dev
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
config-file: .github/codeql/codeql-config.yml
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v3
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3

@ -1,22 +0,0 @@
# This workflow was added by CodeSee. Learn more at https://codesee.io/
# This is v2.0 of this workflow file
on:
push:
branches:
- main
pull_request_target:
types: [opened, synchronize, reopened]
name: CodeSee
permissions: read-all
jobs:
codesee:
runs-on: ubuntu-22.04
continue-on-error: true
name: Analyze the repo with CodeSee
steps:
- uses: Codesee-io/codesee-action@v2
with:
codesee-token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }}

@ -1,43 +0,0 @@
on:
schedule:
- cron: 0 4 * * *
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
name: Nightly - Linux distributions
jobs:
distros:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
container_image: ["fedora", "debian", "archlinux", "ubuntu", "tgagor/centos", "alpine"]
compiler:
- { CC: gcc, CXX: g++ }
- { CC: clang, CXX: clang++ }
build_type: [Release, Debug]
shared_libraries: [ON, OFF]
container:
image: ${{ matrix.container_image }}
env:
CC: ${{ matrix.compiler.CC }}
CXX: ${{ matrix.compiler.CXX }}
CMAKE_FLAGS: -DEXIV2_TEAM_EXTRA_WARNINGS=OFF -DEXIV2_ENABLE_WEBREADY=ON -DEXIV2_ENABLE_CURL=ON -DEXIV2_BUILD_UNIT_TESTS=OFF -DEXIV2_TEAM_WARNINGS_AS_ERRORS=OFF -DCMAKE_INSTALL_PREFIX=install
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: ./ci/install_dependencies.sh
- name: Build and install
run: |
cmake -GNinja $CMAKE_FLAGS -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DBUILD_SHARED_LIBS=${{ matrix.shared_libraries }} -S . -B build
cmake --build build --parallel
cmake --install build

@ -1,40 +0,0 @@
# Builds and runs the fuzz target for a short amount of time. This is
# mainly to protect the fuzz target from bitrot, but hopefully will
# also help to quickly catch some bugs before the PR is merged.
name: On PRs - Linux-Ubuntu Quick Fuzz
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
on:
pull_request:
paths-ignore:
- "*.md"
workflow_dispatch:
jobs:
Linux:
name: 'Ubuntu 24.04 - clang/libFuzzer'
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo ./ci/install_dependencies.sh
- name: Build
env:
CC: clang
CXX: clang++
run: |
cmake --preset linux-sanitizers -S . -B build -DCMAKE_BUILD_TYPE=Release -DEXIV2_BUILD_FUZZ_TESTS=ON -DEXIV2_BUILD_UNIT_TESTS=OFF
cmake --build build --parallel
- name: Fuzz
run: |
cd build
mkdir corpus
LSAN_OPTIONS=suppressions=../fuzz/knownleaks.txt ./bin/fuzz-read-print-write corpus ../test/data/ -dict=../fuzz/exiv2.dict -jobs=$(nproc) -workers=$(nproc) -max_len=4096 -max_total_time=120

@ -1,57 +0,0 @@
name: On PRs - Linux-Ubuntu Matrix
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
on:
pull_request:
paths-ignore:
- "*.md"
jobs:
Linux:
name: 'Ubuntu 22.04 - GCC, BuildType:${{matrix.build_type}}, SHARED:${{matrix.shared_libraries}}'
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
build_type: [Release, Debug]
shared_libraries: [ON, OFF]
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt install -y tree ninja-build
python3 -m pip install conan==1.*
- name: Conan common config
run: |
conan profile new --detect default
conan profile update settings.build_type=${{matrix.build_type}} default
conan profile update settings.compiler.libcxx=libstdc++11 default
- name: Run Conan
run: |
mkdir build-base_linux && cd build-base_linux
conan profile list
conan profile show default
conan install .. -o webready=True --build missing
- name: Build
run: |
cmake --preset base_linux -S . -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DBUILD_SHARED_LIBS=${{matrix.shared_libraries}}
cmake --build build-base_linux --parallel
- name: Install
run: |
cd build-base_linux
cmake --install .
- name: Test
run: |
cd build-base_linux
ctest --output-on-failure

@ -1,187 +0,0 @@
name: On PRs - Linux Special Builds
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
on:
workflow_dispatch:
pull_request:
paths-ignore:
- "*.md"
jobs:
special_debugRelease:
name: 'Ubuntu 22.04 - GCC - Debug+Coverage'
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
# Trying to deal with warning: -> Issue detecting commit SHA. Please run actions/checkout with fetch-depth > 1 or set to 0
- name: Install dependencies
run: |
sudo eatmydata apt-get -y install libxml2-dev libxslt-dev python3-dev ninja-build gcovr
python3 -m pip install conan==1.*
- name: Conan common config
run: |
conan profile new --detect default
conan profile update settings.compiler.libcxx=libstdc++11 default
- name: Run Conan
run: |
mkdir build && cd build
conan profile list
conan profile show default
conan install .. -o webready=True --build missing
- name: Build
run: |
cmake --preset linux-coverage -S . -B build
cmake --build build --parallel
- name: Tests + Upload coverage
run: |
cd build
ctest --output-on-failure
# this needs to match th ecommand in on_push_ExtraJobsForMain.yml!
gcovr --root .. --object-dir . --exclude-unreachable-branches --exclude-throw-branches --xml -o coverage.xml
curl https://keybase.io/codecovsecurity/pgp_keys.asc | gpg --import
curl -Os https://uploader.codecov.io/latest/linux/codecov
curl -Os https://uploader.codecov.io/latest/linux/codecov.SHA256SUM
curl -Os https://uploader.codecov.io/latest/linux/codecov.SHA256SUM.sig
gpg --verify codecov.SHA256SUM.sig codecov.SHA256SUM
shasum -a 256 -c codecov.SHA256SUM
chmod +x codecov
ls -lh
./codecov -f coverage.xml
special_releaseValgrind:
name: 'Ubuntu 22.04 - GCC - Release+Valgrind'
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt install -y valgrind ninja-build
python3 -m pip install conan==1.*
- name: Conan common config
run: |
conan profile new --detect default
conan profile update settings.compiler.libcxx=libstdc++11 default
- name: Run Conan
run: |
mkdir build && cd build
conan profile list
conan profile show default
conan install .. -o webready=True --build missing
- name: Build
run: |
cmake --preset linux-release -S . -B build
cmake --build build --parallel
- name: Tests with valgrind
run: |
cd build/bin
valgrind ./unit_tests
special_releaseSanitizers:
name: 'Ubuntu 22.04 - GCC - Release+Sanitizers'
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt install -y ninja-build
python3 -m pip install conan==1.*
- name: Conan common config
run: |
conan profile new --detect default
conan profile update settings.compiler.libcxx=libstdc++11 default
- name: Run Conan
run: |
mkdir build && cd build
conan profile list
conan profile show default
conan install .. -o webready=True --build missing
- name: Build
run: |
cmake --preset linux-sanitizers -S . -B build
cmake --build build --parallel
- name: Tests
run: |
cd build
ctest --output-on-failure
special_noFilesystemAccess:
name: 'Ubuntu 22.04 - GCC - No filesystem access build'
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt install -y ninja-build
python3 -m pip install conan==1.*
- name: Conan common config
run: |
conan profile new --detect default
conan profile update settings.compiler.libcxx=libstdc++11 default
- name: Build
run: |
cmake --preset linux-release -S . -B build -DEXIV2_ENABLE_FILESYSTEM_ACCESS=OFF -DEXIV2_BUILD_SAMPLES=OFF -DEXIV2_BUILD_UNIT_TESTS=OFF -DEXIV2_BUILD_EXIV2_COMMAND=OFF
cmake --build build --parallel
special_allEnabled:
name: 'Ubuntu 22.04 - GCC - All Options Enabled + Documentation'
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt install -y valgrind doxygen graphviz gettext ninja-build
python3 -m pip install conan==1.*
- name: Conan common config
run: |
conan profile new --detect default
conan profile update settings.compiler.libcxx=libstdc++11 default
- name: Run Conan
run: |
mkdir build && cd build
conan profile list
conan profile show default
conan install .. -o webready=True --build missing
- name: Build
env:
CXXFLAGS: -DEXIV2_DEBUG_MESSAGES
run: |
cmake --preset linux-release -S . -B build -DEXIV2_BUILD_DOC=ON
cmake --build build --parallel
- name: Generate documentation
run: |
make doc

@ -1,65 +0,0 @@
name: On PRs - Linux - Static Analysis
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
on:
workflow_dispatch:
pull_request:
paths-ignore:
- "*.md"
jobs:
special_pvsStudio:
name: 'Ubuntu 22.04 - GCC - Static Analyzer: PVS-Studio'
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
# Trying to deal with warning: -> Issue detecting commit SHA. Please run actions/checkout with fetch-depth > 1 or set to 0
- name: Install dependencies
run: |
python3 -m pip install conan==1.*
sudo add-apt-repository ppa:ubuntu-lxc/daily -y
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 apt update -qq
sudo apt install -qq pvs-studio
- name: Conan common config
run: |
conan profile new --detect default
conan profile update settings.compiler.libcxx=libstdc++11 default
- name: Run Conan
run: |
mkdir build && cd build
conan profile list
conan profile show default
conan install .. -o webready=True --build missing
- name: Configure
run: |
cmake --preset linux-debug -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
- name: Static Analysis
env:
PVS_USERNAME: ${{ secrets.PVS_USERNAME }}
PVS_KEY: ${{ secrets.PVS_KEY }}
run: |
cd build
pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY -o PVS_license.lic
pvs-studio-analyzer analyze -l PVS_license.lic -o pvsStudio.log -j4 --disableLicenseExpirationCheck
plog-converter -a GA:1,2 -d V1042 -t fullhtml pvsStudio.log -o pvsReportHtml
- uses: actions/upload-artifact@v4
with:
name: static_analysis
path: build/pvsReportHtml
retention-days: 7

@ -1,42 +0,0 @@
name: On PRs - Mac Matrix
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
on:
pull_request:
paths-ignore:
- "*.md"
jobs:
MacOS:
name: 'macOS - XCode - ${{matrix.build_type}} - SHARED:${{matrix.shared_libraries}}'
runs-on: macos-latest
strategy:
fail-fast: false
matrix:
build_type: [Release, Debug]
shared_libraries: [ON, OFF]
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
brew install ninja inih googletest
- name: Build
run: |
cmake --preset base_mac -S . -B build -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DBUILD_SHARED_LIBS=${{matrix.shared_libraries}}
cmake --build build --parallel
- name: Install
run: |
cd build
cmake --install .
- name: Test
run: |
ctest --test-dir build --output-on-failure

@ -1,32 +0,0 @@
name: On PRs - Mac Special Builds
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
on:
workflow_dispatch:
pull_request:
paths-ignore:
- "*.md"
jobs:
MacOS_releaseSanitizers:
name: 'macOS - XCode - Release+Sanitizers'
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
brew install ninja inih googletest
- name: Build
run: |
cmake --preset base_mac -S . -B build -DEXIV2_TEAM_USE_SANITIZERS=ON
cmake --build build --parallel
- name: Test
run: |
ASAN_OPTIONS=detect_container_overflow=0 ctest --test-dir build --output-on-failure

@ -1,171 +0,0 @@
name: On PRs - meson
on: pull_request
concurrency:
group: ${{github.workflow}}-${{github.head_ref}}
cancel-in-progress: true
jobs:
Ubuntu:
runs-on: ubuntu-20.04
name: Linux-GCC${{matrix.cxx}}-deps=${{matrix.deps}}
strategy:
matrix:
cxx: ['7', '13']
deps: ['forcefallback', 'default']
steps:
- uses: actions/checkout@v4
- uses: egor-tensin/setup-gcc@v1
with:
version: ${{matrix.cxx}}
- name: Install meson
run: python3 -m pip install meson ninja
- name: Compile and Test
run: |
meson setup "${{github.workspace}}/build" --wrap-mode=${{matrix.deps}} -Dwarning_level=3
meson compile -C "${{github.workspace}}/build"
meson test -C "${{github.workspace}}/build"
Ubuntu-clang:
runs-on: ubuntu-20.04
name: Linux-Clang${{matrix.cxx}}-deps=${{matrix.deps}}
strategy:
matrix:
cxx: ['7', '18']
deps: ['forcefallback', 'default']
steps:
- uses: actions/checkout@v4
- uses: egor-tensin/setup-clang@v1
with:
version: ${{matrix.cxx}}
- name: Install meson
run: |
python3 -m pip install meson ninja
sudo apt install -y libc++abi-${{matrix.cxx}}-dev libc++-${{matrix.cxx}}-dev
- name: Compile and Test
env:
CXXFLAGS: -stdlib=libc++
run: |
meson setup "${{github.workspace}}/build" --wrap-mode=${{matrix.deps}} -Dwarning_level=3 -Dcpp_std=c++20
meson compile -C "${{github.workspace}}/build" --verbose
meson test -C "${{github.workspace}}/build" --verbose
VisualStudio:
runs-on: windows-latest
name: MSVC-${{matrix.deps}}-${{matrix.platform}}
strategy:
matrix:
deps: ['forcefallback', 'default']
platform: ['x64', 'x86']
steps:
- uses: actions/checkout@v4
- name: Install packages
run: |
python -m pip install meson ninja
- uses: ilammy/msvc-dev-cmd@v1
with:
arch: ${{matrix.platform}}
- name: Compile and Test
run: |
meson setup "${{github.workspace}}/build" --wrap-mode=${{matrix.deps}} -Dwarning_level=3 -Dcpp_std=c++latest -Db_sanitize=address
meson compile -C "${{github.workspace}}/build" --verbose
meson test -C "${{github.workspace}}/build" --verbose
VisualStudio-clang-cl:
runs-on: windows-latest
name: clang-cl-${{matrix.deps}}
strategy:
matrix:
deps: ['forcefallback', 'default']
steps:
- uses: actions/checkout@v4
- name: Install packages
run: |
python -m pip install meson ninja
- uses: ilammy/msvc-dev-cmd@v1
- name: Compile and Test
env:
CC: clang-cl
CXX: clang-cl
run: |
meson setup "${{github.workspace}}/build" --wrap-mode=${{matrix.deps}} -Dwarning_level=3 -Dcpp_std=c++latest -Db_sanitize=address
meson compile -C "${{github.workspace}}/build" --verbose
meson test -C "${{github.workspace}}/build" --verbose
MSYS2:
runs-on: windows-latest
name: MSYS2-${{matrix.platform}}-deps=${{matrix.deps}}
strategy:
matrix:
deps: ['enabled', 'disabled']
platform: ['UCRT64', 'CLANG64']
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v4
- uses: msys2/setup-msys2@v2
with:
msystem: ${{matrix.platform}}
pacboy: >-
cc:p
cmake:p
curl:p
gtest:p
libinih:p
meson:p
ninja:p
pkgconf:p
- name: Compile and Test
run: |
meson setup "${{github.workspace}}/build" -Dauto_features=${{matrix.deps}} -Dwarning_level=3 -Dcpp_std=c++20
meson compile -C "${{github.workspace}}/build" --verbose
meson test -C "${{github.workspace}}/build" --verbose
MacOS:
runs-on: macos-latest
name: macOS-deps=${{matrix.deps}}
strategy:
matrix:
deps: ['enabled', 'disabled']
steps:
- uses: actions/checkout@v4
- name: Install packages
run: |
brew install inih meson
- name: Compile and Test
run: |
meson setup "${{github.workspace}}/build" -Dauto_features=${{matrix.deps}} -Dwarning_level=3 -Dnls=disabled -Db_sanitize=address,undefined
meson compile -C "${{github.workspace}}/build" --verbose
meson test -C "${{github.workspace}}/build" --verbose
FreeBSD:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: vmactions/freebsd-vm@v1
with:
prepare: |
pkg install -y cmake curl ninja meson gettext pkgconf googletest expat inih brotli
run: |
meson setup "${{github.workspace}}/build" -Dwarning_level=3 -Dcpp_std=c++20
meson compile -C "${{github.workspace}}/build" --verbose
meson test -C "${{github.workspace}}/build" --verbose
Emscripten:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install packages
run: |
python3 -m pip install meson ninja
- name: Emscripten
uses: mymindstorm/setup-emsdk@v14
- name: Compile
run: |
meson setup "${{github.workspace}}/build" --cross-file="${{github.workspace}}/em.txt" --wrap-mode=forcefallback -Ddefault_library=static -Dwarning_level=3 -Dcpp_std=c++20 -DunitTests=disabled -Dcurl=disabled
meson compile -C "${{github.workspace}}/build" --verbose

@ -1,185 +0,0 @@
name: On PRs - Windows Matrix
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
on:
pull_request:
paths-ignore:
- "*.md"
workflow_dispatch:
push:
branches: [0.28.x, main]
tags:
- '!*'
paths-ignore:
- "*.md"
jobs:
windows:
name: 'Win10 Arch: ${{matrix.platform}} BuildType:${{matrix.build_type}} - SHARED:${{matrix.shared_libraries}}'
runs-on: windows-2022
strategy:
fail-fast: false
matrix:
build_type: [Release, Debug]
shared_libraries: [ON, OFF]
platform: [ x64, x86 ]
steps:
- uses: actions/checkout@v4
- name: Set up Visual Studio shell
uses: ilammy/msvc-dev-cmd@v1
with:
arch: ${{matrix.platform}}
- name: Restore Conan cache
uses: actions/cache@v4
with:
path: ${{github.workspace}}/conanCache
key: ${{runner.os}}-${{matrix.platform}}-${{matrix.build_type}}-Shared${{matrix.shared_libraries}}-${{ hashFiles('conanfile.py') }}
- name: Install Conan & Common config
run: |
python -m pip install conan==1.*
conan config install https://github.com/conan-io/conanclientcert.git
conan profile new --detect default
conan profile update settings.build_type=${{matrix.build_type}} default
conan profile update settings.compiler="Visual Studio" default
conan profile update settings.compiler.version=17 default
conan config set storage.path=$Env:GITHUB_WORKSPACE/conanCache
- name: Conan Arch conditional config
if: ${{matrix.platform == 'x86'}}
run: |
conan profile update settings.arch=x86 default
conan profile update settings.arch_build=x86 default
- name: Run Conan
run: |
md build
cd build
conan profile list
conan install .. --build missing
- name: Build
run: |
cmake --preset base_windows -S . -B build -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DBUILD_SHARED_LIBS=${{matrix.shared_libraries}}
cmake --build build --parallel
- name: Install
run: |
cmake --install build
- name: Test
run: |
ctest --test-dir build --output-on-failure
msys2:
runs-on: windows-latest
timeout-minutes: 40
strategy:
fail-fast: false
matrix:
build_type: [Release, Debug]
shared_libraries: [ON, OFF]
sys: [UCRT64]
name: MSYS2 ${{matrix.sys}} - BuildType:${{matrix.build_type}} - SHARED:${{matrix.shared_libraries}}
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v4
- name: Set up MSYS2
uses: msys2/setup-msys2@v2
with:
path-type: strict
msystem: ${{matrix.sys}}
update: true
pacboy: >-
cc:p
gcc-libs:p
libwinpthread:p
cmake:p
ninja:p
python:p
gtest:p
brotli:p
curl:p
expat:p
libiconv:p
libinih:p
zlib:p
- name: Build
run: |
cmake --preset base_windows \
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
-DBUILD_SHARED_LIBS=${{matrix.shared_libraries}} \
-DCONAN_AUTO_INSTALL=OFF \
-DEXIV2_TEAM_WARNINGS_AS_ERRORS=OFF \
-DPython3_EXECUTABLE=${MINGW_PREFIX}/bin/python.exe \
-S . -B build && \
cmake --build build --parallel
- name: Test
run: |
ctest --test-dir build --output-on-failure
cygwin:
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
build_type: [Release]
shared_libraries: [ON]
platform: [x86_64]
name: Cygwin ${{matrix.platform}} - BuildType:${{matrix.build_type}} - SHARED:${{matrix.shared_libraries}}
env:
SHELLOPTS: igncr
defaults:
run:
shell: C:\cygwin\bin\bash.exe -eo pipefail '{0}'
steps:
# Make sure we don't check out scripts using Windows CRLF line endings
- run: git config --global core.autocrlf input
shell: pwsh
- uses: actions/checkout@v4
- name: Set up Cygwin
uses: cygwin/cygwin-install-action@v4
with:
platform: ${{matrix.platform}}
packages: >-
gcc-g++
cmake
ninja
pkg-config
python3
libbrotli-devel
libcurl-devel
libexpat-devel
libiconv-devel
libinih-devel
zlib-devel
- name: Build
run: |
cmake --preset base_windows \
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
-DBUILD_SHARED_LIBS=${{matrix.shared_libraries}} \
-DCONAN_AUTO_INSTALL=OFF \
-DEXIV2_BUILD_SAMPLES=OFF \
-DEXIV2_BUILD_UNIT_TESTS=OFF \
-DEXIV2_TEAM_WARNINGS_AS_ERRORS=OFF \
-S . -B build && \
cmake --build build --parallel
- name: Test
run: |
ctest --test-dir build --output-on-failure

@ -1,106 +0,0 @@
# Basic CI for all platforms on push
# Note that we want to run this as fast as possible and just for the more common configurations. On
# PRs, we will test things more intensively :)
# - Only running UnitTests and not regression tests
on:
push:
paths-ignore:
- "*.md"
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
name: On PUSH - Basic CI for main platforms
jobs:
windows:
name: 'Windows 10 - MSVC - Arch:X64 BuildType:Release - SHARED'
runs-on: windows-2022
steps:
- uses: actions/checkout@v4
- name: Set up Visual Studio shell
uses: ilammy/msvc-dev-cmd@v1
with:
arch: x64
- name: Restore Conan cache
uses: actions/cache@v4
with:
path: ${{github.workspace}}/conanCache
key: ${{runner.os}}-push-win-${{ hashFiles('conanfile.py') }}
- name: Install Conan & Common config
run: |
python -m pip install conan==1.*
conan profile new --detect default
conan profile show default
conan profile update settings.compiler="Visual Studio" default
conan profile update settings.compiler.version=17 default
conan config set storage.path=$Env:GITHUB_WORKSPACE/conanCache
- name: Build
run: |
cmake --preset win-release -S . -B build
cmake --build build --parallel
- name: Test
run: |
ctest --test-dir build --output-on-failure
Linux:
name: 'Ubuntu 22.04 - GCC - Arch:X64 BuildType:Release - SHARED'
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo eatmydata apt-get -y install ninja-build
python3 -m pip install conan==1.*
- name: Conan
run: |
mkdir build && cd build
conan profile new --detect default
conan profile update settings.compiler.libcxx=libstdc++11 default
conan profile show default
conan install .. -o webready=True --build missing
- name: Build
run: |
cmake --preset linux-release -S . -B build
cmake --build build --parallel
- name: Test
run: |
ctest --test-dir build --output-on-failure
MacOS:
name: 'macOS - XCode - Arch:${{ matrix.runner.arch }} BuildType:Release - SHARED'
runs-on: ${{ matrix.runner.os }}
strategy:
matrix:
runner:
- { os: macos-12, arch: X64 }
- { os: macos-14, arch: ARM64 }
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
brew install ninja inih googletest
- name: Build
run: |
cmake --preset base_mac -S . -B build
cmake --build build --parallel
- name: Test
run: |
ctest --test-dir build --output-on-failure

@ -1,60 +0,0 @@
name: On PUSH - Linux Special Builds for main branch
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
on:
push:
branches:
- main
tags:
- '!*'
paths-ignore:
- "*.md"
workflow_dispatch:
jobs:
special_debugRelease:
name: 'Ubuntu 22.04 - GCC - Debug+Coverage'
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo eatmydata apt-get -y install ninja-build gcovr
python3 -m pip install conan==1.*
- name: Conan common config
run: |
conan profile new --detect default
conan profile update settings.compiler.libcxx=libstdc++11 default
- name: Run Conan
run: |
mkdir build && cd build
conan profile list
conan profile show default
conan install .. -o webready=True --build missing
- name: Build
run: |
cmake --preset linux-coverage -S . -B build
cmake --build build
- name: Tests + Upload coverage
run: |
cd build
ctest --output-on-failure
# this needs to match th ecommand in on_PR_linux_secial_builds.yml!
gcovr --root .. --object-dir . --exclude-unreachable-branches --exclude-throw-branches --xml -o coverage.xml .
curl https://keybase.io/codecovsecurity/pgp_keys.asc | gpg --import
curl -Os https://uploader.codecov.io/latest/linux/codecov
curl -Os https://uploader.codecov.io/latest/linux/codecov.SHA256SUM
curl -Os https://uploader.codecov.io/latest/linux/codecov.SHA256SUM.sig
gpg --verify codecov.SHA256SUM.sig codecov.SHA256SUM
shasum -a 256 -c codecov.SHA256SUM
chmod +x codecov
./codecov -f build/coverage.xml

@ -1,16 +0,0 @@
name: Clang Format Checker
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
on: [push, pull_request]
jobs:
clang-format-checking:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: DoozyX/clang-format-lint-action@v0.17
with:
source: '.'
exclude: './xmpsdk ./contrib'
extensions: 'c,h,cpp,hpp'
style: file

@ -1,227 +0,0 @@
name: Release
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
on:
push:
tags:
- v[0-9]+.[0-9]+.[0-9]+
schedule:
- cron: '30 4 * * *'
workflow_dispatch:
inputs:
tag_name:
description: 'Tag name for release'
required: false
default: nightly
jobs:
Linux:
name: 'Build Linux Release'
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt install -y gettext doxygen graphviz ninja-build
python -m pip install conan==1.*
- name: Conan common config
run: |
conan profile new --detect default
conan profile update settings.build_type=Release default
conan profile update settings.compiler.libcxx=libstdc++11 default
- name: Run Conan
run: |
mkdir build && cd build
conan profile list
conan profile show default
conan install .. -o webready=False --build missing
- name: Build packaged release
run: |
cmake --preset linux-all -S . -B build -DEXIV2_TEAM_PACKAGING=ON -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DEXIV2_ENABLE_WEBREADY=OFF -DEXIV2_ENABLE_CURL=OFF -DEXIV2_BUILD_SAMPLES=OFF
cmake --build build -t doc
cmake --build build -t package
- uses: actions/upload-artifact@v4
with:
name: exiv2-linux64
path: ./build/exiv2-*.tar.gz
if-no-files-found: error
retention-days: 1
macOS:
name: 'Build macOS Release'
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
brew install ninja
brew install inih
brew install tree
brew install gettext
brew install doxygen
brew install graphviz
- name: Build packaged release
run: |
mkdir build
cmake -GNinja -S . -B build \
-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 \
-DEXIV2_BUILD_DOC=ON \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON
cmake --build build -t doc
cmake --build build -t package
- uses: actions/upload-artifact@v4
with:
name: exiv2-macos
path: ./build/exiv2-*.tar.gz
if-no-files-found: error
retention-days: 1
Windows:
name: 'Build Windows Release'
runs-on: windows-2022
steps:
- uses: actions/checkout@v4
- name: Set up Visual Studio shell
uses: ilammy/msvc-dev-cmd@v1
- name: Install doxygen
run: |
choco install doxygen.install
choco install graphviz
- name: Restore conan cache
uses: actions/cache@v4
with:
path: ${{github.workspace}}/conanCache
key: ${{runner.os}}-release-win-${{ hashFiles('conanfile.py') }}
- name: Install Conan & Common config
run: |
python -m pip install conan==1.*
conan profile new --detect default
conan profile show default
conan profile update settings.build_type=Release default
conan profile update settings.compiler="Visual Studio" default
conan profile update settings.compiler.version=17 default
conan config set storage.path=$Env:GITHUB_WORKSPACE/conanCache
- name: Run Conan
run: |
md build
cd build
conan install .. --build missing
- name: Build packaged release
run: |
cmake --preset win-release -S . -B build -DEXIV2_TEAM_PACKAGING=ON -DEXIV2_BUILD_DOC=ON -DEXIV2_ENABLE_WEBREADY=OFF -DEXIV2_ENABLE_CURL=OFF -DEXIV2_BUILD_SAMPLES=OFF
cmake --build build --parallel -t doc
cmake --build build --parallel -t package
- uses: actions/upload-artifact@v4
with:
name: exiv2-win
path: ./build/exiv2-*.zip
if-no-files-found: error
retention-days: 1
publish:
needs: [Linux, macOS, Windows]
runs-on: ubuntu-22.04
permissions:
contents: write
steps:
- if: github.event_name == 'workflow_dispatch'
run: echo "TAG_NAME=${{ github.event.inputs.tag_name }}" >> $GITHUB_ENV
- if: github.event_name == 'schedule'
run: echo 'TAG_NAME=nightly' >> $GITHUB_ENV
- if: github.event_name == 'push'
run: |
TAG_NAME=${{ github.ref }}
echo "TAG_NAME=${TAG_NAME#refs/tags/}" >> $GITHUB_ENV
- if: env.TAG_NAME == 'nightly'
run: |
echo 'BODY<<EOF' >> $GITHUB_ENV
echo '## Exiv2 nightly prerelease build.' >> $GITHUB_ENV
echo 'Please help us improve exiv2 by reporting any issues you encounter :wink:' >> $GITHUB_ENV
echo 'EOF' >> $GITHUB_ENV
- if: env.TAG_NAME != 'nightly'
run: |
echo 'BODY<<EOF' >> $GITHUB_ENV
echo '## Exiv2 Release ${{ env.TAG_NAME }}' >> $GITHUB_ENV
echo 'See [ChangeLog](doc/ChangeLog) for more information about the changes in this release.' >> $GITHUB_ENV
echo 'EOF' >> $GITHUB_ENV
- name: Cleanup old nightly
if: env.TAG_NAME == 'nightly'
uses: actions/github-script@v7
with:
script: |
try{
const rel_id = await github.rest.repos.getReleaseByTag({
...context.repo,
tag: "nightly"
}).then(result => result.data.id);
console.log( "Found existing nightly release with id: ", rel_id);
await github.rest.repos.deleteRelease({
...context.repo,
release_id: rel_id
});
console.log( "Deletion of release successful")
}catch(error){
console.log( "Deletion of release failed");
console.log( "Failed with error\n", error);
}
try{
await github.rest.git.deleteRef({
...context.repo,
ref: "tags/nightly"
});
console.log( "Deletion of tag successful")
}catch(error){
console.log( "Deletion of tag failed");
console.log( "Failed with error\n", error);
}
- uses: actions/download-artifact@v4
- name: List downloaded files
run: tree -L 3
- uses: softprops/action-gh-release@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
# needs newer relase, but add it once available
#fail_on_unmatched_files: true
body: ${{ env.BODY }}
prerelease: ${{ env.TAG_NAME == 'nightly' }}
tag_name: ${{ env.TAG_NAME }}
files: |
./exiv2-linux64/exiv2-*
./exiv2-macos/exiv2-*
./exiv2-win/exiv2-*

7
.gitignore vendored

@ -15,7 +15,6 @@ xcode_build*
msvc_build*
cygwin_build*
mingw_build*
linux_build*
po/POTFILES
po/remove-potcdate.sed
po/stamp-po
@ -23,9 +22,3 @@ src/doxygen.hpp
test/tmp/*
doc/html
contrib/vms/.vagrant
/.vscode
.vs/
CMakeUserPresets.json
*cppcheck*
subprojects/packagecache

@ -0,0 +1,99 @@
# all builds use the same ccache folder in the project root that is cached
variables:
CCACHE_BASEDIR: '$CI_PROJECT_DIR'
CCACHE_DIR: '$CI_PROJECT_DIR/ccache'
# default config for all distros:
# - install dependencies via script
# - create ccache dir & setup caching of it (for each job separately)
.build_config: &default_config
before_script:
- ci/install_dependencies.sh
- mkdir -p ccache
cache:
key: "$CI_JOB_NAME"
paths:
- ccache/
# default build job:
# - run build script
# - only create artifacts of the build directory when something fails
# (for cmake logs)
.build_template: &distro_build
script:
- python3 ci/test_build.py
artifacts:
when: on_failure
paths:
- build/
stages:
- test
- deploy
Fedora:
image: fedora:latest
<<: *default_config
<<: *distro_build
Fedora_MinGW:
image: fedora:latest
before_script:
- dnf -y upgrade
- dnf -y install mingw64-gcc-c++ mingw64-filesystem mingw64-expat mingw64-zlib cmake make
script:
- python3 ci/test_build.py --without-tests --cmake-executable "mingw64-cmake" --cmake-options "-DEXIV2_TEAM_EXTRA_WARNINGS=ON -DEXIV2_ENABLE_VIDEO=ON -DEXIV2_ENABLE_WEBREADY=ON -DEXIV2_ENABLE_WIN_UNICODE=ON " --compilers --shared-libs OFF
Debian:
image: debian:9
<<: *default_config
<<: *distro_build
Archlinux:
image: archlinux/base
<<: *default_config
<<: *distro_build
Ubuntu:
image: ubuntu:18.04
<<: *default_config
<<: *distro_build
CentOS:
image: centos:7
<<: *default_config
<<: *distro_build
OpenSUSE:
image: opensuse/tumbleweed
<<: *default_config
<<: *distro_build
Install:
image: fedora:latest
stage: deploy
<<: *default_config
script:
- mkdir build && cd build
- cmake -DCMAKE_BUILD_TYPE=Release -DEXIV2_ENABLE_VIDEO=ON -DEXIV2_ENABLE_WEBREADY=ON -DEXIV2_BUILD_UNIT_TESTS=ON -DCMAKE_INSTALL_PREFIX=/usr/ -DBUILD_WITH_CCACHE=ON ..
- make -j $(nproc)
- make install
- make clean
- EXIV2_BINDIR=/usr/bin/ make tests
pages:
image: fedora:latest
stage: deploy
<<: *default_config
script:
- dnf -y install doxygen graphviz
- mkdir build && cd build
- cmake -DCMAKE_BUILD_TYPE=Release -DEXIV2_ENABLE_VIDEO=ON -DEXIV2_ENABLE_WEBREADY=ON -DEXIV2_BUILD_DOC=ON ..
- make doc
- cd ..
- mv build/doc/html/ public/
artifacts:
paths:
- public
only:
- master

@ -1,23 +0,0 @@
pull_request_rules:
- name: forward patches to main branch
conditions:
- base=0.28.x
- label=forward-to-main
actions:
backport:
branches:
- main
assignees:
- "{{ author }}"
- name: delete head branch after merge
conditions:
- merged
actions:
delete_head_branch: {}
- name: remove outdated reviews
conditions: []
actions:
dismiss_reviews:
changes_requested: False

@ -1 +0,0 @@
//-V::1042

@ -0,0 +1,41 @@
language: cpp
git:
quiet: true
depth: 1
matrix:
include:
- os: linux
dist: xenial
sudo: required
compiler: gcc
env: COVERAGE=1 CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Debug -DEXIV2_ENABLE_VIDEO=ON -DEXIV2_ENABLE_WEBREADY=ON -DEXIV2_BUILD_UNIT_TESTS=ON -DBUILD_WITH_COVERAGE=ON -DEXIV2_ENABLE_CURL=ON -DCMAKE_CXX_STANDARD=98"
- os: linux
dist: xenial
sudo: required
compiler: gcc
env:
- WITH_VALGRIND=1
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release -DEXIV2_ENABLE_VIDEO=ON -DEXIV2_ENABLE_WEBREADY=ON -DEXIV2_BUILD_UNIT_TESTS=ON -DEXIV2_ENABLE_CURL=ON -DCMAKE_CXX_STANDARD=98"
- os: linux
dist: xenial
sudo: required
compiler: clang
env: CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release -DEXIV2_ENABLE_VIDEO=ON -DEXIV2_ENABLE_WEBREADY=ON -DEXIV2_BUILD_UNIT_TESTS=ON -DEXIV2_ENABLE_CURL=ON -DCMAKE_CXX_STANDARD=98"
- os: osx
osx_image: xcode11.3
compiler: clang
env: CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release -DEXIV2_ENABLE_VIDEO=ON -DEXIV2_ENABLE_WEBREADY=ON -DEXIV2_BUILD_UNIT_TESTS=ON -DEXIV2_ENABLE_NLS=OFF -DEXIV2_ENABLE_CURL=ON -DCMAKE_CXX_STANDARD=98"
install: ./ci/install.sh
script: ./ci/run.sh
cache:
ccache: true
directories:
- conan # Conan installation folder
- $HOME/conanData # Conan storage location

@ -1,197 +1,152 @@
# Minimum version imposed by Ubuntu:20.04
cmake_minimum_required(VERSION 3.16.3)
# use TWEAK to categorize the build:
#
# * 1.00.0 = GM (tagged and released)
# * 1.00.0.9 = 1.00.0 Development
# * 1.00.0.00 = GM Preview
# * 1.00.0.2 = RC2 (tagged and released)
# * 1.00.0.20 = RC2 Preview
# * 1.00.0.29 = RC2 Development
#
project(
exiv2
VERSION 1.00.0.9
DESCRIPTION "Exif/IPTC/Xmp C++ metadata library and tools plus ICC Profiles, Previews and more."
LANGUAGES C CXX
cmake_minimum_required( VERSION 3.3.2 )
project(exiv2 # use TWEAK to categorize the build
VERSION 0.27.3 # 0.27.3 = GM
# 0.27.3.00 = GM Preview
# 0.27.3.09 = Not For Release
# 0.27.3.2 = RC2
# 0.27.3.20 = RC2 Preview
# 0.27.3.29 = RC2 Not for release
LANGUAGES CXX C
)
set(CMAKE_CXX_STANDARD 14)
# Shared Object versioning (SemVer-like: must bump major on API breakage)
if(PROJECT_VERSION_MAJOR EQUAL 0)
# support legacy scheme (e.g. 0.27.x -> 27)
set(EXIV2LIB_SOVERSION ${PROJECT_VERSION_MINOR})
else()
# restart from 30
math(EXPR EXIV2LIB_SOVERSION "30 + (${PROJECT_VERSION_MAJOR} - 1)")
endif()
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
include(cmake/mainSetup.cmake REQUIRED)
include(cmake/mainSetup.cmake)
# options and their default values
option(BUILD_SHARED_LIBS "Build exiv2lib as a shared library" ON)
option(EXIV2_ENABLE_XMP "Build with XMP metadata support" ON)
option(EXIV2_ENABLE_EXTERNAL_XMP "Use external version of XMP" OFF)
option(EXIV2_ENABLE_PNG "Build with PNG support (requires zlib)" ON)
option(EXIV2_ENABLE_NLS "Build native language support (requires gettext)" OFF)
option(EXIV2_ENABLE_LENSDATA "Build including Nikon lens data" ON)
option(EXIV2_ENABLE_DYNAMIC_RUNTIME "Use dynamic runtime (used for static libs)" ON)
option(EXIV2_ENABLE_WEBREADY "Build webready support into library" OFF)
option(EXIV2_ENABLE_CURL "Use libcurl for HttpIo (WEBREADY)" OFF)
option(EXIV2_ENABLE_BMFF "Build with BMFF support" ON)
option(EXIV2_ENABLE_BROTLI "Use Brotli for JPEG XL compressed boxes (BMFF)" ON)
option(EXIV2_ENABLE_VIDEO "Build with video support" ON)
option(EXIV2_ENABLE_INIH "Use inih library" ON)
option(EXIV2_ENABLE_FILESYSTEM_ACCESS "Build with filesystem access" ON)
option(EXIV2_BUILD_SAMPLES "Build sample applications" OFF)
option(EXIV2_BUILD_EXIV2_COMMAND "Build exiv2 command-line executable" ON)
option(EXIV2_BUILD_UNIT_TESTS "Build unit tests" OFF)
option(EXIV2_BUILD_FUZZ_TESTS "Build fuzz tests (libFuzzer)" OFF)
option(EXIV2_BUILD_DOC "Add 'doc' target to generate documentation" OFF)
option( BUILD_SHARED_LIBS "Build exiv2lib as a shared library" ON )
option( EXIV2_ENABLE_XMP "Build with XMP metadata support" ON )
option( EXIV2_ENABLE_EXTERNAL_XMP "Use external version of XMP" OFF )
option( EXIV2_ENABLE_PNG "Build with png support (requires libz)" ON )
option( EXIV2_ENABLE_NLS "Build native language support (requires gettext)" OFF )
option( EXIV2_ENABLE_PRINTUCS2 "Build with Printucs2" ON )
option( EXIV2_ENABLE_LENSDATA "Build including lens data" ON )
option( EXIV2_ENABLE_VIDEO "Build video support into library" OFF )
option( EXIV2_ENABLE_DYNAMIC_RUNTIME "Use dynamic runtime (used for static libs)" ON )
option( EXIV2_ENABLE_WIN_UNICODE "Use Unicode paths (wstring) on Windows" OFF )
option( EXIV2_ENABLE_WEBREADY "Build webready support into library" OFF )
option( EXIV2_ENABLE_CURL "USE Libcurl for HttpIo (WEBREADY)" OFF )
option( EXIV2_ENABLE_SSH "USE Libssh for SshIo (WEBREADY)" OFF )
option( EXIV2_BUILD_SAMPLES "Build sample applications" ON )
option( EXIV2_BUILD_EXIV2_COMMAND "Build exiv2 command-line executable" ON )
option( EXIV2_BUILD_UNIT_TESTS "Build unit tests" OFF )
option( EXIV2_BUILD_DOC "Add 'doc' target to generate documentation" OFF )
# Only intended to be used by Exiv2 developers/contributors
option(EXIV2_TEAM_EXTRA_WARNINGS "Add more sanity checks using compiler flags" OFF)
option(EXIV2_TEAM_WARNINGS_AS_ERRORS "Treat warnings as errors" OFF)
option(EXIV2_TEAM_USE_SANITIZERS "Enable ASAN and UBSAN when available" OFF)
# The EXIV2_TEAM_OSS_FUZZ option is used by the OSS-Fuzz build script:
#
# * https://github.com/google/oss-fuzz/tree/master/projects/exiv2/build.sh
#
option(EXIV2_TEAM_OSS_FUZZ "Build config for OSS-Fuzz" OFF)
option(EXIV2_TEAM_PACKAGING "Additional stuff for generating packages" OFF)
option( EXIV2_TEAM_EXTRA_WARNINGS "Add more sanity checks using compiler flags" OFF )
option( EXIV2_TEAM_WARNINGS_AS_ERRORS "Treat warnings as errors" OFF )
option( EXIV2_TEAM_USE_SANITIZERS "Enable ASAN and UBSAN when available" OFF )
option( EXIV2_TEAM_PACKAGING "Additional stuff for generating packages" OFF )
set(EXTRA_COMPILE_FLAGS " ")
mark_as_advanced(EXIV2_TEAM_EXTRA_WARNINGS EXIV2_TEAM_WARNINGS_AS_ERRORS EXIV2_ENABLE_EXTERNAL_XMP EXTRA_COMPILE_FLAGS EXIV2_TEAM_USE_SANITIZERS)
mark_as_advanced(
EXIV2_TEAM_EXTRA_WARNINGS
EXIV2_TEAM_WARNINGS_AS_ERRORS
EXIV2_ENABLE_EXTERNAL_XMP
EXTRA_COMPILE_FLAGS
EXIV2_TEAM_USE_SANITIZERS
)
option(BUILD_WITH_STACK_PROTECTOR "Build with stack protector" ON)
option(BUILD_WITH_CCACHE "Use ccache to speed up compilations" OFF)
option(BUILD_WITH_COVERAGE "Add compiler flags to generate coverage stats" OFF)
include(cmake/gcovr.cmake REQUIRED)
option( BUILD_WITH_CCACHE "Use ccache to speed up compilations" OFF )
option( BUILD_WITH_COVERAGE "Add compiler flags to generate coverage stats" OFF )
set(PACKAGE_URL "https://exiv2.org")
set( PACKAGE_BUGREPORT "http://github.com/exiv2/exiv2" )
set( PACKAGE_URL "http://exiv2.dyndns.org")
set( PROJECT_DESCRIPTION "Exif and IPTC metadata library and tools")
if(EXIV2_ENABLE_EXTERNAL_XMP)
set(EXIV2_ENABLE_XMP OFF)
if ( EXIV2_ENABLE_EXTERNAL_XMP )
set(EXIV2_ENABLE_XMP OFF)
endif()
include(cmake/findDependencies.cmake REQUIRED)
include(cmake/compilerFlags.cmake REQUIRED)
if( EXIV2_BUILD_UNIT_TESTS )
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) # Requires CMake 3.3.3
endif()
include(cmake/findDependencies.cmake REQUIRED)
include(cmake/compilerFlags.cmake REQUIRED)
include(cmake/generateConfigFile.cmake REQUIRED)
if(EXIV2_BUILD_DOC)
include(cmake/generateDoc.cmake REQUIRED)
generate_documentation("${PROJECT_SOURCE_DIR}/cmake/Doxyfile.in")
if (EXIV2_BUILD_DOC)
include(cmake/generateDoc.cmake REQUIRED)
generate_documentation("${PROJECT_SOURCE_DIR}/cmake/Doxyfile.in")
endif()
include_directories(${CMAKE_BINARY_DIR}) # Make the exv_conf.h file visible for the full project
if(EXIV2_ENABLE_XMP)
add_subdirectory(xmpsdk)
include_directories(${CMAKE_BINARY_DIR}) # Make the exv_conf.h file visible for the full project
if( EXIV2_ENABLE_XMP )
add_subdirectory( xmpsdk )
endif()
include(cmake/compilerFlagsExiv2.cmake REQUIRED)
add_subdirectory(src)
if(BUILD_TESTING AND EXIV2_BUILD_UNIT_TESTS)
set(EXIV2_ENABLE_FILESYSTEM_ACCESS ON)
add_subdirectory(unitTests)
endif()
add_subdirectory( include )
add_subdirectory( src )
if(EXIV2_BUILD_FUZZ_TESTS)
set(EXIV2_ENABLE_FILESYSTEM_ACCESS ON)
add_subdirectory(fuzz)
if( EXIV2_BUILD_UNIT_TESTS )
add_subdirectory ( unitTests )
add_custom_target(unit_test
COMMAND env EXIV2_BINDIR="${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" make unit_test
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test"
)
endif()
if(EXIV2_BUILD_EXIV2_COMMAND)
add_subdirectory(app)
set(EXIV2_ENABLE_FILESYSTEM_ACCESS ON)
if(EXIV2_BUILD_SAMPLES)
add_subdirectory(samples)
set(EXIV2_ENABLE_FILESYSTEM_ACCESS ON)
get_directory_property(SAMPLES DIRECTORY samples DEFINITION APPLICATIONS)
add_custom_target(version_test
COMMAND env EXIV2_BINDIR="${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" make version_test
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test"
)
if(BUILD_TESTING AND Python3_Interpreter_FOUND)
add_test(
NAME bashTests
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests
COMMAND cmake -E env EXIV2_BINDIR=${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${Python3_EXECUTABLE} runner.py --verbose bash_tests
)
if( EXIV2_BUILD_SAMPLES )
##
# tests
if( EXIV2_BUILD_UNIT_TESTS )
add_custom_target(tests
COMMAND env EXIV2_BINDIR="${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" make unit_test
COMMAND env EXIV2_BINDIR="${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" make bash_tests
COMMAND env EXIV2_BINDIR="${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" make python_tests
COMMAND env EXIV2_BINDIR="${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" make version_test
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test"
)
else()
add_custom_target(tests
COMMAND env EXIV2_BINDIR="${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" make bash_tests
COMMAND env EXIV2_BINDIR="${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" make python_tests
COMMAND env EXIV2_BINDIR="${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" make version_test
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test"
)
endif()
endif()
if(BUILD_TESTING AND Python3_Interpreter_FOUND)
add_test(
NAME bugfixTests
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests
COMMAND cmake -E env EXIV2_BINDIR=${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${Python3_EXECUTABLE} runner.py --verbose bugfixes
)
add_test(
NAME lensTests
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests
COMMAND cmake -E env EXIV2_BINDIR=${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${Python3_EXECUTABLE} runner.py --verbose lens_tests
)
# Repeat lens test with a DE locale that uses "," as float delimiter
# to check that all float conversions are done independently of locale
# See GitHub issue #2746
add_test(
NAME lensTestsLocaleDE
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests
COMMAND cmake -E env LC_ALL=de_DE.UTF-8 EXIV2_BINDIR=${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${Python3_EXECUTABLE} runner.py --verbose lens_tests
)
add_test(
NAME tiffTests
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests
COMMAND cmake -E env EXIV2_BINDIR=${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${Python3_EXECUTABLE} runner.py --verbose tiff_test
)
add_test(
NAME versionTests
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests
COMMAND cmake -E env EXIV2_BINDIR=${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${Python3_EXECUTABLE} runner.py --verbose bash_tests/version_test.py
)
add_test(
NAME regressionTests
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests
COMMAND cmake -E env EXIV2_BINDIR=${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${Python3_EXECUTABLE} runner.py --verbose regression_tests
)
endif()
add_custom_target(python_tests
COMMAND env EXIV2_BINDIR="${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" make python_tests
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test"
)
add_custom_target(bash_tests
COMMAND env EXIV2_BINDIR="${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" make bash_tests
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test"
)
add_subdirectory( samples )
get_directory_property(SAMPLES DIRECTORY samples DEFINITION APPLICATIONS)
add_dependencies(tests exiv2lib exiv2 ${SAMPLES})
endif()
if(EXIV2_ENABLE_NLS)
add_subdirectory(po)
if( EXIV2_ENABLE_NLS )
add_subdirectory( po )
endif()
if(EXIV2_TEAM_PACKAGING)
include(cmake/packaging.cmake)
if (EXIV2_TEAM_PACKAGING)
include(cmake/packaging.cmake)
endif()
# Handle both relative and absolute paths (e.g. NixOS) for a relocatable package
if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}")
set(EXIV2_LIBDIR "${CMAKE_INSTALL_LIBDIR}")
else()
join_paths(EXIV2_LIBDIR "\${exec_prefix}" "${CMAKE_INSTALL_LIBDIR}")
endif()
if(IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}")
set(EXIV2_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}")
else()
join_paths(EXIV2_INCLUDEDIR "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
endif()
configure_file(cmake/exiv2.pc.in exiv2.pc @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/exiv2.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
# ******************************************************************************
# Man page
install(FILES ${PROJECT_SOURCE_DIR}/man/man1/exiv2.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
install( FILES ${PROJECT_SOURCE_DIR}/man/man1/exiv2.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 )
include(cmake/printSummary.cmake)
# That's all Folks!
#
##

@ -1,151 +0,0 @@
{
"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,
"EXIV2_ENABLE_VIDEO": true
}
},
{
"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": "matches",
"string": "${hostSystemName}",
"regex": "Windows|CYGWIN.*|MSYS.*"
}
},
{
"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_ENABLE_VIDEO": false,
"EXIV2_BUILD_DOC": true
}
}
]
}

@ -18,7 +18,7 @@ Coding Guidelines
- All new code that is added must be resistant to integer overflows, thus if you multiply, add, subtract, divide or bitshift integers you must ensure that no overflow can occur. Please keep in mind that signed integer overflow is undefined behavior, thus you must check for overflows before performing the arithmetic operation, otherwise the compiler is free to optimize your check after the overflow away (this has happened already).
- All new code must be resistant to buffer overflows. Thus before you access arrays a range check must be performed.
- Distrust any data that you extract from images or from external sources. E.g. if the metadata of an image gives you an offset of another information inside that file, do not assume that this offset will not result in an out off bounds read.
- New code must not assume the endianness and the word size of the system it is being run on. I.e. don't assume that `sizeof(int) = 8` or that the following will work:
- New code must not assume the endianes and the word size of the system it is being run on. I.e. don't assume that `sizeof(int) = 8` or that the following will work:
```cpp
const uint32_t some_var = get_var();
const uint16_t lower_2_bytes = (const uint16_t*) &some_var;

@ -17,7 +17,7 @@ We welcome any help, for example contributing lens data (images), code contribut
Code contributions can be performed via *pull requests* (PR) on GitHub (if you cannot or do not want to use GitHub, see [3. Contributing code via email](#3-contributing-code-via-email)).
For this to work you first need to [create a user account on GitHub](https://help.github.com/articles/signing-up-for-a-new-github-account/) if you don't already have one.
A pull request should preferable contain only one new feature, bug fix, etc. Since it is not uncommon to work on several PRs at the same time
A pull request should preferable contain only one new feature or bug fix etc. Since it is not uncommon to work on several PRs at the same time
it is recommended to create a new _branch_ for each PR. In this way PRs can easily be separated and the review and merge process becomes cleaner.
As a rule-of-thumb:
@ -31,7 +31,7 @@ As a rule-of-thumb:
See the [GIT_GUIDELINES.md](git_guidelines.md) file for a more detailed description of the git workflow.
Below we outline the recommended steps in the code contribution workflow. We use `your-username` to refer to your username on GitHub, `exiv2_upstream` is used when we
set the upstream remote repository for Exiv2 (we could have picked any name but try to avoid already used names like, in particular, `origin` and `main`), and
set the upstream remote repository for Exiv2 (we could have picked any name by try to avoid already used names like, in particular, `origin` and `master`), and
we use the name `my-new-feature` for the branch that we create (e.g., the branch name should reflect the code change being made).
**Important**: If your PR lives for a long time, then don't press the button _Update branch_ in the Pull Request view, instead follow the steps below, as
@ -59,38 +59,34 @@ Once you have a GitHub login:
origin https://github.com/your-username/exiv2.git (fetch)
origin https://github.com/your-username/exiv2.git (push)
4. Next, create a branch for your PR from `exiv2_upstream/main` (which we also need to fetch first):
4. Next, create a branch for your PR from `exiv2_upstream/master` (which we also need to fetch first):
$ git fetch exiv2_upstream main
$ git checkout -b my-new-feature exiv2_upstream/main --no-track
$ git fetch exiv2_upstream master
$ git checkout -b my-new-feature exiv2_upstream/master --no-track
NB: This is an important step to avoid dragging in old commits!
NB: This is an important step to avoid draging in old commits!
5. Configure the project and check that it builds (if not, please report a bug):
$ rm -rf build
$ cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
$ cmake --build build --parallel
$ mkdir build && cd build
$ cmake -DCMAKE_BUILD_TYPE=Release ..
$ make
6. Now, make your change(s), add tests for your changes, and commit each change:
...
$ git commit -m "Commit message 1"
...
$ git commit -m "Commit message 2"
Please keep in mind that the project has a Continuous Integration job to check that your new code is satisfying the
format defined in the file `.clang-format`. Use your preferred text editor, IDE or method to make sure your code is
properly formatted before creating the PR.
...
Note: You can use the script `contrib/scripts/clangFormatWholeProject.sh` to format the whole project.
$ git commit -m "Commit message 2"
7. Make sure the tests pass:
$ ctest
$ make tests # Integration tests
$./bin/unit_tests # Unit tests
Exiv2's (new) test system is described in more detail in the [doc.md](tests/doc.md) and [writing_tests.md](tests/writing_tests.md) files, and a description of the old
test system can be found in the Redmine wiki: [How do I run the test suite for Exiv2](http://dev.exiv2.org/projects/exiv2/wiki/How_do_I_run_the_test_suite_for_Exiv2)
@ -111,9 +107,9 @@ Once you have a GitHub login:
$ git checkout my-new-feature
And rebase it on top of main:
And rebase it on top of master:
$ git pull --rebase exiv2_upstream main
$ git pull --rebase exiv2_upstream master
When you perform a rebase the commit history is rewritten and, therefore, the next time you try to push your branch to your fork repository you will need to use
the `--force-with-lease` option:

@ -16,7 +16,7 @@ A commit message can look like this:
- Specify concrete ubuntu and mac versions
- Use latest conan version
- Fix the profiles for linux and mac
- Use new version of expat (available in conan-center)
- Use new version of expat (avilable in conan-center)
- Install urllib3 as suggested in python guidelines
- Use virtualenv with python3
```
@ -77,7 +77,7 @@ We can summarize this in the following guidelines:
- Every commit should keep the code base in a buildable state. The test suite
needn't pass on every commit, but must pass before being merged into
`main`.
`master`.
These are however not strict rules and it always depends on the case. If in
doubt: ask.
@ -89,7 +89,7 @@ We prefer to keep the git log nearly linear with the individual pull requests
still visible, since they usually form one logical unit. It should look roughly
like this:
```
* 9f74f247 Merge pull request #227 from frli8848/main
* 9f74f247 Merge pull request #227 from frli8848/master
|\
| * 73ac02d7 Added test for Sigma lenses
| * fc8b45dd Added the Sigma 120-300mm F2.8 DG OS HSM | S for Nikon mount.
@ -141,61 +141,61 @@ rather complicated logs, like this:
Instead of using the `Update Branch` button use `git pull --rebase`. For the
following example, we'll assume that we are working in a branch called
`feature_xyz` that should be merged into the branch `main`. Furthermore the
`feature_xyz` that should be merged into the branch `master`. Furthermore the
remote `origin` is a fork of exiv2 and the remote `upstream` is the "official"
exiv2 repository.
Before we start working, the `main` branch looks like this:
Before we start working, the `master` branch looks like this:
```
$ git log main --oneline --graph
* efee9a2b (main) Merge pull request #something
$ git log master --oneline --graph
* efee9a2b (master) Merge pull request #something
|\
| * ead7f309 A commit on main
| * ead7f309 A commit on master
|/
* 55001c8d Merge pull request #something else
```
We create a new branch `feature_xyz` based on `main`, create two new commits
`My commit 1` and `My commit 2` and submit a pull request into `main`. The log
We create a new branch `feature_xyz` based on `master`, create two new commits
`My commit 1` and `My commit 2` and submit a pull request into master. The log
of the branch `feature_xyz` now looks like this:
```
$ git log feature_xyz --oneline --graph
* 893fffa5 (HEAD -> feature_xyz) My commit 2
* a2a22fb9 My commit 1
* efee9a2b (main) Merge pull request #something
* efee9a2b (master) Merge pull request #something
|\
| * ead7f309 A commit on main
| * ead7f309 A commit on master
|/
* 55001c8d Merge pull request #something else
```
If now new commits are pushed to `main`, resulting in this log:
If now new commits are pushed to `master`, resulting in this log:
```
$ git log main --oneline --graph
* 0d636cc9 (HEAD -> main) Hotfix for issue #something completely different
$ git log master --oneline --graph
* 0d636cc9 (HEAD -> master) Hotfix for issue #something completely different
* efee9a2b Merge pull request #something
|\
| * ead7f309 A commit on main
| * ead7f309 A commit on master
|/
* 55001c8d Merge pull request #something else
```
then the branch `feature_xyz` is out of date with `main`, because it lacks the
then the branch `feature_xyz` is out of date with `master`, because it lacks the
commit `0d636cc9`. We could now merge both branches (via the cli or GitHub's
`Update Branch` button), but that will result in a messy history. Thus **don't**
do it! If you do it, you'll have to remove the merge commits manually.
Instead run: `git pull --rebase upstream main` in the `feature_xyz`
branch. Git will pull the new commit `0d636cc9` from main into your branch
Instead run: `git pull --rebase upstream master` in the `feature_xyz`
branch. Git will pull the new commit `0d636cc9` from master into your branch
`feature_xyz` and apply the two commits `My commit 1` and `My commit 2` on top
of it:
```
$ git log feature_xyz --oneline --graph
* 22a7a8c2 (HEAD -> feature_xyz) My commit 2
* efe2ccdc My commit 1
* 0d636cc9 (main) Hotfix for issue #something completely different
* 0d636cc9 (master) Hotfix for issue #something completely different
* efee9a2b Merge pull request #something
|\
| * ead7f309 A commit on main
| * ead7f309 A commit on master
|/
* 55001c8d Merge pull request #something else
```
@ -208,20 +208,20 @@ changes via `git push --force` next time you push your changes upstream.
Most pull requests should be merged by creating a merge commit (the default on
GitHub). Small pull requests (= only one can commit) can be rebased on top of
`main`.
master.
## Branches and tags
- The `main` branch is the current "main" development branch. It is protected
- The `master` branch is the current "main" development branch. It is protected
so that changes can be only included via reviewed pull requests. New releases
are made by tagging a specific commit on `main`.
are made by tagging a specific commit on `master`.
- Releases are tagged with a tag of the form `v$major.$minor`. The tag is not
changed when changes are backported.
- For each release a branch of the form `$major.$minor` should be created to
store backported changes. It should be branched of from `main` at the commit
store backported changes. It should be branched of from `master` at the commit
which was tagged with `v$major.$minor`.
- All other branches are development branches for pull requests, experiments,

@ -1,17 +0,0 @@
This program is part of the Exiv2 distribution.
Copyright (C) 2004-2022 Exiv2 authors
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
---------------------------------------------------------------------------
Note:
Individual files contain the following tag instead of the full license text.
SPDX-License-Identifier: GPL-2.0-or-later
This enables machine processing of license information based on the SPDX
License Identifiers that are here available: http://spdx.org/licenses/

@ -44,7 +44,6 @@ The build procedures for those platforms are discussed here: See [README.md](REA
# 1 Step by Step Guide
<name id="1-1"></a>
##### 1.1) </a>Install conan:
```bash
@ -60,7 +59,6 @@ $ pip install conan --upgrade
```
<name id="1-2"></a>
##### 1.2) Test conan installation
```bash
@ -69,7 +67,6 @@ Conan version 1.23.0
```
<name id="1-3"></a>
##### 1.3) Create a build directory<name id="1-3"></a>
Create a build directory and run the conan commands:
@ -81,7 +78,7 @@ $ conan profile list
```
_**Visual Studio Users**_
_The profile msvc2019Release96 in `%USERPROFILE%\.conan\profiles\msvc2019Release64` is:_
_The profile msvc2019Release `%USERPROFILE%\.conan\profiles\msvc2019Release` is:_
```ini
[build_requires]
@ -98,27 +95,26 @@ os_build=Windows
[env]
```
_Profiles for Visual Studio are discussed in detail here: [Visual Studio Notes](#2-2)_
_Profiles for Visual Studio are discussed in detail here: [Visual Studio Notes](#2-2)__
<name id="1-4"></a>
##### 1.4) Build dependencies, create build environment, build and test</a>
| | Build Steps | Linux and macOS | Visual Studio |
|:-- |:-------------------------------------------------------------------------|-----------------------|------------------------------|
| _**1**_ | Get conan to fetch dependencies<br><br>The output can be quite<br>long as conan downloads and/or builds<br>zlib, expat, curl and other dependencies.| $ conan install ..<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--build missing | c:\\..\\build> conan install .. --build missing<br>&nbsp;&nbsp;&nbsp;&nbsp;--profile msvc2019Release64 |
| _**2**_ | Get cmake to generate<br>makefiles or sln/vcxproj | $ cmake .. | c:\\..\\build> cmake&nbsp;..&nbsp;-G&nbsp;"Visual Studio 16 2019"
| _**3**_ | Build | $ cmake --build . | c:\\..\\build>&nbsp;cmake&nbsp;--build&nbsp;.&nbsp;--config&nbsp;Release<br>You may prefer to open exiv2.sln and build using the IDE. |
| _**4**_ | Optionally Run Test Suite<br/>Test documentation: [README.md](README.md) | $ ctest | c:\\..\\build>&nbsp;ctest -C Release |
| | Build Steps | Linux and macOS | Visual Studio |
|:--|:--------------|--------------------------------|------------------------------|
| _**1**_ | Get conan to fetch dependencies<br><br>The output can be quite<br>long as conan downloads and/or builds<br>zlib, expat, curl and other dependencies.| $ conan install ..<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--build missing | c:\\..\\build> conan install .. --build missing<br>&nbsp;&nbsp;&nbsp;&nbsp;--profile msvc2019Release |
| _**2**_ | Get cmake to generate<br>makefiles or sln/vcxproj | $ cmake .. | c:\\..\\build> cmake&nbsp;..&nbsp;-G&nbsp;"Visual Studio 16 2019"
| _**3**_ | Build | $ cmake --build . | c:\\..\\build>&nbsp;cmake&nbsp;--build&nbsp;.&nbsp;--config&nbsp;Release<br>You may prefer to open exiv2.sln and build using the IDE. |
| _**4**_ | Optionally Run Test Suite | $ make tests | You must install MinGW<br>bash and python to run tests<br>See [README.md](README.md) |
[TOC](#TOC)
<name id="2"></a>
## 2) Platform Notes
<name id="2-1"></a>
### 2.1) Linux Notes
##### Default Profile
@ -169,29 +165,48 @@ algorithms when bringing the Exiv2 dependencies with conan, this might indicate
[TOC](#TOC)
<name id="2-2"></a>
### 2.2) Visual Studio Notes
We recommend that you install python as discussed here: [https://github.com/Exiv2/exiv2/pull/1403#issuecomment-731836146](https://github.com/Exiv2/exiv2/pull/1403#issuecomment-731836146)
I use the following batch file `cmd64.bat` to start cmd.exe. I do this to reduce the complexity of the path which grows as various tools are installed on Windows. The purpose of this script is to ensure a "stripped down path".
```bat
@echo off
setlocal
set "P="
set "P=%P%C:\Python37\;C:\Python37\Scripts;" # DOS Python3
set "P=%P%c:\Program Files\cmake\bin;" # DOS cmake
set "P=%P%c:\msys64\usr\bin;" # msys2 make, bash etc
set "P=%P%c:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\MSBuild\15.0\Bin;"
set "P=%P%c:\Windows\System32;" # windows
set "P=%P%%USERPROFILE%\com;" # my home-made magic
echo %P%
set "PATH=%P%"
set "EXIV2_EXT=.exe"
set "EXIV2_BINDIR=%USERPROFILE%\gnu\github\exiv2\0.27-maintenance\build\bin"
color 0d
cmd /S /K cd "%EXIV2_BINDIR%\..\.."
color
endlocal
```
### Profiles for Visual Studio
Exiv2 v0.27 can be built with VS 2008, 2010, 2012, 2013, 2015 , 2017 and 2019.
Exiv2 v1.0 is being "modernised" to C++11 and will not support C++98.
We don't expect Exiv2 v1.0 to build with VS versions earlier than VS 2015.
Exiv2 v0.28 is being "modernised" to C++11 and will not support C++98. We don't expect Exiv2 v0.28 to build with VS versions earlier than VS 2015.
You create profiles in %HOMEPATH%\.conan\profiles with a text editor. For your convenience, you'll find profiles in `<exiv2dir>\cmake\msvc_conan_profiles`.
You create profiles in %HOMEPATH%\.conan\profiles with a text editor. For your convenience, you'll find profiles in `<exiv2dir>\cmake\msvc_conan_profiles`. There are 26 in total:
```
Profile := msvc{Edition}{Type}{Bits}
Edition := { 2019 | 2017 | 2015 }
Type := { Release | Debug }
Bits := { 64 | 32 }
Examples: msvc2019Release64 msvc2017Release32 msvc2015Debug32
Bits := { 64 | 32 } # 32 bit build is not provided for 2019
Examples: msvc2019Release msvc2017Release64 msvc2015Debug32
```
The profile msvc2019Release64 is as follows:
The profile msvc2019Release is as follows:
```ini
[build_requires]
@ -224,8 +239,8 @@ In the step-by-step guide, the command `$ cmake ..` uses
the default CMake generator. Always use the generator for your version of Visual Studio. For example:
```bat
c:\..\build> conan install .. --build missing --profile msvc2019Release64
c:\..\build> cmake .. -G "Visual Studio 16 2019" -A x64
c:\..\build> conan install .. --build missing --profile msvc2019Release
c:\..\build> cmake .. -G "Visual Studio 16 2019"
c:\..\build> cmake --build . --config Release
```
@ -233,8 +248,8 @@ CMake provides Generators for different editions of Visual Studio. The 64 and 3
| Architecture | Visual Studio 2019 | Visual Studio 2017 | Visual Studio 2015 |
|:--------- |--------------------|--------------------|--------------------|--------------------|
| 64 bit | -G "Visual Studio 16 2019" -A x64 | -G "Visual Studio 15 2017 Win64" | -G "Visual Studio 14 2015 Win64" |
| 32 bit | -G "Visual Studio 16 2019" -A Win32 | -G "Visual Studio 15 2017" | -G "Visual Studio 14 2015" |
| 64 bit | "Visual Studio 16 2019" | "Visual Studio 15 2017 Win64" | "Visual Studio 14 2015 Win64" |
| 32 bit | Not provided | "Visual Studio 15 2017" | "Visual Studio 14 2015" |
### Recommended settings for Visual Studio
@ -242,24 +257,24 @@ CMake provides Generators for different editions of Visual Studio. The 64 and 3
| | Visual Studio 2019 | Visual Studio 2017 | Visual Studio 2015|
|:---------|--------------------|--------------------|--------------|
| _**conan install .. --profile**_ | msvc2019Release64 | msvc2017Release64 | msvc2015Release64 |
| _**cmake**_ | -G "Visual Studio 16 2019" -A x64 | -G "Visual Studio 15 2017 Win64" | -G "Visual Studio 14 2015 Win64" |
| _**conan install .. --profile**_ | msvc2019Release | msvc2017Release64 | msvc2015Release64 |
| _**cmake -G**_ | "Visual Studio 16 2019" | "Visual Studio 15 2017 Win64" | "Visual Studio 14 2015 Win64" |
| _**profile**_<br><br><br><br><br><br><br>_ | arch=x86\_64<br>arch\_build=x86\_64<br>build\_type=Release<br>compiler.runtime=MD<br>compiler.version=16<br>compiler=Visual Studio<br>os=Windows<br>os\_build=Windows | arch=x86\_64<br>arch\_build=x86\_64<br>build\_type=Release<br>compiler.runtime=MD<br>compiler.version=15<br>compiler=Visual Studio<br>os=Windows<br>os\_build=Windows | arch=x86\_64<br>arch\_build=x86\_64<br>build\_type=Release<br>compiler.runtime=MD<br>compiler.version=14 <br>compiler=Visual Studio<br>os=Windows<br>os\_build=Windows |
##### Debug Builds
|| Visual Studio 2019 | Visual Studio 2017 | Visual Studio 2015 |
|:-------|-------|------|--------------|
| _**conan install .. --profile**_ | msvc2019Debug64 | msvc2017Debug64 | msvc2015Debug64 |
| _**conan install .. --profile**_ | msvc2019Debug | msvc2017Debug64 | msvc2015Debug64 |
| _**profile**_<br>_ | build\_type=Debug<br>compiler.runtime=MDd | build\_type=Debug<br>compiler.runtime=MDd | build_type=Debug<br>compiler.runtime=MDd |
##### 32bit Builds
|| Visual Studio 2019 | Visual Studio 2017 | Visual Studio 2015 |
|:-----------|--------------------|--------------------|--------------------|
| _**conan install .. --profile**_ | msvc2019Release32 | msvc2017Release32 | msvc2015Release32 |
| _**cmake**_ | -G "Visual Studio 16 2019" -A Win32 | -G "Visual Studio 15 2017" | -G "Visual Studio 14 2015" |
| _**profile**_<br>_ | arch=x86<br>arch\_build=x86 | arch=x86<br>arch\_build=x86 | arch=x86<br>arch\_build=x86 |
| _**conan install .. --profile**_ | Not provided | msvc2017Release32 | msvc2015Release32 |
| _**cmake -G**_ | Not provided | "Visual Studio 15 2017" | "Visual Studio 14 2015" |
| _**profile**_<br>_ | Not provided | arch=x86<br>arch\_build=x86 | arch=x86<br>arch\_build=x86 |
##### Static Builds
@ -285,7 +300,7 @@ You should link everything with the dynamic or static run-time. You can link a s
It is recommended that you use profiles provided in `<exiv2dir>\cmake\msvc_conan_profiles`.
You can modify profile settings on the command line.
The following example demonstrates making substantial changes to profile settings by performing a 32 bit build using Visual Studio 2015 with a 2017 profile! This example is not considered good practice, it is an illustration of some conan flexibility which may be useful when your build environment is automated.
The following example demonstrates making substantial changes to profile settings by performing a 32 bit build using Visual Studio 2015 with a 2017 profile! This example is not considered good practice, it is an illustration to some conan flexibility which be useful when your build environment is automated.
```bash
$ conan install .. --profile msvc2017Release64 -s arch_build=x86 -s arch=x86 -s compiler.version=14
@ -294,11 +309,11 @@ $ cmake --build . --config Release
```
[TOC](#TOC)
<name id="3">
## 3 Conan Architecture
<name id="3-1">
##### 3.1) conanfile.py
In the root level of the **Exiv2** repository, the file `conanfile.py` defines C/C++ dependencies with the syntax: `Library/version@user/channel`
@ -311,7 +326,6 @@ self.requires('self.requires('zlib/1.2.11@conan/stable')')
[TOC](#TOC)
<name id="3-2">
##### 3.2) Conan _**Recipes**_
Conan searches remote servers for a _**recipe**_ to build a dependency.
@ -361,7 +375,6 @@ Existing packages for recipe zlib/1.2.11@conan/stable:
[TOC](#TOC)
<name id="3-3">
##### 3.3) Conan server search path
Conan searches remote servers for a _**recipe**_ to build the dependency. You can list them with the command:
@ -378,7 +391,6 @@ $ conan remote add conan-piponazo https://api.bintray.com/conan/piponazo/piponaz
[TOC](#TOC)
<name id="3-4">
##### 3.4) Configuring conan on your machine
Conan stores its configuration and local builds in the directory ~/.conan (%HOMEPATH%\\.conan on Windows).
@ -392,7 +404,6 @@ $HOME/.conan/data Dependencies are built/stored in this directory
[TOC](#TOC)
<name id="3-5">
##### 3.5) Running `conan install` for the first time
The first time you run `$ conan install`, it will auto-detect your configuration and store a default profile in the file
@ -517,7 +528,6 @@ Indicating that the packages were found in the local cache.
[TOC](#TOC)
<name id="4">
## 4 Building Exiv2 with Adobe XMPsdk 2016
With Exiv2 v0.27, you can build Exiv2 with Adobe XMPsdk 2016 on Linux/GCC, Mac/clang and Visual Studio 2017.
@ -528,7 +538,6 @@ library can be used by the application and Exiv2. The Adobe XMPsdk can be built
To build Exiv2 with Adobe XMPsdk 2016, perform steps 1.1, 1.2 and 1.3 described above, then perform the following:
<name id="4-1">
##### 4.1) Add a remote directory to conan's recipe search path
By default, conan knows about several public conan repositories. Exiv2 requires
@ -539,7 +548,6 @@ $ conan remote add conan-piponazo https://api.bintray.com/conan/piponazo/piponaz
```
<name id="4-2">
##### 4.2) Build dependencies and install conan artefacts in your build directory
```bash
@ -547,7 +555,6 @@ $ conan install .. --options xmp=True --build missing
```
<name id="4-3">
##### 4.3) Execute cmake to generate build files for your environment:
You must tell CMake to link Adobe's library:
@ -562,7 +569,6 @@ $ cmake .. -DEXIV2_ENABLE_EXTERNAL_XMP=On -G Xcode
```
<name id="4-4">
##### 4.4) Build Exiv2 and link Adobe XMPsdk library
```bash
@ -571,18 +577,17 @@ $ cmake --build . --config Release
[TOC](#TOC)
<name id="5">
## 5 Webready Support
Exiv2 can perform I/O using internet protocols such as http, https and ftp.
The feature is disabled by default. You will need to instruct conan to build/download necessary libraries (curl and openssl) and tell CMake to link to the libraries.
The feature is disabled by default. You will need to instruct conan to build/download necessary libraries (curl, openssl and libssh) and tell CMake to link to the libraries.
```bash
$ conan install .. --options webready=True
$ cmake -DEXIV2_ENABLE_WEBREADY=ON -DEXIV2_ENABLE_CURL=ON ..
$ cmake -DEXIV2_ENABLE_WEBREADY=ON -DEXIV2_ENABLE_CURL=ON -DEXIV2_ENABLE_SSH=ON ..
```
[TOC](#TOC)
Written by Robin Mills<br>robin@clanmills.com<br>Updated: 2021-12-17
Written by Robin Mills<br>robin@clanmills.com<br>Updated: 2020-05-21

@ -1,7 +1,3 @@
| Travis | AppVeyor | GitLab| Codecov| Repology| Chat |
|:-------------:|:-------------:|:-----:|:------:|:-------:|:----:|
| [![Build Status](https://travis-ci.org/Exiv2/exiv2.svg?branch=0.27-maintenance)](https://travis-ci.org/Exiv2/exiv2) | [![Build status](https://ci.appveyor.com/api/projects/status/d6vxf2n0cp3v88al/branch/0.27-maintenance?svg=true)](https://ci.appveyor.com/project/piponazo/exiv2-wutfp/branch/0.27-maintenance) | [![pipeline status](https://gitlab.com/D4N/exiv2/badges/0.27-maintenance/pipeline.svg)](https://gitlab.com/D4N/exiv2/commits/0.27-maintenance) | [![codecov](https://codecov.io/gh/Exiv2/exiv2/branch/0.27-maintenance/graph/badge.svg)](https://codecov.io/gh/Exiv2/exiv2) | [![Packaging status](https://repology.org/badge/tiny-repos/exiv2.svg)](https://repology.org/metapackage/exiv2/versions) | [![#exiv2-chat on matrix.org](matrix-standard-vector-logo-xs.png)](https://matrix.to/#/#exiv2-chat:matrix.org) |
![Exiv2](exiv2.png)
# Exiv2 Sample Applications
@ -21,9 +17,9 @@ The following programs are build and installed in /usr/local/bin.
| _**addmoddel**_ | Demonstrates Exiv2 library APIs to add, modify or delete metadata | [addmoddel](#addmoddel) | [addmoddel.cpp](samples/addmoddel.cpp) |
| _**exifcomment**_ | Set Exif.Photo.UserComment in an image | [exifcomment](#exifcomment) | [exifcomment.cpp](samples/exifcomment.cpp) |
| _**exifdata**_ | Prints _**Exif**_ metadata in different formats in an image | [exifdata](#exifdata) | [exifdata.cpp](samples/exifdata.cpp) |
| _**exifprint**_ | Print _**Exif**_ metadata in images<br>Miscellaneous other features | [exifprint](#exifprint)| [exifprint.cpp](samples/exifprint.cpp) |
| _**exifprint**_ | Print _**Exif**_ metadata in images<br>Miscelleous other features | [exifprint](#exifprint)| [exifprint.cpp](samples/exifprint.cpp) |
| _**exifvalue**_ | Prints the value of a single _**Exif**_ tag in a file | [exifvalue](#exifvalue) | [exifvalue.cpp](samples/exifvalue.cpp) |
| _**exiv2**_ | Utility to read and write image metadata, including Exif, IPTC, XMP, image comments, ICC Profile, thumbnails, image previews and many vendor makernote tags.<br>This is the primary test tool used by Team Exiv2 and can exercise almost all code in the library. Due to the extensive capability of this utility, the APIs used are usually less obvious for casual code inspection. | [exiv2 manpage](exiv2.md)<br>[https://exiv2.org/sample.html](https://exiv2.org/sample.html) | |
| _**exiv2**_ | Command line utility to read, write, delete and modify Exif, IPTC, XMP and ICC image metadata.<br>This is the primary test tool used by Team Exiv2 and can exercise almost all code in the library. Due to the extensive capability of this utility, the APIs used are usually less obvious for casual code inspection. | [https://exiv2.org/manpage.html](https://exiv2.org/manpage.html)<br>[https://exiv2.org/sample.html](https://exiv2.org/sample.html) | |
| _**exiv2json**_ | Extracts data from image in JSON format.<br>This program also contains a parser to recursively parse Xmp metadata into vectors and objects. | [exiv2json](#exiv2json) | [exiv2json.cpp](samples/exiv2json.cpp) |
| _**geotag**_ | Reads GPX data and updates images with GPS Tags | [geotag](#geotag) | [geotag.cpp](samples/geotag.cpp) |
| _**iptceasy**_ | Demonstrates read, set or modify IPTC metadata | [iptceasy](#iptceasy) | [iptceasy.cpp](samples/iptceasy.cpp) |
@ -61,6 +57,7 @@ As Exiv2 is open source, we publish all our materials. The following programs a
| _**remotetest**_ | Tester application for testing remote i/o. | [remotetest](#remotetest) |
| _**stringto-test**_ | Test conversions from string to long, float and Rational types. | [stringto-test](#stringto-test) |
| _**tiff-test**_ | Simple TIFF write test | [tiff-test](#tiff-test) |
| _**werror-test**_ | Simple tests for the wide-string error class WError | [werror-test](#werror-test) |
| _**write-test**_ | ExifData write unit tests | [write-test](#write-test) |
| _**write2-test**_ | ExifData write unit tests for Exif data created from scratch | [write2-test](#write2-test) |
| _**xmpparser-test**_ | Read an XMP packet from a file, parse and re-serialize it. | [xmpparser-test](#xmpparser-test)|
@ -111,21 +108,18 @@ This is a simple program to demonstrate dumping _**Exif**_ metadata in common fo
#### exifprint
```
Usage: exifprint [ [--lint] path | --version | --version-test ]
Usage: exifprint [ path | --version | --version-test ]
```
| Arguments | Description |
|:-- |:--- |
| path | Path to image |
| --lint path | Path to image. Type metadata test |
| --version | Print version information from build |
| --version-test | Tests Exiv2 VERSION API |
This program demonstrates how to print _**Exif**_ metadata in an image. This program is also discussed in the platform ReadMe.txt file included in a build bundle. The option **--version** was added to enable the user to build a test application which dumps the build information. The option **--version-test** was added to test the macro EXIV2\_TEST\_VERSION() in **include/exiv2/version.hpp**.
You can process the metadata in two different ways. The default prints the metadata. The option --lint instructs exifprint to compare the type of the metadata to the standard.
There is another unique feature of this program. It is the only test/sample program which can use the EXV\_UNICODE\_PATH build feature of Exiv2 on Windows.
There is one other unique feature of this program. It is the only test/sample program which can use the EXV\_UNICODE\_PATH build feature of Exiv2 on Windows.
_Code: [exifprint.cpp](samples/exifprint.cpp)_
@ -161,20 +155,16 @@ Option: all | exif | iptc | xmp | filesystem
This program dumps metadata from an image in JSON format. _Code: [exiv2json.cpp](samples/exiv2json.cpp)_
exiv2json has a recursive parser to encode XMP into Vectors and Objects. XMP data is XMP and can contain XMP `Bag` and `Seq` which are converted to JSON Objects and Arrays. Exiv2 presents data in the format: [Family.Group.Tagname](exiv2.md#exiv2_key_syntax). For XMP, results in "flat" output such as:
exiv2json has a recursive parser to encode XMP into Vectors and Objects. XMP data is XMP and can contain XMP `Bag` and `Seq` which are converted to JSON Objects and Arrays. Exiv2 presents data in the format: Family.Group.Tag. For XMP, results in "flat" output such such as:
```
$ curl --silent -O https://clanmills.com/Stonehenge.jpg
$ exiv2 --print x Stonehenge.jpg
$ exiv2 -px ~/Stonehenge.jpg
Xmp.xmp.Rating XmpText 1 0
Xmp.xmp.ModifyDate XmpText 25 2015-07-16T20:25:28+01:00
Xmp.cm2e.Father XmpText 11 Robin Mills
Xmp.cm2e.Family XmpBag 0
Xmp.dc.description LangAlt 1 lang="x-default" Classic View
Xmp.dc.Family XmpBag 1 Robin
```
exiv2json parses the Exiv2 [Family.Group.Tagname](exiv2.md#exiv2_key_syntax) data and restores the structure of the original data in JSON. _Code: [exiv2json.cpp](samples/exiv2json.cpp)_
exiv2json parses the Exiv2 'Family.Group.Tag' data and restores the structure of the original data in JSON. _Code: [exiv2json.cpp](samples/exiv2json.cpp)_
```
$ exiv2json -xmp http://clanmills.com/Stonehenge.jpg
@ -210,7 +200,7 @@ $
Usage: geotag {-help|-version|-dst|-dryrun|-ascii|-verbose|-adjust value|-tz value|-delta value}+ path+
```
Geotag reads one or more GPX files and adds GPS Tags to images. _Code: [geotag.cpp](samples/geotag.cpp)_
Geotag reads one or more GPX files and adds GPS Tages to images. _Code: [geotag.cpp](samples/geotag.cpp)_
If the path is a directory, geotag will read all the files in the directory. It constructs a time dictionary of position data, then updates every image with GPS Tags.
@ -262,7 +252,7 @@ Demonstrates Exiv2 library APIs to print Iptc data. _Code: [iptcprint.cpp](sampl
#### metacopy
```
Usage: metacopy [-iecxaph] readfile writefile
Usage: metacopy [-iecaph] readfile writefile
Reads and writes raw metadata. Use -h option for help.
```
@ -352,16 +342,10 @@ Conversion test driver
#### easyaccess-test
```
Usage: ..\build\bin\easyaccess-test.exe file [category [category ...]]
Categories: Orientation | ISOspeed | DateTimeOriginal | FlashBias | ExposureMode | SceneMode |
MacroMode | ImageQuality | WhiteBalance | LensName | Saturation | Sharpness |
Contrast | SceneCaptureType | MeteringMode | Make | Model | ExposureTime | FNumber |
ShutterSpeed | Aperture | Brightness | ExposureBias | MaxAperture | SubjectDistance |
LightSource | Flash | SerialNumber | FocalLength | SubjectArea | FlashEnergy |
ExposureIndex | SensingMethod | AFpoint
Usage: easyaccess-test file
```
Sample program using high-level metadata access functions. Without specification of a category, metadata for all categories are shown.
Sample program using high-level metadata access functions
[Sample](#TOC1) Programs [Test](#TOC2) Programs
@ -483,7 +467,7 @@ Test access to preview images
#### remotetest
```
Usage: remotetest file {--nocurl | --curl}
Usage: remotetest remotetest file {--nocurl | --curl}
```
Tester application for testing remote i/o.
@ -541,8 +525,7 @@ FlashDevice, 9, 0x0009, Nikon3, Exif.Nikon3.FlashDevice, Ascii, Flash de
We can see those tags being used:
```
$ curl --silent -O https://clanmills.com/Stonehenge.jpg
$ exiv2 --print a --grep Nikon3 Stonehenge.jpg
$ exiv2 -pa --grep Nikon3 http://clanmills.com/Stonehenge.jpg
Exif.Nikon3.Version Undefined 4 2.11
Exif.Nikon3.ISOSpeed Short 2 200
...
@ -552,7 +535,7 @@ This information is formatted (search Nikon (format 3) MakerNote Tags): [https:/
#### taglist all
These options are provided to list every tag known to Exiv2. The option `all` prints the [Group.Tagnames](exiv2.md#exiv2_key_syntax) for every Exif tag. The option `ALL` prints the [Group.Tagnames](exiv2.md#exiv2_key_syntax) for every Exif tag, followed by the TagInfo for that tag. For example:
These options are provided to list every Exif tag known to Exiv2. The option `all` prints Group.Name for every tag. The option `ALL` print Group.Name followed by the TagInfo for that tag. For example:
```bash
$ taglist all | grep ISOSpeed$
@ -604,6 +587,18 @@ Simple TIFF write test
[Sample](#TOC1) Programs [Test](#TOC2) Programs
<div id="werror-test">
#### werror-test
```
Usage: werror-test
```
Simple tests for the wide-string error class WError
[Sample](#TOC1) Programs [Test](#TOC2) Programs
<div id="write-test">
#### write-test
@ -657,4 +652,4 @@ Read an XMP packet from a file, parse and re-serialize it.
Robin Mills<br>
robin@clanmills.com<br>
Revised: 2021-09-21
Revised: 2020-05-17

@ -1,10 +0,0 @@
meson build system
This is a basic meson.build file intended to be used by meson projects that use
WrapDB: https://github.com/mesonbuild/wrapdb
This can also be used as a test playground to test various options not exposed
by the CMake build, eg: iconv and intl on Windows.
It is currently incomplete. Tests are not implemented yet. The library and
executable are.

File diff suppressed because it is too large Load Diff

@ -1,59 +0,0 @@
# Security Policy
## Supported Versions
| Exiv2 Version | Date | Tag | Branch | _Dot/Security_ Release | Date | Tag |
|:-- |:-- |:- |:-- |:-- |:- |:- |
| v0.28 | 2023-05-08 | v0.28.0 | 0.28.x | v0.28.0 | 2023-05-08 | v0.28.0 |
| | | | | v0.28.1 | 2023-11-06 | v0.28.1 |
| | | | | v0.28.2 | 2024-02-13 | v0.28.2 |
| | | | | v0.28.3 | 2024-07-08 | v0.28.3 |
| v0.27 | 2018-12-20 | 0.27 | 0.27-maintenance | v0.27.0 | 2018-12-20 | v0.27.0 |
| | | | | v0.27.1 | 2019-04-18 | v0.27.1 |
| | | | | v0.27.2 | 2019-07-29 | v0.27.2 |
| | | | | v0.27.3 | 2020-06-30 | v0.27.3 |
| | | | | v0.27.4 | 2021-06-15 | v0.27.4 |
| | | | | v0.27.5 | 2021-09-30 | v0.27.5 |
| | | | | v0.27.6 | 2023-01-18 | v0.27.6 |
| | | | | v0.27.7 | 2023-05-14 | v0.27.7 |
| v0.26 | 2017-04-28 | v0.26 | 0.26 | None | | |
| v0.25 | 2015-06-21 | _None_ | 0.25 | None | | |
## Security Process
If you have found a security vulnerability in Exiv2, please follow these steps:
* Click [this link](https://github.com/Exiv2/exiv2/security/advisories/new) to create a draft security advisory.
* Write a detailed description of the vulnerability in the draft advisory.
* Include all of the following details in your description of the vulnerability:
* Exact version of Exiv2 that you tested. _For example: commit [194bb65ac568a5435874c9d9d73b1c8a68e4edec](https://github.com/Exiv2/exiv2/commit/194bb65ac568a5435874c9d9d73b1c8a68e4edec)_
* Platform used. _For example: Ubuntu 22.04.3 LTS (x86\_64)_
* Exact command used to build Exiv2. _For example: `mkdir build; cd build; cmake ..; make`_
* Attach a copy of the image file that triggers the bug. _For example: `poc.jpg`_
* Exact command line arguments that trigger the bug. _For example: `./bin/exiv2 poc.jpg`_
* Crash output (stdout + stderr).
* The source location of the bug and/or any other information that you are able to provide about what the cause of the bug is.
The draft security advisory is private until we publish it, so it is a good place to discuss the details of the vulnerability privately.
To qualify as a security issue, the bug **must** be reproducible on an official release of Exiv2, via a realistic attack vector. As a general rule, that means it should be possible to trigger the bug by running the `exiv2` command-line application on a malicious input file. Please note that the applications in the `samples` sub-directory are demo applications that are not intended for production use, so we usually do not consider bugs in those applications to be security vulnerabilities. However, if one of the sample applications reveals a legitimate bug in the exiv2 library then we will still consider it as a potential security issue.
Official releases are listed [here](https://github.com/Exiv2/exiv2/releases) (not including those labeled "pre-release"). Bugs that are only reproducible on the [main branch](https://github.com/Exiv2/exiv2/tree/main) or on a pre-release are not security issues and can be reported as regular [issues](https://github.com/Exiv2/exiv2/issues).
Team Exiv2 does not back-port security (or any other fix) to earlier releases of the code. An engineer at SUSE has patched and fixed some security releases for Exiv2 v0.26 and Exiv2 v0.25 in branches 0.26 and 0.25. Exiv2 has provided several _**Dot Release**_ for v0.27. Exiv2 has never issued a _**Security Release**_.
The version numbering scheme is explained below. The design includes provision for a security release. A _**Dot Release**_ is an updated version of the library with security PRs and other changes. A _**Dot Release**_ offers the same API as its parent. A _**Security Release**_ is an existing release PLUS one or more security PRs. Nothing else is changed from it parent.
Users can register on GitHub.com to receive release notices for RC and GM Releases. Additionally, we inform users when we begin a project to create a new release on FaceBook (https://facebook.com/exiv2) and Discuss Pixls (https://discuss.pixls.us). The announcement of a new release project has a preliminary specification and schedule.
## Version Numbering Scheme
| Version | Name | Status | Purpose |
|:-- |:-- |:-- |:-- |
| v0.27.7.3 | Exiv2 v0.27.3 | GM | Golden Master. This is the final and official release. |
| v0.27.3.2 | Exiv2 v0.27.3.2 | RC2 | Release Candidate 2. |
| v0.27.3.20 | Exiv2 v0.27.3.2 | RC2 Preview | Dry-run for release candidate. For team review. |
| v0.27.3.81 | Exiv2 v0.27.3 | Security Fix | Security Release |
| v0.27.3.29 | Exiv2 v0.27.3.29 | Development | Should never be installed for production. |
| v0.27.4.9 | Exiv2 v0.27.4.9 | Development | Should never be installed for production. |
| v0.27.99 | Exiv2 v0.28 | Development | Should never be installed for production. |

@ -1,65 +0,0 @@
set(APP_SOURCES
exiv2.cpp
exiv2app.hpp
actions.cpp
actions.hpp
getopt.cpp
getopt.hpp
app_utils.cpp
app_utils.hpp
)
add_executable(exiv2 ${APP_SOURCES})
target_include_directories(exiv2 PRIVATE ${PROJECT_SOURCE_DIR}/src) # To find i18n.hpp
set_target_properties(exiv2 PROPERTIES COMPILE_FLAGS ${EXTRA_COMPILE_FLAGS} XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS[variant=Debug] "YES")
if(MSVC)
set_target_properties(exiv2 PROPERTIES LINK_FLAGS "/ignore:4099") # Ignore missing PDBs
endif()
target_link_libraries(exiv2 PRIVATE exiv2lib)
if(EXIV2_ENABLE_NLS)
target_link_libraries(exiv2 PRIVATE ${Intl_LIBRARIES})
target_include_directories(exiv2 PRIVATE ${Intl_INCLUDE_DIRS})
endif()
target_link_libraries(exiv2 PRIVATE std::filesystem)
if(MSVC OR MINGW)
# Trick to get properly UTF-8 encoded argv.
# More info at: https://github.com/huangqinjin/wmain
add_library(wmain STATIC wmain.cpp)
target_link_libraries(exiv2 PRIVATE wmain)
endif()
if(MSVC)
target_link_options(wmain INTERFACE /WHOLEARCHIVE:$<TARGET_FILE:wmain>)
target_link_options(exiv2 PRIVATE "/ENTRY:wWinMainCRTStartup")
endif()
if(MINGW)
target_compile_options(exiv2 PRIVATE -municode)
target_link_options(exiv2 PRIVATE -municode)
endif()
if(USING_CONAN
AND WIN32
AND EXISTS ${PROJECT_BINARY_DIR}/conanDlls
)
# In case of using conan recipes with their 'shared' option turned on, we will have dlls of the 3rd party dependencies in the conanDlls folder.
add_custom_command(
TARGET exiv2
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_BINARY_DIR}/conanDlls ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
COMMENT "Copy 3rd party DLLs the bin folder"
)
# Copy 3rd party DLLs the bin folder. [install step]
install(DIRECTORY ${PROJECT_BINARY_DIR}/conanDlls/ DESTINATION bin)
endif()
install(TARGETS exiv2 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})

File diff suppressed because it is too large Load Diff

@ -1,326 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*!
@file actions.hpp
@brief Implements base class Task, TaskFactory and the various supported
actions (derived from Task).
@author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 11-Dec-03, ahu: created
*/
#ifndef ACTIONS_HPP_
#define ACTIONS_HPP_
// *****************************************************************************
#include <unordered_map>
#include "exiv2app.hpp"
// *****************************************************************************
// class declarations
namespace Exiv2 {
class ExifData;
class Image;
class Metadatum;
class PreviewImage;
} // namespace Exiv2
// *****************************************************************************
// namespace extensions
/// @brief Contains all action classes (task subclasses).
namespace Action {
//! Enumerates all tasks
enum TaskType {
none,
adjust,
print,
rename,
erase,
extract,
insert,
modify,
fixiso,
fixcom,
};
// *****************************************************************************
// class definitions
/*!
@brief Abstract base class for all concrete actions.
Task provides a simple interface that actions must implement and a few
commonly used helpers.
*/
class Task {
public:
//! Shortcut for an auto pointer.
using UniquePtr = std::unique_ptr<Task>;
//! Virtual destructor.
virtual ~Task() = default;
Task() = default;
Task(const Task&) = default;
Task& operator=(const Task&) = default;
//! Virtual copy construction.
[[nodiscard]] virtual UniquePtr clone() const = 0;
/// @brief Application interface to perform a task.
/// @param path Path of the file to process.
/// @return 0 if successful.
virtual int run(const std::string& path) = 0;
bool setBinary(bool b) {
bool bResult = binary_;
binary_ = b;
return bResult;
}
[[nodiscard]] bool binary() const {
return binary_;
}
private:
//! copy binary_ from command-line params to task
bool binary_{false};
}; // class Task
/*!
@brief Task factory.
Creates an instance of the task of the requested type. The factory is
implemented as a singleton, which can be accessed only through the static
member function instance().
*/
class TaskFactory {
public:
/*!
@brief Get access to the task factory.
Clients access the task factory exclusively through this method. (SINGLETON)
*/
static TaskFactory& instance();
~TaskFactory() = default;
//! Prevent copy construction: not implemented.
TaskFactory(const TaskFactory&) = delete;
TaskFactory& operator=(const TaskFactory&) = delete;
//! Destructor
void cleanup();
/*!
@brief Create a task.
@param type Identifies the type of task to create.
@return An auto pointer that owns a task of the requested type. If
the task type is not supported, the pointer is 0.
@remark The caller of the function should check the content of the
returned auto pointer and take appropriate action (e.g., throw
an exception) if it is 0.
*/
Task::UniquePtr create(TaskType type);
private:
//! Prevent construction other than through instance().
TaskFactory();
//! List of task types and corresponding prototypes.
std::unordered_map<TaskType, Task::UniquePtr> registry_;
};
//! %Print the Exif (or other metadata) of a file to stdout
class Print : public Task {
public:
int run(const std::string& path) override;
[[nodiscard]] Task::UniquePtr clone() const override;
//! Print the Jpeg comment
int printComment();
//! Print list of available preview images
int printPreviewList();
//! Print Exif summary information
int printSummary();
//! Print Exif, IPTC and XMP metadata in user defined format
int printList();
//! Return true if key should be printed, else false
static bool grepTag(const std::string& key);
//! Return true if key should be printed, else false
static bool keyTag(const std::string& key);
//! Print all metadata in a user defined format
int printMetadata(const Exiv2::Image* image);
//! Print a metadatum in a user defined format, return true if something was printed
bool printMetadatum(const Exiv2::Metadatum& md, const Exiv2::Image* image);
//! Print the label for a summary line
void printLabel(const std::string& label) const;
/*!
@brief Print one summary line with a label (if provided) and requested
data. A line break is printed only if a label is provided.
@return 1 if a line was written, 0 if the key was not found.
*/
int printTag(const Exiv2::ExifData& exifData, const std::string& key, const std::string& label = "") const;
//! Type for an Exiv2 Easy access function
using EasyAccessFct = Exiv2::ExifData::const_iterator (*)(const Exiv2::ExifData&);
/*!
@brief Print one summary line with a label (if provided) and requested
data. A line break is printed only if a label is provided.
@return 1 if a line was written, 0 if the information was not found.
*/
int printTag(const Exiv2::ExifData& exifData, EasyAccessFct easyAccessFct, const std::string& label = "",
EasyAccessFct easyAccessFctFallback = nullptr) const;
private:
std::string path_;
int align_{0}; // for the alignment of the summary output
};
/// @brief %Rename a file to its metadata creation timestamp, in the specified format.
class Rename : public Task {
public:
int run(const std::string& path) override;
[[nodiscard]] Task::UniquePtr clone() const override;
}; // class Rename
//! %Adjust the Exif (or other metadata) timestamps
class Adjust : public Task {
public:
int run(const std::string& path) override;
[[nodiscard]] Task::UniquePtr clone() const override;
private:
int adjustDateTime(Exiv2::ExifData& exifData, const std::string& key, const std::string& path) const;
int64_t adjustment_{0};
int64_t yearAdjustment_{0};
int64_t monthAdjustment_{0};
int64_t dayAdjustment_{0};
}; // class Adjust
/// @brief %Erase the entire exif data or only the thumbnail section.
class Erase : public Task {
public:
int run(const std::string& path) override;
[[nodiscard]] Task::UniquePtr clone() const override;
/// @brief Delete the thumbnail image, incl IFD1 metadata from the file.
static int eraseThumbnail(Exiv2::Image* image);
/// @brief Erase the complete Exif data block from the file.
static int eraseExifData(Exiv2::Image* image);
/// @brief Erase all Iptc data from the file.
static int eraseIptcData(Exiv2::Image* image);
/// @brief Erase Jpeg comment from the file.
static int eraseComment(Exiv2::Image* image);
/// @brief Erase XMP packet from the file.
static int eraseXmpData(Exiv2::Image* image);
/// @brief Erase ICCProfile from the file.
static int eraseIccProfile(Exiv2::Image* image);
private:
std::string path_;
};
/// @brief %Extract the entire exif data or only the thumbnail section.
class Extract : public Task {
public:
int run(const std::string& path) override;
[[nodiscard]] Task::UniquePtr clone() const override;
/*!
@brief Write the thumbnail image to a file. The filename is composed by
removing the suffix from the image filename and appending
"-thumb" and the appropriate suffix (".jpg" or ".tif"), depending
on the format of the Exif thumbnail image.
*/
[[nodiscard]] int writeThumbnail() const;
/// @brief Write preview images to files.
[[nodiscard]] int writePreviews() const;
/// @brief Write one preview image to a file. The filename is composed by removing the suffix from the image
/// filename and appending "-preview<num>" and the appropriate suffix (".jpg" or ".tif"), depending on the
/// format of the Exif thumbnail image.
void writePreviewFile(const Exiv2::PreviewImage& pvImg, size_t num) const;
/// @brief Write embedded iccProfile files.
[[nodiscard]] int writeIccProfile(const std::string& target) const;
private:
std::string path_;
};
/// @brief %Insert the Exif data from corresponding *.exv files.
class Insert : public Task {
public:
int run(const std::string& path) override;
[[nodiscard]] Task::UniquePtr clone() const override;
/*!
@brief Insert a Jpeg thumbnail image from a file into file \em path.
The filename of the thumbnail is expected to be the image
filename (\em path) minus its suffix plus "-thumb.jpg".
*/
static int insertThumbnail(const std::string& path);
/// @brief Insert an XMP packet from a xmpPath into file \em path.
static int insertXmpPacket(const std::string& path, const std::string& xmpPath);
/// @brief Insert xmp from a DataBuf into file \em path.
static int insertXmpPacket(const std::string& path, const Exiv2::DataBuf& xmpBlob, bool usePacket = false);
/// @brief Insert an ICC profile from iccPath into file \em path.
static int insertIccProfile(const std::string& path, const std::string& iccPath);
/// @brief Insert an ICC profile from binary DataBuf into file \em path.
static int insertIccProfile(const std::string& path, Exiv2::DataBuf&& iccProfileBlob);
};
/// @brief %Modify the Exif data according to the commands in the modification table.
class Modify : public Task {
public:
int run(const std::string& path) override;
[[nodiscard]] Task::UniquePtr clone() const override;
//! Apply modification commands to the \em pImage, return 0 if successful.
static int applyCommands(Exiv2::Image* pImage);
private:
//! Add a metadatum to \em pImage according to \em modifyCmd
static int addMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd);
//! Set a metadatum in \em pImage according to \em modifyCmd
static int setMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd);
//! Delete a metadatum from \em pImage according to \em modifyCmd
static void delMetadatum(Exiv2::Image* pImage, const ModifyCmd& modifyCmd);
//! Register an XMP namespace according to \em modifyCmd
static void regNamespace(const ModifyCmd& modifyCmd);
};
/// @brief %Copy ISO settings from any of the Nikon makernotes to the regular Exif tag, Exif.Photo.ISOSpeedRatings.
class FixIso : public Task {
public:
int run(const std::string& path) override;
[[nodiscard]] Task::UniquePtr clone() const override;
private:
std::string path_;
};
/// @brief Fix the character encoding of Exif UNICODE user comments.
///
/// Decodes the comment using the auto-detected or specified character encoding and writes it back in UCS-2.
class FixCom : public Task {
public:
int run(const std::string& path) override;
[[nodiscard]] Task::UniquePtr clone() const override;
private:
std::string path_;
};
} // namespace Action
#endif // #ifndef ACTIONS_HPP_

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

@ -1,17 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef APP_UTILS_HPP_
#define APP_UTILS_HPP_
#include <cstdint>
namespace Util {
/*!
@brief Convert a C string to an int64_t value, which is returned in n.
Returns true if the conversion is successful, else false.
n is not modified if the conversion is unsuccessful. See strtol(2).
*/
bool strtol(const char* nptr, int64_t& n);
} // namespace Util
#endif // APP_UTILS_HPP_

File diff suppressed because it is too large Load Diff

@ -1,302 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*!
@brief Defines class Params, used for the command line handling of exiv2
@author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 08-Dec-03, ahu: created
*/
#ifndef EXIV2APP_HPP_
#define EXIV2APP_HPP_
// *****************************************************************************
// included header files
#include <exiv2/exiv2.hpp>
#include "getopt.hpp"
#include "types.hpp"
// + standard includes
#include <iostream>
#include <regex>
#include <set>
//! Command identifiers
enum class CmdId {
invalid,
add,
set,
del,
reg,
};
//! Metadata identifiers
enum class MetadataId : uint32_t {
invalid = Exiv2::mdNone, // 0
exif = Exiv2::mdExif, // 1
iptc = Exiv2::mdIptc, // 2
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
struct ModifyCmd {
//! C'tor
ModifyCmd() = default;
CmdId cmdId_{CmdId::invalid}; //!< Command identifier
std::string key_; //!< Exiv2 key string
MetadataId metadataId_{MetadataId::invalid}; //!< Metadata identifier
Exiv2::TypeId typeId_{Exiv2::invalidTypeId}; //!< Exiv2 type identifier
//! Flag to indicate if the type was explicitly specified (true)
bool explicitType_{false};
std::string value_; //!< Data
};
//! Container for modification commands
using ModifyCmds = std::vector<ModifyCmd>;
/*!
@brief Implements the command line handling for the program.
Derives from Util::Getopt to use the command line argument parsing
functionality provided there. This class is implemented as a singleton,
i.e., there is only one global instance of it, which can be accessed
from everywhere.
<b>Usage example:</b> <br>
@code
#include "params.h"
int main(int argc, char* const argv[])
{
Params& params = Params::instance();
if (params.getopt(argc, argv)) {
params.usage();
return 1;
}
if (params.help_) {
params.help();
return 0;
}
if (params.version_) {
params.version();
return 0;
}
// do something useful here...
return 0;
}
@endcode
*/
class Params : public Util::Getopt {
private:
std::string optstring_;
public:
//! Container for command files
using CmdFiles = std::vector<std::string>;
//! Container for commands from the command line
using CmdLines = std::vector<std::string>;
//! Container to store filenames.
using Files = std::vector<std::string>;
//! Container for preview image numbers
using PreviewNumbers = std::set<int>;
//! Container for keys
using Keys = std::vector<std::string>;
/*!
@brief Controls all access to the global Params instance.
@return Reference to the global Params instance.
*/
static Params& instance();
//! Prevent copy-construction: not implemented.
~Params() override = default;
Params(const Params&) = delete;
Params& operator=(const Params&) = delete;
//! Enumerates print modes
enum PrintMode {
pmSummary,
pmList,
pmComment,
pmPreview,
pmStructure,
pmXMP,
pmIccProfile,
pmRecursive,
};
//! Individual items to print, bitmap
enum PrintItem : uint32_t {
prTag = 1,
prGroup = 2,
prKey = 4,
prName = 8,
prLabel = 16,
prType = 32,
prCount = 64,
prSize = 128,
prValue = 256,
prTrans = 512,
prHex = 1024,
prSet = 2048,
prDesc = 4096
};
//! Enumerates common targets, bitmap
enum CommonTarget : uint32_t {
ctExif = 1,
ctIptc = 2,
ctComment = 4,
ctThumb = 8,
ctXmp = 16,
ctXmpSidecar = 32,
ctPreview = 64,
ctIccProfile = 128,
ctXmpRaw = 256,
ctStdInOut = 512,
ctIptcRaw = 1024
};
//! Enumerates the policies to handle existing files in rename action
enum FileExistsPolicy {
overwritePolicy,
renamePolicy,
askPolicy,
};
//! Enumerates year, month and day adjustments.
enum Yod {
yodYear,
yodMonth,
yodDay,
};
//! Structure for year, month and day adjustment command line arguments.
struct YodAdjust {
bool flag_; //!< Adjustment flag.
const char* option_; //!< Adjustment option string.
int64_t adjustment_; //!< Adjustment value.
};
bool help_{false}; //!< Help option flag.
bool version_{false}; //!< Version option flag.
bool verbose_{false}; //!< Verbose (talkative) option flag.
bool force_{false}; //!< Force overwrites flag.
bool binary_{false}; //!< Suppress long binary values.
bool unknown_{true}; //!< Suppress unknown tags.
bool preserve_{false}; //!< Preserve timestamps flag.
bool timestamp_{false}; //!< Rename also sets the file timestamp.
bool timestampOnly_{false}; //!< Rename only sets the file timestamp.
FileExistsPolicy fileExistsPolicy_{askPolicy}; //!< What to do if file to rename exists.
bool adjust_{false}; //!< Adjustment flag.
PrintMode printMode_{pmSummary}; //!< Print mode.
PrintItem printItems_{0}; //!< Print items.
MetadataId printTags_{Exiv2::mdNone}; //!< Print tags (bitmap of MetadataId flags).
//! %Action (integer rather than TaskType to avoid dependency).
int action_{0};
CommonTarget target_; //!< What common target to process.
int64_t adjustment_{0}; //!< Adjustment in seconds.
std::array<YodAdjust, 3> yodAdjust_; //!< Year, month and day adjustment info.
std::string format_; //!< Filename format (-r option arg).
bool formatSet_{false}; //!< Whether the format is set with -r
CmdFiles cmdFiles_; //!< Names of the modification command files
CmdLines cmdLines_; //!< Commands from the command line
ModifyCmds modifyCmds_; //!< Parsed modification commands
std::string jpegComment_; //!< Jpeg comment to set in the image
std::string directory_; //!< Location for files to extract/insert
std::string suffix_; //!< File extension of the file to insert
Files files_; //!< List of non-option arguments.
PreviewNumbers previewNumbers_; //!< List of preview numbers
std::vector<std::regex> greps_; //!< List of keys to 'grep' from the metadata
Keys keys_; //!< List of keys to match from the metadata
std::string charset_; //!< Charset to use for UNICODE Exif user comment
Exiv2::DataBuf stdinBuf; //!< DataBuf with the binary bytes from stdin
private:
bool first_{true};
Params();
//! @name Helpers
//@{
int setLogLevel(const std::string& optarg);
int evalGrep(const std::string& optarg);
int evalKey(const std::string& optarg);
int evalRename(int opt, const std::string& optarg);
int evalAdjust(const std::string& optarg);
int evalYodAdjust(const Yod& yod, const std::string& optarg);
int evalPrint(const std::string& optarg);
int evalPrintFlags(const std::string& optarg);
int evalDelete(const std::string& optarg);
int evalExtract(const std::string& optarg);
int evalInsert(const std::string& optarg);
int evalModify(int opt, const std::string& optarg);
//@}
public:
/*!
@brief Call Getopt::getopt() with optstring, to initiate command line
argument parsing, perform consistency checks after all command line
arguments are parsed.
@param argc Argument count as passed to main() on program invocation.
@param argv Argument array as passed to main() on program invocation.
@return 0 if successful, >0 in case of errors.
*/
int getopt(int argc, char* const argv[]);
//! Handle options and their arguments.
int option(int opt, const std::string& optarg, int optopt) override;
//! Handle non-option parameters.
int nonoption(const std::string& argv) override;
//! Print a minimal usage note to an output stream.
void usage(std::ostream& os = std::cout) const;
//! Print further usage explanations to an output stream.
void help(std::ostream& os = std::cout) const;
//! Print version information to an output stream.
static void version(bool verbose = false, std::ostream& os = std::cout);
//! getStdin binary data read from stdin to DataBuf
/*
stdin can be used by multiple images in the exiv2 command line:
For example: $ cat foo.icc | exiv2 -iC- a.jpg b.jpg c.jpg will modify the ICC profile in several images.
*/
void getStdin(Exiv2::DataBuf& buf);
}; // 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_

@ -1,112 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// included header files
#include "getopt.hpp"
#include <cstdio>
#include <cstring>
#if __has_include(<filesystem>)
#include <filesystem>
namespace fs = std::filesystem;
#else
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#endif
namespace Util {
// https://raw.githubusercontent.com/skeeto/getopt/master/getopt.h
int optind = 0;
int opterr = 1;
int optopt;
int optpos = 1;
const char* optarg;
/* A minimal POSIX getopt() implementation in ANSI C
*
* This is free and unencumbered software released into the public domain.
*
* This implementation supports the convention of resetting the option
* parser by assigning optind to 0. This resets the internal state
* appropriately.
*
* Ref: http://pubs.opengroup.org/onlinepubs/9699919799/functions/getopt.html
*/
int getopt(int argc, char* const argv[], const char* optstring) {
const char* arg;
(void)argc;
/* Reset? */
if (optind == 0) {
optind = 1;
optpos = 1;
}
arg = argv[optind];
if (arg && strcmp(arg, "--") == 0) {
optind++;
return -1;
}
if (!arg || arg[0] != '-' || !isalnum(arg[1])) {
return -1;
}
const char* opt = strchr(optstring, arg[optpos]);
optopt = arg[optpos];
if (!opt) {
if (opterr && *optstring != ':')
fprintf(stderr, "%s: illegal option: %c\n", argv[0], optopt);
return '?';
}
if (opt[1] == ':') {
if (arg[optpos + 1]) {
optarg = const_cast<char*>(arg) + optpos + 1;
optind++;
optpos = 1;
return optopt;
}
if (argv[optind + 1]) {
optarg = argv[optind + 1];
optind += 2;
optpos = 1;
return optopt;
}
if (opterr && *optstring != ':')
fprintf(stderr, "%s: option requires an argument: %c\n", argv[0], optopt);
return *optstring == ':' ? ':' : '?';
}
if (!arg[++optpos]) {
optind++;
optpos = 1;
}
return optopt;
}
// *****************************************************************************
// class Getopt
int Getopt::getopt(int argc, char* const argv[], const std::string& optstring) {
progname_ = fs::path(argv[0]).filename().string();
Util::optind = 0; // reset the Util::Getopt scanner
while (!errcnt_) {
int c = Util::getopt(argc, argv, optstring.c_str());
if (c == -1) {
break;
}
errcnt_ += option(c, Util::optarg ? Util::optarg : "", Util::optopt);
if (c == '?') {
break;
}
}
for (int i = Util::optind; i < argc; i++) {
errcnt_ += nonoption(argv[i]);
}
return errcnt_;
}
int Getopt::nonoption(const std::string& /*argv*/) {
return 0;
}
} // namespace Util

@ -1,104 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef GETOPT_H
#define GETOPT_H
#include <string>
namespace Util {
extern int optind;
extern int opterr;
extern int optopt;
extern int optpos;
extern const char* optarg;
int getopt(int argc, char* const argv[], const char* optstring);
// *********************************************************************
// class definitions
/*!
@brief Parse the command line options of a program.
A wrapper around the POSIX %getopt(3) function. Parses the command line
options and passes each option to virtual option(). A derived class
implements this method to handle options as needed. Similarly,
remaining non-option parameters are passed to the virtual nonoption()
method.
*/
class Getopt {
public:
//! Default constructor.
Getopt() = default;
//! Destructor.
virtual ~Getopt() = default;
/*!
@brief Parse command line arguments.
Parses the command line arguments. Calls option() with the
character value of the option and its argument (if any) for each
recognized option and with ':' or '?' for unrecognized options.
See the manual pages for %getopt(3) for details. In addition,
nonoption() is invoked for each remaining non-option parameter on
the command line.
@param argc Argument count as passed to main() on program invocation.
@param argv Argument array as passed to main() on program invocation.
@param optstring String containing the legitimate option characters.
@return Number of errors (the sum of the return values from option()
and nonoption()).
*/
int getopt(int argc, char* const argv[], const std::string& optstring);
/*!
@brief Callback used by getopt() to pass on each option and its
argument (if any).
Implement this method in a derived class to handle the options as
needed. See the manual pages for %getopt(3) for further details, in
particular, the semantics of optarg and optopt.
@param opt Value of the option character as returned by %getopt(3).
@param optarg The corresponding option argument.
@param optopt The actual option character in case of an unrecognized
option or a missing option argument (opt is '?' or ':').
@return 0 if successful, 1 in case of an error.
*/
virtual int option(int opt, const std::string& optarg, int optopt) = 0;
/*!
@brief Callback used by getopt() to pass on each non-option parameter
found on the command line.
Implement this method in a derived class to handle the non-option
parameters as needed. The default implementation ignores all non-option
parameters.
@param argv The non-option parameter from the command line.
@return 0 if successful, 1 in case of an error.
*/
virtual int nonoption(const std::string& argv);
//! Program name (argv[0])
[[nodiscard]] const std::string& progname() const {
return progname_;
}
//! Total number of errors returned by calls to option()
[[nodiscard]] int errcnt() const {
return errcnt_;
}
private:
std::string progname_;
int errcnt_{0};
};
} // namespace Util
#endif

@ -1,40 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <windows.h>
extern int __cdecl main(int, char*[]);
int wmain(int argc, wchar_t* argv[]) {
char** args;
int nbytes = static_cast<int>(sizeof(char*) * (argc + 1));
HANDLE heap = GetProcessHeap();
for (int i = 0; i < argc; ++i)
nbytes += WideCharToMultiByte(CP_UTF8, 0, argv[i], -1, nullptr, 0, nullptr, nullptr);
args = reinterpret_cast<char**>(HeapAlloc(heap, 0, nbytes));
args[0] = reinterpret_cast<char*>(args + argc + 1);
for (int i = 0; i < argc; ++i)
args[i + 1] = args[i] + WideCharToMultiByte(CP_UTF8, 0, argv[i], -1, args[i], nbytes, nullptr, nullptr);
args[argc] = nullptr;
argc = main(argc, args);
HeapFree(heap, 0, args);
return argc;
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) {
(void)hInstance;
(void)hPrevInstance;
(void)lpCmdLine;
(void)nCmdShow;
int argc;
wchar_t** argv;
argv = CommandLineToArgvW(GetCommandLineW(), &argc);
argc = wmain(argc, argv);
LocalFree(argv);
return argc;
}

@ -12,6 +12,7 @@ environment:
VCVARS: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat
ARCHITECTURE: x86_64
UNIT_TESTS: 1
WEBREADY: True
WARNINGS_AS_ERRORS: ON
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
CMAKE_GENERATOR: Ninja
@ -20,6 +21,7 @@ environment:
VCVARS: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat
ARCHITECTURE: x86_64
UNIT_TESTS: 1
WEBREADY: True
WARNINGS_AS_ERRORS: ON
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
CMAKE_GENERATOR: Ninja
@ -28,7 +30,17 @@ environment:
VCVARS: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat
ARCHITECTURE: x86_64
UNIT_TESTS: 1
WEBREADY: True
WARNINGS_AS_ERRORS: ON
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
CMAKE_GENERATOR: Ninja
INTEGRATION_TESTS: 0
VS_COMPILER_VERSION: 12
VCVARS: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat
ARCHITECTURE: x86_64
UNIT_TESTS: 0
WEBREADY: False
WARNINGS_AS_ERRORS: OFF
shallow_clone: true
@ -42,12 +54,10 @@ install:
- set PATH=C:\projects\deps\ninja;%PATH%
- ninja --version
- python -m pip install --upgrade pip
- pip3.exe install conan==1.35.2
- pip3.exe install lxml
- pip3.exe install conan==1.24.1
- cd %APPVEYOR_BUILD_FOLDER%
before_build:
- cmd: conan config install https://github.com/conan-io/conanclientcert.git
- cmd: conan remote list
- cmd: conan config set storage.path=c:\Users\appveyor\conanCache
- cmd: conan profile new --detect default
@ -61,14 +71,15 @@ build_script:
- cmd: cd build
- cmd: call "%VCVARS%" x86_amd64
- cmd: conan --version
- cmd: conan install .. -o webready=False --build missing
- cmd: conan install .. -o webready=%WEBREADY% --build missing
- cmd: echo %CMAKE_GENERATOR%
- cmd: cmake -G "%CMAKE_GENERATOR%" -DEXIV2_TEAM_WARNINGS_AS_ERRORS=%WARNINGS_AS_ERRORS% -DCMAKE_BUILD_TYPE=Release -DEXIV2_ENABLE_NLS=OFF -DEXIV2_ENABLE_PNG=ON -DEXIV2_ENABLE_BMFF=ON -DEXIV2_ENABLE_WEBREADY=OFF -DEXIV2_BUILD_UNIT_TESTS=%UNIT_TESTS% -DCMAKE_INSTALL_PREFIX=install ..
- cmd: cmake -G "%CMAKE_GENERATOR%" -DEXIV2_TEAM_WARNINGS_AS_ERRORS=%WARNINGS_AS_ERRORS% -DCMAKE_BUILD_TYPE=Release -DEXIV2_ENABLE_NLS=OFF -DEXIV2_ENABLE_PNG=ON -DEXIV2_ENABLE_WEBREADY=%WEBREADY% -DEXIV2_BUILD_UNIT_TESTS=%UNIT_TESTS% -DCMAKE_INSTALL_PREFIX=install ..
- cmd: cmake --build . --config Release
- cmd: cmake --build . --config Release --target install
- cmd: cd bin
- cmd: if %UNIT_TESTS% == 1 unit_tests.exe
- cmd: cd ../../tests/
- cmd: set EXIV2_EXT=.exe
- cmd: if %INTEGRATION_TESTS% == 1 %PYTHON%/python.exe runner.py -v
- cmd: cd ../build/bin
- cmd: exiv2 --version --verbose

@ -1,69 +0,0 @@
# Configuration rescued from 'old-master' branch.
# Only one Visual Studio (latest one), and all possible configurations
image: Visual Studio 2019
configuration:
- Debug
- Release
platform:
- x86
- x64
environment:
VCVARS: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat
PYTHON: "C:\\Python39-x64"
matrix:
- SHARED: ON
- SHARED: OFF
shallow_clone: true
install:
- set PATH=%PATH%;%PYTHON%/Scripts/
- echo %APPVEYOR_BUILD_FOLDER%
- if not exist deps mkdir deps
- cd deps
- if not exist ninja appveyor DownloadFile https://github.com/ninja-build/ninja/releases/download/v1.10.2/ninja-win.zip -FileName ninja.zip
- if not exist ninja 7z x ninja.zip -o%APPVEYOR_BUILD_FOLDER%\deps\ninja > nul
- set PATH=%APPVEYOR_BUILD_FOLDER%\deps\ninja;%PATH%
- ninja --version
- python -m pip install --upgrade pip
- pip3.exe install conan==1.35.2
- pip3.exe install lxml
- cd %APPVEYOR_BUILD_FOLDER%
before_build:
- cmd: conan remote list
- cmd: conan config set storage.path=c:\Users\appveyor\conanCache
- cmd: conan profile new --detect default
- cmd: conan profile update settings.compiler.version=16 default
- cmd: if "%platform%"=="x64" (set ARCHITECTURE=x86_64) else (set ARCHITECTURE=x86)
- cmd: if "%CONFIGURATION%"=="Debug" (set RUNTIME=MDd) else (set RUNTIME=MD)
- cmd: conan profile update settings.arch=%ARCHITECTURE% default
- cmd: conan profile update settings.arch_build=%ARCHITECTURE% default
- cmd: conan profile update settings.build_type=%CONFIGURATION% default
- cmd: conan profile update settings.compiler.runtime=%RUNTIME% default
- cmd: cat c:\Users\appveyor\.conan\conan.conf
- cmd: cat c:\Users\appveyor\.conan\profiles\default
build_script:
- cmd: md build
- cmd: cd build
- cmd: if "%platform%"=="x64" (set VC_ARCH=x86_amd64) else (set VC_ARCH=x86)
- cmd: call "%VCVARS%" %VC_ARCH%
- cmd: conan install .. --build missing -o webready=True
- cmd: cmake -GNinja -DBUILD_SHARED_LIBS=%SHARED% -DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DEXIV2_ENABLE_NLS=OFF -DEXIV2_ENABLE_PNG=ON -DEXIV2_ENABLE_WEBREADY=ON -DEXIV2_ENABLE_CURL=ON -DEXIV2_BUILD_UNIT_TESTS=ON -DEXIV2_ENABLE_WIN_UNICODE=OFF -DEXIV2_ENABLE_BMFF=ON -DCMAKE_INSTALL_PREFIX=install ..
- cmd: ninja
- cmd: ninja install
- cmd: cd bin
- cmd: unit_tests.exe
- cmd: cd ../../tests/
- cmd: set EXIV2_EXT=.exe
- cmd: c:\Python39-x64\python.exe runner.py -v
cache:
- deps # Ninja installation
#- c:\Users\appveyor\conanCache # Conan cache

@ -1,64 +0,0 @@
init:
- echo %PYTHON%
environment:
PYTHON: "C:/Python37-x64"
matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
BUILD: MINGW64
INTEGRATION_TESTS: 1
ARCHITECTURE: x86_64
UNIT_TESTS: 1
WEBREADY: False
WARNINGS_AS_ERRORS: OFF
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
BUILD: CYGWIN64
INTEGRATION_TESTS: 1
ARCHITECTURE: x86_64
UNIT_TESTS: 1
WEBREADY: False
WARNINGS_AS_ERRORS: OFF
shallow_clone: true
install:
- echo %APPVEYOR_BUILD_FOLDER%
- if "%BUILD%"=="MINGW64" set "PATH=c:\msys64\mingw64\bin;c:\msys64\usr\bin;c:\msys64\usr\local\bin;"
- if "%BUILD%"=="MINGW64" C:\msys64\usr\bin\bash -c "python -m pip install --upgrade pip;pip3.exe install lxml ; for i in base-devel git coreutils dos2unix tar diffutils make \
mingw-w64-x86_64-toolchain mingw-w64-x86_64-gcc mingw-w64-x86_64-gdb \
mingw-w64-x86_64-cmake mingw-w64-x86_64-gettext mingw-w64-x86_64-python3 \
mingw-w64-x86_64-libexpat mingw-w64-x86_64-libiconv mingw-w64-x86_64-zlib \
mingw-w64-x86_64-gtest ; do (echo y | pacman -S $i) ; done
- cd %APPVEYOR_BUILD_FOLDER%
- if "%BUILD%"=="CYGWIN64" set "PATH=c:\cygwin64\usr\local\bin;c:\cygwin64\bin;c:\cygwin64\usr\bin;c:\cygwin64\usr\sbin;"
- if "%BUILD%"=="CYGWIN64" C:\cygwin64\bin\bash -c "wget https://raw.githubusercontent.com/transcode-open/apt-cyg/master/apt-cyg ; chmod +x apt-cyg; mv apt-cyg /usr/local/bin"
- if "%BUILD%"=="CYGWIN64" C:\cygwin64\bin\bash -c "apt-cyg install cmake zlib-devel libexpat-devel libxml2-devel libxslt-devel python38 python38-pip python38-libxml2"
- if "%BUILD%"=="CYGWIN64" C:\cygwin64\bin\bash -c "/usr/bin/python3.8.exe -m pip install --upgrade pip"
build_script:
- cmd: set CMD=mkdir -p build
- cmd: set CMD=%CMD%; cd build
- cmd: set CMD=%CMD%; cmake .. -G 'Unix Makefiles'
- cmd: set CMD=%CMD%; cmake --build . --config Release
- cmd: rem echo %CMD%
- cd %APPVEYOR_BUILD_FOLDER%
- cmd: if "%BUILD%"=="MINGW64" C:\msys64\usr\bin\bash -c "%CMD%"
- cmd: set CMD=which python3 python
- cmd: set CMD=%CMD%; python --version
- cmd: set CMD=%CMD%; build/bin/exiv2 --verbose --version; pwd ; ls -l
- cmd: set CMD=%CMD%; cd build ; cmake --build . --config Release --target python_tests
- cmd: echo %CMD%
- cd %APPVEYOR_BUILD_FOLDER%
- cmd: if "%BUILD%"=="MINGW64" C:\msys64\usr\bin\bash -c "%CMD%"
- cmd: set "PATH=c:\cygwin64\usr\local\bin;c:\cygwin64\bin;c:\cygwin64\usr\bin;c:\cygwin64\usr\sbin;"
- cmd: set CMD=rm -rf build
- cmd: set CMD=%CMD%; mkdir -p build
- cmd: set CMD=%CMD%; cd build
- cmd: set CMD=%CMD%;cmake ..
- cmd: set CMD=%CMD%; make
- cmd: set CMD=%CMD%; make python_tests
- cmd: echo %CMD%
- cd %APPVEYOR_BUILD_FOLDER%
- cmd: if "%BUILD%"=="CYGWIN64" C:\cygwin64\bin\bash -c "%CMD%"

@ -0,0 +1,34 @@
#!/bin/bash
set -e # Enables cheking of return values from each command
set -x # Prints every command
python --version
python3 --version
if [[ "$(uname -s)" == 'Linux' ]]; then
sudo apt-get update
sudo apt-get install cmake zlib1g-dev libssh-dev python-pip libxml2-utils
if [ -n "$WITH_VALGRIND" ]; then
sudo apt-get install valgrind
fi
sudo pip install virtualenv
virtualenv conan
source conan/bin/activate
pip install conan==1.22.0
pip install codecov
else
sudo pip3 install virtualenv
virtualenv conan
source conan/bin/activate
pip3 install conan==1.22.0
pip3 install codecov
fi
conan --version
conan config set storage.path=~/conanData
conan profile new default --detect
if [[ "$(uname -s)" == 'Linux' ]]; then
conan profile update settings.compiler.libcxx=libstdc++11 default
fi

@ -8,79 +8,64 @@
debian_build_gtest() {
[ -d gtest_build ] || mkdir gtest_build
cd gtest_build
cmake -GNinja -DBUILD_SHARED_LIBS=1 /usr/src/googletest/googletest
cmake --build .
if [ -f "lib/libgtest.so" ]; then
# Ubuntu 20.04 with gtest 1.10
cp lib/libgtest* /usr/lib/
else
# Debian 9 with gtest 1.8
cp libgtest* /usr/lib/
fi
cd ..
}
# Centos doesn't have a working version of the inih library, so we need to build it ourselves.
centos_build_inih() {
[-d inih_build ] || git clone https://github.com/benhoyt/inih.git inih_build
cd inih_build
git checkout r58
meson --buildtype=plain builddir
meson compile -C builddir
meson install -C builddir
cmake -DBUILD_SHARED_LIBS=1 /usr/src/googletest/googletest
make
cp libgtest* /usr/lib/
cd ..
}
# workaround for really bare-bones Archlinux containers:
if [ -x "$(command -v pacman)" ]; then
pacman --noconfirm -Sy
pacman --noconfirm --needed -S grep gawk sed
pacman --noconfirm -S grep gawk sed
fi
distro_id=$(grep '^ID=' /etc/os-release|awk -F = '{print $2}'|sed 's/\"//g')
case "$distro_id" in
'fedora')
dnf -y --refresh install gcc-c++ clang cmake ninja-build expat-devel zlib-devel brotli-devel libssh-devel libcurl-devel gmock-devel glibc-langpack-en inih-devel
dnf -y --refresh install gcc-c++ clang cmake make ccache expat-devel zlib-devel libssh-devel libcurl-devel gtest-devel which dos2unix glibc-langpack-en diffutils
;;
'debian')
apt-get update
apt-get install -y cmake ninja-build g++ clang libexpat1-dev zlib1g-dev libbrotli-dev libssh-dev libcurl4-openssl-dev libgmock-dev libxml2-utils libinih-dev
# debian_build_gtest
apt-get install -y cmake g++ clang make ccache python3 libexpat1-dev zlib1g-dev libssh-dev libcurl4-openssl-dev libgtest-dev libxml2-utils
debian_build_gtest
;;
'arch')
pacman --noconfirm -Syu
pacman --noconfirm --needed -S gcc clang cmake ninja expat zlib brotli libssh curl gtest libinih
pacman --noconfirm -S gcc clang cmake make ccache expat zlib libssh curl gtest python dos2unix which diffutils
;;
'ubuntu')
apt-get update
apt-get install -y cmake ninja-build g++ clang libexpat1-dev zlib1g-dev libbrotli-dev libssh-dev libcurl4-openssl-dev libgmock-dev libxml2-utils libinih-dev
# debian_build_gtest
;;
'alpine')
apk update
apk add gcc g++ clang cmake samurai expat-dev zlib-dev brotli-dev libssh-dev curl-dev gtest gtest-dev gmock libintl gettext-dev libxml2-utils inih-dev inih-inireader-dev
;;
'rhel')
dnf clean all
dnf -y install gcc-c++ clang cmake ninja-build expat-devel zlib-devel brotli-devel libssh-devel libcurl-devel inih-devel
apt-get install -y cmake g++ clang make ccache python3 libexpat1-dev zlib1g-dev libssh-dev libcurl4-openssl-dev libgtest-dev google-mock libxml2-utils
debian_build_gtest
;;
'centos')
dnf clean all
dnf -y install gcc-c++ clang cmake expat-devel zlib-devel brotli-devel libssh-devel libcurl-devel git
dnf -y --enablerepo=crb install ninja-build meson
centos_build_inih
'centos'|'rhel')
yum -y install epel-release
# enable copr for gtest
curl https://copr.fedorainfracloud.org/coprs/defolos/devel/repo/epel-7/defolos-devel-epel-7.repo > /etc/yum.repos.d/_copr_defolos-devel.repo
yum clean all
yum -y install gcc-c++ clang cmake3 make ccache expat-devel zlib-devel libssh-devel libcurl-devel gtest-devel which python3 dos2unix
# symlink up to date versions of cmake to 'default' name
mv /bin/cmake /bin/.cmake.old
ln -s /bin/cmake3 /bin/cmake
;;
'opensuse-tumbleweed')
'opensuse'|'opensuse-tumbleweed')
zypper --non-interactive refresh
zypper --non-interactive install gcc-c++ clang cmake ninja libexpat-devel zlib-devel libbrotli-devel libssh-devel libcurl-devel gmock libxml2-tools libinih-devel
zypper --non-interactive install gcc-c++ clang cmake make ccache libexpat-devel zlib-devel libssh-devel curl tar libcurl-devel git which dos2unix libxml2-tools
pushd /tmp
curl -LO https://github.com/google/googletest/archive/release-1.8.0.tar.gz
tar xzf release-1.8.0.tar.gz
mkdir -p googletest-release-1.8.0/build
pushd googletest-release-1.8.0/build
cmake .. ; make ; make install
popd
popd
;;
*)
echo "Sorry, no predefined dependencies for your distribution $distro_id exist yet"

@ -0,0 +1,41 @@
#!/bin/bash
set -e
set -x
source conan/bin/activate
if [[ "$(uname -s)" == 'Linux' ]]; then
if [ "$CC" == "clang" ]; then
# clang + Ubuntu don't like to run with UBSAN, but ASAN works
export CMAKE_OPTIONS="$CMAKE_OPTIONS -DCMAKE_CXX_FLAGS=\"-fsanitize=address\" -DCMAKE_C_FLAGS=\"-fsanitize=address\" -DCMAKE_EXE_LINKER_FLAGS=\"-fsanitize=address\" -DCMAKE_MODULE_LINKER_FLAGS=\"-fsanitize=address\""
elif [ -n "$WITH_VALGRIND" ]; then
export EXIV2_VALGRIND="valgrind --quiet"
else
export CMAKE_OPTIONS="$CMAKE_OPTIONS -DEXIV2_TEAM_USE_SANITIZERS=ON"
fi
else
export CMAKE_OPTIONS="$CMAKE_OPTIONS -DEXIV2_TEAM_USE_SANITIZERS=ON"
fi
CMAKE_OPTIONS="$CMAKE_OPTIONS -DCMAKE_CXX_FLAGS=-Wno-deprecated"
mkdir build
cd build
conan install .. -o webready=True --build missing
cmake ${CMAKE_OPTIONS} -DEXIV2_TEAM_WARNINGS_AS_ERRORS=ON -DCMAKE_INSTALL_PREFIX=install ..
make -j 2
make tests
make install
# Check for detecting issues with the installation of headers
if [ `ls install/include/exiv2/ | wc -l` > 10 ]; then
echo Headers installed correctly
else
echo There was some problem with the installation of the public headers
exit 1
fi
if [ -n "$COVERAGE" ]; then
bash <(curl -s https://codecov.io/bash)
fi

@ -79,7 +79,7 @@ if __name__ == '__main__':
description="Build and test exiv2 using a matrix of build switches")
parser.add_argument(
"--compilers",
help="Compilers to be used to build exiv2 (when none are specified, "
help="Compilers to be used to build exiv2 (when none ore specified, "
"then the default compiler will be used)",
nargs='*',
default=["gcc", "clang"],
@ -116,8 +116,8 @@ if __name__ == '__main__':
help="Additional flags for cmake",
type=str,
nargs='?',
default="-DEXIV2_TEAM_EXTRA_WARNINGS=ON "
"-DEXIV2_ENABLE_WEBREADY=ON -DEXIV2_BUILD_UNIT_TESTS=ON -DEXIV2_ENABLE_BMFF=ON "
default="-DEXIV2_TEAM_EXTRA_WARNINGS=ON -DEXIV2_ENABLE_VIDEO=ON "
"-DEXIV2_ENABLE_WEBREADY=ON -DEXIV2_BUILD_UNIT_TESTS=ON "
"-DBUILD_WITH_CCACHE=ON -DEXIV2_ENABLE_CURL=ON"
)

@ -268,7 +268,7 @@ OPTIMIZE_OUTPUT_VHDL = NO
# parses. With this tag you can assign which parser to use for a given
# extension. Doxygen has a built-in mapping, but you can override or extend it
# using this tag. The format is ext=language, where ext is a file extension, and
# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
# Fortran. In the later case the parser tries to guess whether the code is fixed
@ -675,7 +675,7 @@ SHOW_NAMESPACES = YES
# The FILE_VERSION_FILTER tag can be used to specify a program or script that
# doxygen should invoke to get the current version for each file (typically from
# the version control system). Doxygen will invoke the program by executing (via
# popen()) the command input-file, where command is the value of the
# popen()) the command command input-file, where command is the value of the
# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
# by doxygen. Whatever the program writes to standard output is used as the file
# version. For an example see the documentation.
@ -1474,7 +1474,7 @@ EXT_LINKS_IN_WINDOW = NO
FORMULA_FONTSIZE = 10
# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
# Use the FORMULA_TRANPARENT tag to determine whether or not the images
# generated for formulas are transparent PNGs. Transparent PNGs are not
# supported properly for IE 6.0, but are supported on all modern browsers.
#
@ -1486,7 +1486,7 @@ FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
# http://www.mathjax.org) which uses client side JavaScript for the rendering
# http://www.mathjax.org) which uses client side Javascript for the rendering
# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
# installed or if you want to formulas look prettier in the HTML output. When
# enabled you may also need to install MathJax separately and configure the path
@ -1556,7 +1556,7 @@ MATHJAX_CODEFILE =
SEARCHENGINE = YES
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
# implemented using a web server instead of a web client using JavaScript. There
# implemented using a web server instead of a web client using Javascript. There
# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
# setting. When disabled, doxygen will generate a PHP script for searching and
# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing

@ -1,45 +0,0 @@
#***************************************************************************
# _ _ ____ _
# Project ___| | | | _ \| |
# / __| | | | |_) | |
# | (__| |_| | _ <| |___
# \___|\___/|_| \_\_____|
#
# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at https://curl.se/docs/copyright.html.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is
# furnished to do so, under the terms of the COPYING file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
###########################################################################
include(FindPackageHandleStandardArgs)
find_path(BROTLI_INCLUDE_DIR "brotli/decode.h")
find_library(BROTLICOMMON_LIBRARY NAMES brotlicommon)
find_library(BROTLIDEC_LIBRARY NAMES brotlidec)
find_package_handle_standard_args(Brotli
FOUND_VAR
BROTLI_FOUND
REQUIRED_VARS
BROTLIDEC_LIBRARY
BROTLICOMMON_LIBRARY
BROTLI_INCLUDE_DIR
FAIL_MESSAGE
"Could NOT find Brotli"
)
set(Brotli_INCLUDE_DIRS ${BROTLI_INCLUDE_DIR})
set(Brotli_LIBRARIES ${BROTLICOMMON_LIBRARY} ${BROTLIDEC_LIBRARY})
mark_as_advanced(BROTLI_INCLUDE_DIR)
mark_as_advanced(BROTLICOMMON_LIBRARY)
mark_as_advanced(BROTLIDEC_LIBRARY)

@ -1,247 +0,0 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#[=======================================================================[.rst:
FindFilesystem
##############
This module supports the C++17 standard library's filesystem utilities. Use the
:imp-target:`std::filesystem` imported target to
Options
*******
The ``COMPONENTS`` argument to this module supports the following values:
.. find-component:: Experimental
:name: fs.Experimental
Allows the module to find the "experimental" Filesystem TS version of the
Filesystem library. This is the library that should be used with the
``std::experimental::filesystem`` namespace.
.. find-component:: Final
:name: fs.Final
Finds the final C++17 standard version of the filesystem library.
If no components are provided, behaves as if the
:find-component:`fs.Final` component was specified.
If both :find-component:`fs.Experimental` and :find-component:`fs.Final` are
provided, first looks for ``Final``, and falls back to ``Experimental`` in case
of failure. If ``Final`` is found, :imp-target:`std::filesystem` and all
:ref:`variables <fs.variables>` will refer to the ``Final`` version.
Imported Targets
****************
.. imp-target:: std::filesystem
The ``std::filesystem`` imported target is defined when any requested
version of the C++ filesystem library has been found, whether it is
*Experimental* or *Final*.
If no version of the filesystem library is available, this target will not
be defined.
.. note::
This target has ``cxx_std_17`` as an ``INTERFACE``
:ref:`compile language standard feature <req-lang-standards>`. Linking
to this target will automatically enable C++17 if no later standard
version is already required on the linking target.
.. _fs.variables:
Variables
*********
.. variable:: CXX_FILESYSTEM_IS_EXPERIMENTAL
Set to ``TRUE`` when the :find-component:`fs.Experimental` version of C++
filesystem library was found, otherwise ``FALSE``.
.. variable:: CXX_FILESYSTEM_HAVE_FS
Set to ``TRUE`` when a filesystem header was found.
.. variable:: CXX_FILESYSTEM_HEADER
Set to either ``filesystem`` or ``experimental/filesystem`` depending on
whether :find-component:`fs.Final` or :find-component:`fs.Experimental` was
found.
.. variable:: CXX_FILESYSTEM_NAMESPACE
Set to either ``std::filesystem`` or ``std::experimental::filesystem``
depending on whether :find-component:`fs.Final` or
:find-component:`fs.Experimental` was found.
Examples
********
Using `find_package(Filesystem)` with no component arguments:
.. code-block:: cmake
find_package(Filesystem REQUIRED)
add_executable(my-program main.cpp)
target_link_libraries(my-program PRIVATE std::filesystem)
#]=======================================================================]
if(TARGET std::filesystem)
# This module has already been processed. Don't do it again.
return()
endif()
cmake_minimum_required(VERSION 3.10)
include(CMakePushCheckState)
include(CheckIncludeFileCXX)
# If we're not cross-compiling, try to run test executables.
# Otherwise, assume that compile + link is a sufficient check.
if(CMAKE_CROSSCOMPILING)
include(CheckCXXSourceCompiles)
macro(_cmcm_check_cxx_source code var)
check_cxx_source_compiles("${code}" ${var})
endmacro()
else()
include(CheckCXXSourceRuns)
macro(_cmcm_check_cxx_source code var)
check_cxx_source_runs("${code}" ${var})
endmacro()
endif()
cmake_push_check_state()
set(CMAKE_REQUIRED_QUIET ${Filesystem_FIND_QUIETLY})
# All of our tests required C++17 or later
set(CMAKE_CXX_STANDARD 17)
# Normalize and check the component list we were given
set(want_components ${Filesystem_FIND_COMPONENTS})
if(Filesystem_FIND_COMPONENTS STREQUAL "")
set(want_components Final)
endif()
# Warn on any unrecognized components
set(extra_components ${want_components})
list(REMOVE_ITEM extra_components Final Experimental)
foreach(component IN LISTS extra_components)
message(WARNING "Extraneous find_package component for Filesystem: ${component}")
endforeach()
# Detect which of Experimental and Final we should look for
set(find_experimental TRUE)
set(find_final TRUE)
if(NOT "Final" IN_LIST want_components)
set(find_final FALSE)
endif()
if(NOT "Experimental" IN_LIST want_components)
set(find_experimental FALSE)
endif()
if(find_final)
check_include_file_cxx("filesystem" _CXX_FILESYSTEM_HAVE_HEADER)
mark_as_advanced(_CXX_FILESYSTEM_HAVE_HEADER)
if(_CXX_FILESYSTEM_HAVE_HEADER)
# We found the non-experimental header. Don't bother looking for the
# experimental one.
set(find_experimental FALSE)
endif()
else()
set(_CXX_FILESYSTEM_HAVE_HEADER FALSE)
endif()
if(find_experimental)
check_include_file_cxx("experimental/filesystem" _CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER)
mark_as_advanced(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER)
else()
set(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER FALSE)
endif()
if(_CXX_FILESYSTEM_HAVE_HEADER)
set(_have_fs TRUE)
set(_fs_header filesystem)
set(_fs_namespace std::filesystem)
set(_is_experimental FALSE)
elseif(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER)
set(_have_fs TRUE)
set(_fs_header experimental/filesystem)
set(_fs_namespace std::experimental::filesystem)
set(_is_experimental TRUE)
else()
set(_have_fs FALSE)
endif()
set(CXX_FILESYSTEM_HAVE_FS ${_have_fs} CACHE BOOL "TRUE if we have the C++ filesystem headers")
set(CXX_FILESYSTEM_HEADER ${_fs_header} CACHE STRING "The header that should be included to obtain the filesystem APIs")
set(CXX_FILESYSTEM_NAMESPACE ${_fs_namespace} CACHE STRING "The C++ namespace that contains the filesystem APIs")
set(CXX_FILESYSTEM_IS_EXPERIMENTAL ${_is_experimental} CACHE BOOL "TRUE if the C++ filesystem library is the experimental version")
set(_found FALSE)
if(CXX_FILESYSTEM_HAVE_FS)
# We have some filesystem library available. Do link checks
string(CONFIGURE [[
#include <cstdlib>
#include <@CXX_FILESYSTEM_HEADER@>
int main() {
auto cwd = @CXX_FILESYSTEM_NAMESPACE@::current_path();
printf("%s", cwd.c_str());
return EXIT_SUCCESS;
}
]] code @ONLY)
# Check a simple filesystem program without any linker flags
_cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_NO_LINK_NEEDED)
set(can_link ${CXX_FILESYSTEM_NO_LINK_NEEDED})
if(NOT CXX_FILESYSTEM_NO_LINK_NEEDED)
set(prev_libraries ${CMAKE_REQUIRED_LIBRARIES})
# Add the libstdc++ flag
set(CMAKE_REQUIRED_LIBRARIES ${prev_libraries} -lstdc++fs)
_cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_STDCPPFS_NEEDED)
set(can_link ${CXX_FILESYSTEM_STDCPPFS_NEEDED})
if(NOT CXX_FILESYSTEM_STDCPPFS_NEEDED)
# Try the libc++ flag
set(CMAKE_REQUIRED_LIBRARIES ${prev_libraries} -lc++fs)
_cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_CPPFS_NEEDED)
set(can_link ${CXX_FILESYSTEM_CPPFS_NEEDED})
endif()
endif()
if(can_link)
add_library(std::filesystem INTERFACE IMPORTED)
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_COMPILE_FEATURES cxx_std_17)
set(_found TRUE)
if(CXX_FILESYSTEM_NO_LINK_NEEDED)
# Nothing to add...
elseif(CXX_FILESYSTEM_STDCPPFS_NEEDED)
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_LINK_LIBRARIES -lstdc++fs)
elseif(CXX_FILESYSTEM_CPPFS_NEEDED)
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_LINK_LIBRARIES -lc++fs)
endif()
endif()
endif()
cmake_pop_check_state()
set(Filesystem_FOUND ${_found} CACHE BOOL "TRUE if we can run a program using std::filesystem" FORCE)
if(Filesystem_FIND_REQUIRED AND NOT Filesystem_FOUND)
message(FATAL_ERROR "Cannot run simple program using std::filesystem")
endif()

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

@ -0,0 +1,50 @@
# - Try to find the Regex library
#
# Once done this will define
#
# REGEX_FOUND - system has libregex
# REGEX_INCLUDE_DIR - the libregex include directory
# REGEX_LIBRARIES - Link these to use libregex
#
# Copyright (c) 2018, Gilles Caulier, <caulier dot gilles at gmail dot com>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
if ( NOT MSVC AND NOT MINGW AND NOT MSYS )
find_path(Regex_INCLUDE_DIR
NAMES regex.h
DOC "libregex include directory"
)
mark_as_advanced(Regex_INCLUDE_DIR)
find_library(Regex_LIBRARY "regex"
DOC "libregex libraries"
)
mark_as_advanced(Regex_LIBRARY)
find_package_handle_standard_args(Regex
FOUND_VAR Regex_FOUND
REQUIRED_VARS Regex_INCLUDE_DIR
FAIL_MESSAGE "Failed to find libregex"
)
if(REGEX_FOUND)
set(REGEX_INCLUDE_DIRS ${Regex_INCLUDE_DIRS})
if(Regex_LIBRARY)
set(REGEX_LIBRARIES ${Regex_LIBRARY})
else()
unset(REGEX_LIBRARIES)
endif()
endif()
endif()

@ -1,45 +0,0 @@
set(inih_LIBRARY_NAMES "inih" "libinih")
set(inih_inireader_LIBRARY_NAMES "INIReader" "libINIReader")
find_path(inih_INCLUDE_DIR
NAMES "ini.h"
DOC "inih include directory")
find_path(inih_inireader_INCLUDE_DIR
NAMES "INIReader.h"
DOC "INIReader include directory")
find_library(inih_LIBRARY
NAMES ${inih_LIBRARY_NAMES}
DOC "inih library")
find_library(inih_inireader_LIBRARY
NAMES ${inih_inireader_LIBRARY_NAMES}
DOC "inih library")
mark_as_advanced(inih_INCLUDE_DIR)
mark_as_advanced(inih_LIBRARY)
mark_as_advanced(inih_inireader_INCLUDE_DIR)
mark_as_advanced(inih_inireader_LIBRARY)
find_package_handle_standard_args(inih REQUIRED_VARS inih_LIBRARY inih_INCLUDE_DIR inih_inireader_INCLUDE_DIR inih_inireader_LIBRARY)
if(NOT inih_FOUND)
message(FATAL_ERROR "inih library not found")
endif()
set(inih_INCLUDE_DIRS "${inih_INCLUDE_DIR}")
set(inih_LIBRARIES "${inih_LIBRARY}")
if(NOT TARGET inih::libinih)
add_library(inih::libinih INTERFACE IMPORTED)
endif()
set_property(TARGET inih::libinih PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${inih_INCLUDE_DIRS}")
set_property(TARGET inih::libinih PROPERTY INTERFACE_LINK_LIBRARIES "${inih_LIBRARIES}")
set(inih_inireader_INCLUDE_DIRS "${inih_inireader_INCLUDE_DIR}")
set(inih_inireader_LIBRARIES "${inih_inireader_LIBRARY}")
if(NOT TARGET inih::inireader)
add_library(inih::inireader INTERFACE IMPORTED)
endif()
set_property(TARGET inih::inireader PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${inih_inireader_INCLUDE_DIRS}")
set_property(TARGET inih::inireader PROPERTY INTERFACE_LINK_LIBRARIES "${inih_inireader_LIBRARIES}")

@ -1,24 +0,0 @@
# This module provides function for joining paths
# known from most languages
#
# Original license:
# SPDX-License-Identifier: (MIT OR CC0-1.0)
# Copyright 2020 Jan Tojnar
# https://github.com/jtojnar/cmake-snips
#
# Modelled after Pythons os.path.join
# https://docs.python.org/3.7/library/os.path.html#os.path.join
# Windows not supported
function(join_paths joined_path first_path_segment)
set(temp_path "${first_path_segment}")
foreach(current_segment IN LISTS ARGN)
if(NOT ("${current_segment}" STREQUAL ""))
if(IS_ABSOLUTE "${current_segment}")
set(temp_path "${current_segment}")
else()
set(temp_path "${temp_path}/${current_segment}")
endif()
endif()
endforeach()
set(${joined_path} "${temp_path}" PARENT_SCOPE)
endfunction()

@ -1,9 +1,4 @@
# These flags applies to exiv2lib, the applications, and to the xmp code
include(CheckCXXCompilerFlag)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS ON)
if ( MINGW OR UNIX OR MSYS ) # MINGW, Linux, APPLE, CYGWIN
if (${CMAKE_CXX_COMPILER_ID} STREQUAL GNU)
@ -27,28 +22,23 @@ if ( MINGW OR UNIX OR MSYS ) # MINGW, Linux, APPLE, CYGWIN
if (COMPILER_IS_GCC OR COMPILER_IS_CLANG)
# This fails under Fedora - MinGW - Gcc 8.3
if (NOT (MINGW OR CYGWIN OR CMAKE_HOST_SOLARIS))
if (NOT APPLE) # Don't know why this isn't working correctly on Apple with M1 processor
check_cxx_compiler_flag(-fstack-clash-protection HAS_FSTACK_CLASH_PROTECTION)
endif()
check_cxx_compiler_flag(-fcf-protection HAS_FCF_PROTECTION)
check_cxx_compiler_flag(-fstack-protector-strong HAS_FSTACK_PROTECTOR_STRONG)
if(HAS_FSTACK_CLASH_PROTECTION)
add_compile_options(-fstack-clash-protection)
endif()
if(HAS_FCF_PROTECTION)
add_compile_options(-fcf-protection)
# This fails under Fedora, MinGW GCC 8.3.0 and CYGWIN/MSYS 9.3.0
if (NOT (MINGW OR CMAKE_HOST_SOLARIS OR CYGWIN OR MSYS) )
if (COMPILER_IS_GCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0)
add_compile_options(-fstack-clash-protection -fcf-protection)
endif()
if(BUILD_WITH_STACK_PROTECTOR AND HAS_FSTACK_PROTECTOR_STRONG)
if( (COMPILER_IS_GCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 5.0) # Not in GCC 4.8
OR (COMPILER_IS_CLANG AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 3.7) # Not in Clang 3.4.2
)
add_compile_options(-fstack-protector-strong)
add_link_options(-fstack-protector-strong)
endif()
endif()
add_compile_options(-Wp,-D_GLIBCXX_ASSERTIONS)
if (CMAKE_BUILD_TYPE STREQUAL Release AND NOT (APPLE OR MINGW OR MSYS))
if (CMAKE_BUILD_TYPE STREQUAL Release AND NOT APPLE AND NOT MSYS)
add_compile_options(-Wp,-D_FORTIFY_SOURCE=2) # Requires to compile with -O2
endif()
@ -60,26 +50,10 @@ if ( MINGW OR UNIX OR MSYS ) # MINGW, Linux, APPLE, CYGWIN
endif()
add_compile_options(-Wall -Wcast-align -Wpointer-arith -Wformat-security -Wmissing-format-attribute -Woverloaded-virtual -W)
add_compile_options(-Wno-error=format-nonliteral)
# This seems to be causing issues in the Fedora_MinGW GitLab job
#add_compile_options(-fasynchronous-unwind-tables)
# The EXIV2_TEAM_OSS_FUZZ option is used by the OSS-Fuzz build script:
# https://github.com/google/oss-fuzz/tree/master/projects/exiv2/build.sh
# OSS-Fuzz wants full control of the sanitizer flags, so we don't add
# the `-fsanitize=fuzzer-no-link` flag when building for OSS-Fuzz.
if( EXIV2_BUILD_FUZZ_TESTS AND NOT EXIV2_TEAM_OSS_FUZZ )
if (NOT COMPILER_IS_CLANG)
message(FATAL_ERROR "You need to build with Clang for the fuzzers to work. "
"Use Clang")
endif()
set(FUZZER_FLAGS "-fsanitize=fuzzer-no-link")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FUZZER_FLAGS}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FUZZER_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${FUZZER_FLAGS}")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${FUZZER_FLAGS}")
endif()
if ( EXIV2_TEAM_USE_SANITIZERS )
# ASAN is available in gcc from 4.8 and UBSAN from 4.9
@ -121,7 +95,6 @@ if(MSVC)
PATHS ENV CLCACHE_PATH
PATH_SUFFIXES Scripts clcache-4.1.0
)
if (CLCACHE)
message(STATUS "clcache found in ${CLCACHE}")
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
@ -131,12 +104,6 @@ if(MSVC)
endif()
endif()
# Make Debug builds a little faster without sacrificing debugging experience
#set (CMAKE_CXX_FLAGS_DEBUG "/MDd /Zi /Ob0 /Od /RTC1")
set (CMAKE_CXX_FLAGS_DEBUG "/MDd /Zi /Ob0 /Ox /Zo")
# /Ox (Enable Most Speed Optimizations)
# /Zo (Enhance Optimized Debugging)
set(variables
CMAKE_CXX_FLAGS_DEBUG
CMAKE_CXX_FLAGS_MINSIZEREL
@ -167,7 +134,13 @@ if(MSVC)
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
endif ()
add_compile_options(/MP) # Object Level Parallelism
add_compile_options(/utf-8) # Set source and execution character sets to UTF-8
add_definitions(-DNOMINMAX) # This definition is not only needed for Exiv2 but also for xmpsdk
# Object Level Parallelism
add_compile_options(/MP)
add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN)
# https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/
if (MSVC_VERSION GREATER_EQUAL "1910") # VS2017 and up
add_compile_options("/Zc:__cplusplus")
endif()
endif()

@ -1,14 +1,8 @@
# These flags only applies to exiv2lib, and the applications, but not to the xmp code
include(CheckCXXCompilerFlag)
if (COMPILER_IS_GCC OR COMPILER_IS_CLANG) # MINGW, Linux, APPLE, CYGWIN
if ( EXIV2_TEAM_WARNINGS_AS_ERRORS )
add_compile_options(-Werror)
check_cxx_compiler_flag(-Wdeprecated-copy DEPRECATED_COPY)
if ( DEPRECATED_COPY)
add_compile_options(-Wdeprecated-copy)
endif ()
add_compile_options(-Werror -Wno-error=deprecated-declarations)
endif ()
if ( EXIV2_TEAM_EXTRA_WARNINGS )
@ -21,10 +15,10 @@ if (COMPILER_IS_GCC OR COMPILER_IS_CLANG) # MINGW, Linux, APPLE, CYGWIN
" -Wlogical-op"
" -Wdouble-promotion"
" -Wshadow"
" -Wuseless-cast"
" -Wpointer-arith" # This warning is also enabled by -Wpedantic
" -Wformat=2"
#" -Wold-style-cast"
#" -Wuseless-cast" Disabled mainly because of conversion of socket types (different types on OSs)
)
endif ()

@ -3,56 +3,79 @@
#ifndef _EXV_CONF_H_
#define _EXV_CONF_H_
// Defined if you want to use libssh for SshIO.
#cmakedefine EXV_USE_SSH
// Define to 1 if you want to use libcurl in httpIO.
#cmakedefine EXV_USE_CURL
// Define to 1 if you want to enable filesystem access
#cmakedefine EXV_ENABLE_FILESYSTEM
// Define if you require webready support.
#cmakedefine EXV_ENABLE_WEBREADY
// Define if you have the <libintl.h> header file.
#cmakedefine EXV_HAVE_LIBINTL_H
// Define if you want translation of program messages to the user's native language
#cmakedefine EXV_ENABLE_NLS
// Define if you want to enable the decoding of video metadata
// Define if you want video support.
#cmakedefine EXV_ENABLE_VIDEO
// Define if you want BMFF support.
#cmakedefine EXV_ENABLE_BMFF
// Define if you want to use the inih library.
#cmakedefine EXV_ENABLE_INIH
// Define if you have the strerror_r function.
#cmakedefine EXV_HAVE_STRERROR_R
// Define if the strerror_r function returns char*.
#cmakedefine EXV_STRERROR_R_CHAR_P
// Define to enable the Windows unicode path support.
#cmakedefine EXV_UNICODE_PATH
/* Define to `const' or to empty, depending on the second argument of `iconv'. */
#cmakedefine ICONV_ACCEPTS_CONST_INPUT
#if defined(__NetBSD__)
#include <sys/param.h>
#if __NetBSD_Prereq__(9,99,17)
#define NETBSD_POSIX_ICONV 1
#else
#define NETBSD_POSIX_ICONV 0
#endif
#endif
#if defined(ICONV_ACCEPTS_CONST_INPUT) || (defined(__NetBSD__) && !NETBSD_POSIX_ICONV)
#if defined(ICONV_ACCEPTS_CONST_INPUT) || defined(__NetBSD__)
#define EXV_ICONV_CONST const
#else
#define EXV_ICONV_CONST
#endif
// Define if you have the zlib library.
// Define if you have the <regex.h> header file.
#cmakedefine EXV_HAVE_REGEX_H
// Define if have the <memory.h> header file.
#cmakedefine EXV_HAVE_MEMORY_H
// Define if stdbool.h conforms to C99.
#cmakedefine EXV_HAVE_STDBOOL_H
// Define if you have the <stdint.h> header file.
#cmakedefine EXV_HAVE_STDINT_H
// Define if you have the <strings.h> header file.
#cmakedefine EXV_HAVE_STRINGS_H
// Define if you have the mmap function.
#cmakedefine EXV_HAVE_MMAP
// Define if you have the munmap function.
#cmakedefine EXV_HAVE_MUNMAP
// Define if you have <sys/stat.h> header file.
#cmakedefine EXV_HAVE_SYS_STAT_H
// Define if you have the <sys/types.h> header file.
#cmakedefine EXV_HAVE_SYS_TYPES_H
/* Define if you have the <unistd.h> header file. */
#cmakedefine EXV_HAVE_UNISTD_H
// Define if you have the <sys/mman.h> header file.
#cmakedefine EXV_HAVE_SYS_MMAN_H
// Define if you have are using the zlib library.
#cmakedefine EXV_HAVE_LIBZ
// Define if you have the brotli library.
#cmakedefine EXV_HAVE_BROTLI
// Define if you have the <process.h> header file.
#cmakedefine EXV_HAVE_PROCESS_H
/* Define if you have (Exiv2/xmpsdk) Adobe XMP Toolkit. */
#cmakedefine EXV_HAVE_XMP_TOOLKIT
@ -66,10 +89,10 @@
/* Define to the version of this package. */
#cmakedefine EXV_PACKAGE_VERSION "@PROJECT_VERSION@"
#define EXIV2_MAJOR_VERSION (@PROJECT_VERSION_MAJOR@U)
#define EXIV2_MINOR_VERSION (@PROJECT_VERSION_MINOR@U)
#define EXIV2_PATCH_VERSION (@PROJECT_VERSION_PATCH@U)
#define EXIV2_TWEAK_VERSION (@PROJECT_VERSION_TWEAK@U)
#define EXIV2_MAJOR_VERSION (@PROJECT_VERSION_MAJOR@)
#define EXIV2_MINOR_VERSION (@PROJECT_VERSION_MINOR@)
#define EXIV2_PATCH_VERSION (@PROJECT_VERSION_PATCH@)
#define EXIV2_TWEAK_VERSION (@PROJECT_VERSION_TWEAK@)
// Definition to enable translation of Nikon lens names.
#cmakedefine EXV_HAVE_LENSDATA
@ -77,4 +100,7 @@
// Define if you have the iconv function.
#cmakedefine EXV_HAVE_ICONV
// Definition to enable conversion of UCS2 encoded Windows tags to UTF-8.
#cmakedefine EXV_HAVE_PRINTUCS2
#endif /* !_EXV_CONF_H_ */

@ -1,13 +1,11 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
libdir=@EXIV2_LIBDIR@
includedir=@EXIV2_INCLUDEDIR@
libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
Name: exiv2
Description: @PROJECT_DESCRIPTION@
Version: @PROJECT_VERSION@
URL: @PACKAGE_URL@
Requires.private: @requires_private_for_pc_file@
Libs: -L${libdir} -lexiv2
Libs.private: @libs_private_for_pc_file@
Cflags: -I${includedir}

@ -1,19 +0,0 @@
@PACKAGE_INIT@
cmake_minimum_required(VERSION 3.5)
include(CMakeFindDependencyMacro)
if(@EXIV2_ENABLE_PNG@) # if(EXIV2_ENABLE_PNG)
find_dependency(ZLIB REQUIRED)
endif()
if(@EXIV2_ENABLE_XMP@) # if(EXIV2_ENABLE_XMP)
find_dependency(EXPAT REQUIRED)
endif()
include("${CMAKE_CURRENT_LIST_DIR}/exiv2Export.cmake")
check_required_components(exiv2)
# compatibility with non-aliased users
add_library(exiv2lib ALIAS Exiv2::exiv2lib)

@ -1,14 +1,14 @@
IF(NOT EXISTS "${CMAKE_BINARY_DIR}/install_manifest.txt")
MESSAGE(FATAL_ERROR "Cannot find install manifest: ${CMAKE_BINARY_DIR}/install_manifest.txt")
ENDIF(NOT EXISTS "${CMAKE_BINARY_DIR}/install_manifest.txt")
IF(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_BINARY_DIR@/install_manifest.txt\"")
ENDIF(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
FILE(READ "${CMAKE_BINARY_DIR}/install_manifest.txt" files)
FILE(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files)
STRING(REGEX REPLACE "\n" ";" files "${files}")
FOREACH(file ${files})
MESSAGE(STATUS "Uninstalling: ${file}")
IF(IS_SYMLINK "${file}" OR EXISTS "${file}")
MESSAGE(STATUS "Uninstalling \"${file}\"")
IF(EXISTS "${file}")
EXEC_PROGRAM(
"${CMAKE_COMMAND}" ARGS "-E remove \"${file}\""
"@CMAKE_COMMAND@" ARGS "-E remove \"${file}\""
OUTPUT_VARIABLE rm_out
RETURN_VALUE rm_retval
)
@ -16,7 +16,7 @@ FOREACH(file ${files})
ELSE("${rm_retval}" STREQUAL 0)
MESSAGE(FATAL_ERROR "Problem when removing \"${file}\"")
ENDIF("${rm_retval}" STREQUAL 0)
ELSE(IS_SYMLINK "${file}" OR EXISTS "${file}")
ELSE(EXISTS "${file}")
MESSAGE(STATUS "File \"${file}\" does not exist.")
ENDIF(IS_SYMLINK "${file}" OR EXISTS "${file}")
ENDIF(EXISTS "${file}")
ENDFOREACH(file)

@ -1,63 +1,41 @@
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/develop/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()
# set include path for FindXXX.cmake files
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
# don't use Frameworks on the Mac (#966)
if (APPLE)
# On Apple, we use the conan cmake_paths generator
if (EXISTS ${CMAKE_BINARY_DIR}/conan_paths.cmake)
include(${CMAKE_BINARY_DIR}/conan_paths.cmake)
endif()
else()
# Otherwise, we rely on the conan cmake_find_package generator
list(APPEND CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR})
list(APPEND CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR})
set(CMAKE_FIND_FRAMEWORK NEVER)
endif()
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/")
if(BUILD_TESTING)
find_package(Python3 COMPONENTS Interpreter)
if(NOT Python3_Interpreter_FOUND)
message(WARNING "Python3 was not found. Python tests under the 'tests' folder will not be executed.")
endif()
# Check if the conan file exist to find the dependencies
if (EXISTS ${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
set(USING_CONAN ON)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup(NO_OUTPUT_DIRS KEEP_RPATHS TARGETS)
endif()
if(EXIV2_ENABLE_FILESYSTEM_ACCESS)
find_package(Filesystem COMPONENTS Experimental Final REQUIRED)
endif()
# don't use Frameworks on the Mac (#966)
if (APPLE)
set(CMAKE_FIND_FRAMEWORK NEVER)
endif()
# find_package(Threads REQUIRED)
if( EXIV2_ENABLE_PNG )
find_package( ZLIB REQUIRED )
endif( )
if( EXIV2_ENABLE_BMFF AND EXIV2_ENABLE_BROTLI )
find_package( Brotli REQUIRED )
endif( )
if( EXIV2_ENABLE_WEBREADY )
if( EXIV2_ENABLE_CURL )
find_package(CURL REQUIRED)
endif()
if( EXIV2_ENABLE_SSH )
find_package(libssh CONFIG REQUIRED)
# Define an imported target to have compatibility with <=libssh-0.9.0
# libssh-0.9.1 is broken regardless.
if(NOT TARGET ssh)
add_library(ssh SHARED IMPORTED)
set_target_properties(ssh PROPERTIES
IMPORTED_LOCATION "${LIBSSH_LIBRARIES}"
INTERFACE_INCLUDE_DIRECTORIES "${LIBSSH_INCLUDE_DIR}"
)
endif()
endif()
endif()
if (EXIV2_ENABLE_XMP AND EXIV2_ENABLE_EXTERNAL_XMP)
@ -76,16 +54,8 @@ endif( )
find_package(Iconv)
if( ICONV_FOUND )
message ( "-- Iconv_INCLUDE_DIRS : " ${Iconv_INCLUDE_DIRS} )
message ( "-- Iconv_LIBRARIES : " ${Iconv_LIBRARIES} )
endif()
if( EXIV2_ENABLE_INIH )
find_package(inih)
message ( "-- inih_INCLUDE_DIRS : " ${inih_INCLUDE_DIRS} )
message ( "-- inih_LIBRARIES : " ${inih_LIBRARIES} )
message ( "-- inih_inireader_INCLUDE_DIRS : " ${inih_inireader_INCLUDE_DIRS} )
message ( "-- inih_inireader_LIBRARIES : " ${inih_inireader_LIBRARIES} )
message ( "-- ICONV_INCLUDE_DIR : " ${Iconv_INCLUDE_DIR} )
message ( "-- ICONV_LIBRARIES : " ${Iconv_LIBRARY} )
endif()
if( BUILD_WITH_CCACHE )
@ -96,3 +66,4 @@ if( BUILD_WITH_CCACHE )
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
endif()
endif()

@ -1,24 +0,0 @@
# Intended usage
# cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_WITH_COVERAGE=yes ../
# cmake --build . --config Debug
# ctest
# cmake --build . --config Debug --target coverage
if(BUILD_WITH_COVERAGE)
find_program (GCOVR gcovr)
if(GCOVR)
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/coverage_output )
add_custom_command(OUTPUT _run_gcovr_parser
POST_BUILD
COMMAND ${GCOVR} --root ${PROJECT_SOURCE_DIR} --object-dir=${CMAKE_BINARY_DIR} --html --html-details -o coverage_output/coverage.html
--exclude-directories xmpsdk --exclude-directories unitTests --exclude-directories samples
--exclude '.*xmpsdk.*' --exclude '.*unitTests.*' --exclude '.*samples.*'
--exclude-unreachable-branches --exclude-throw-branches
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
add_custom_target (coverage DEPENDS _run_gcovr_parser)
endif()
endif(BUILD_WITH_COVERAGE)

@ -4,13 +4,13 @@ include(CheckCXXSymbolExists)
# Note that the scope of the EXV_ variables in local
if (${EXIV2_ENABLE_WEBREADY})
set(EXV_USE_SSH ${EXIV2_ENABLE_SSH})
set(EXV_USE_CURL ${EXIV2_ENABLE_CURL})
endif()
set(EXV_ENABLE_BMFF ${EXIV2_ENABLE_BMFF})
set(EXV_ENABLE_WEBREADY ${EXIV2_ENABLE_WEBREADY})
set(EXV_HAVE_LENSDATA ${EXIV2_ENABLE_LENSDATA})
set(EXV_ENABLE_INIH ${EXIV2_ENABLE_INIH})
set(EXV_ENABLE_FILESYSTEM ${EXIV2_ENABLE_FILESYSTEM_ACCESS})
set(EXV_ENABLE_VIDEO ${EXIV2_ENABLE_VIDEO})
set(EXV_ENABLE_WEBREADY ${EXIV2_ENABLE_WEBREADY})
set(EXV_HAVE_LENSDATA ${EXIV2_ENABLE_LENSDATA})
set(EXV_HAVE_PRINTUCS2 ${EXIV2_ENABLE_PRINTUCS2})
set(EXV_PACKAGE_NAME ${PROJECT_NAME})
set(EXV_PACKAGE_VERSION ${PROJECT_VERSION})
@ -22,8 +22,11 @@ else()
endif()
set(EXV_HAVE_ICONV ${ICONV_FOUND})
set(EXV_HAVE_LIBZ ${ZLIB_FOUND})
set(EXV_HAVE_BROTLI ${BROTLI_FOUND})
set(EXV_UNICODE_PATH ${EXIV2_ENABLE_WIN_UNICODE})
check_cxx_symbol_exists(gmtime_r time.h EXV_HAVE_GMTIME_R)
check_cxx_symbol_exists(mmap sys/mman.h EXV_HAVE_MMAP )
check_cxx_symbol_exists(munmap sys/mman.h EXV_HAVE_MUNMAP )
check_cxx_symbol_exists(strerror_r string.h EXV_HAVE_STRERROR_R )
check_cxx_source_compiles( "
@ -31,11 +34,23 @@ check_cxx_source_compiles( "
int main() {
char buff[100];
const char* c = strerror_r(0,buff,100);
(void)c; // ignore unuse-variable
return 0;
}" EXV_STRERROR_R_CHAR_P )
check_include_file_cxx( "memory.h" EXV_HAVE_MEMORY_H )
check_include_file_cxx( "process.h" EXV_HAVE_PROCESS_H )
check_include_file_cxx( "stdbool.h" EXV_HAVE_STDBOOL_H )
check_include_file_cxx( "stdint.h" EXV_HAVE_STDINT_H )
check_include_file_cxx( "strings.h" EXV_HAVE_STRINGS_H )
check_include_file_cxx( "sys/stat.h" EXV_HAVE_SYS_STAT_H )
check_include_file_cxx( "sys/types.h" EXV_HAVE_SYS_TYPES_H )
check_include_file_cxx( "inttypes.h" EXV_HAVE_INTTYPES_H )
check_include_file_cxx( "unistd.h" EXV_HAVE_UNISTD_H )
check_include_file_cxx( "sys/mman.h" EXV_HAVE_SYS_MMAN_H )
if ( NOT MINGW AND NOT MSYS AND NOT MSVC )
check_include_file_cxx( "regex.h" EXV_HAVE_REGEX_H )
endif()
set(EXV_ENABLE_NLS ${EXIV2_ENABLE_NLS})
set(EXV_ENABLE_VIDEO ${EXIV2_ENABLE_VIDEO})
configure_file(cmake/config.h.cmake ${CMAKE_BINARY_DIR}/exv_conf.h @ONLY)

@ -5,10 +5,6 @@ include(GNUInstallDirs)
include(CheckFunctionExists)
include(GenerateExportHeader)
include(CMakeDependentOption)
include(cmake/JoinPaths.cmake)
include(CTest)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
@ -27,7 +23,7 @@ if (UNIX)
set(CMAKE_MACOSX_RPATH ON)
set(CMAKE_INSTALL_RPATH "@loader_path")
else()
join_paths(CMAKE_INSTALL_RPATH "$ORIGIN" ".." "${CMAKE_INSTALL_LIBDIR}")
set(CMAKE_INSTALL_RPATH "$ORIGIN/../${CMAKE_INSTALL_LIBDIR}")
endif()
endif()

@ -1,12 +0,0 @@
[build_requires]
[settings]
arch=x86
build_type=Debug
compiler=Visual Studio
compiler.runtime=MDd
compiler.version=16
os=Windows
arch_build=x86
os_build=Windows
[options]
[env]

@ -1,12 +0,0 @@
[build_requires]
[settings]
arch=x86_64
build_type=Debug
compiler=Visual Studio
compiler.runtime=MDd
compiler.version=16
os=Windows
arch_build=x86_64
os_build=Windows
[options]
[env]

@ -1,12 +0,0 @@
[build_requires]
[settings]
arch=x86
build_type=Release
compiler=Visual Studio
compiler.runtime=MD
compiler.version=16
os=Windows
arch_build=x86
os_build=Windows
[options]
[env]

@ -1,12 +0,0 @@
[build_requires]
[settings]
arch=x86_64
build_type=Release
compiler=Visual Studio
compiler.runtime=MD
compiler.version=16
os=Windows
arch_build=x86_64
os_build=Windows
[options]
[env]

@ -1,5 +1,5 @@
set(CPACK_PACKAGE_NAME "${PROJECT_NAME}")
set(CPACK_PACKAGE_CONTACT "Luis Díaz Más <piponazo@gmail.com>")
set(CPACK_PACKAGE_CONTACT "Luis Díaz Más <piponazo@gmail.com>")
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
set(CPACK_SOURCE_GENERATOR TGZ)
@ -59,6 +59,11 @@ if ( NOT APPLE AND NOT CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" )
endif()
endif()
set (VI "") # Video
if ( EXIV2_ENABLE_VIDEO )
set (VI Video)
endif()
set (WR "") # WebReady
if ( EXIV2_ENABLE_WEBREADY )
set (WR Webready)
@ -113,7 +118,7 @@ endif()
# Set RV = Release Version
set(RV "Exiv2 v${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${VS}${BUNDLE_NAME}${BS}${CC}${LT}${BT}${WR})
set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${VS}${BUNDLE_NAME}${BS}${CC}${LT}${BT}${VI}${WR})
# https://stackoverflow.com/questions/17495906/copying-files-and-including-them-in-a-cpack-archive
install(FILES "${PROJECT_SOURCE_DIR}/samples/exifprint.cpp" DESTINATION "samples")
@ -131,7 +136,7 @@ foreach(doc ${DOCS})
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${doc} DESTINATION .)
endforeach()
# copy build/log which is present if built by build.sh
# copy build/log which which is present if built by build.sh
if(EXISTS ${PROJECT_SOURCE_DIR}/build/logs/build.txt)
install(FILES ${PROJECT_SOURCE_DIR}/build/logs/build.txt DESTINATION "logs")
endif()

@ -38,36 +38,42 @@ message( STATUS "RelWithDebInfo: ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}" )
message( STATUS "MinSizeRel: ${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL}" )
message( STATUS "" )
message( STATUS "Compiler Options")
OptionOutput( "Warnings as errors: " EXIV2_TEAM_WARNINGS_AS_ERRORS )
OptionOutput( "Use extra compiler warning flags: " EXIV2_TEAM_EXTRA_WARNINGS )
OptionOutput( "Warnings as errors: " EXIV2_WARNINGS_AS_ERRORS )
OptionOutput( "Use extra compiler warning flags: " EXIV2_EXTRA_WARNINGS )
message( STATUS "" )
message( STATUS "------------------------------------------------------------------" )
OptionOutput( "Building shared library: " BUILD_SHARED_LIBS )
OptionOutput( "Building PNG support: " EXIV2_ENABLE_PNG AND ZLIB_FOUND )
message( STATUS "------------------------------------------------------------------" )
OptionOutput( "Building shared library: " BUILD_SHARED_LIBS )
OptionOutput( "Building PNG support: " EXIV2_ENABLE_PNG AND ZLIB_FOUND )
if ( EXIV2_ENABLE_EXTERNAL_XMP )
OptionOutput( "XMP metadata support (EXTERNAL): " EXIV2_ENABLE_EXTERNAL_XMP )
OptionOutput( "XMP metadata support (EXTERNAL): " EXIV2_ENABLE_EXTERNAL_XMP )
else()
OptionOutput( "XMP metadata support: " EXIV2_ENABLE_XMP )
OptionOutput( "XMP metadata support: " EXIV2_ENABLE_XMP )
endif()
OptionOutput( "Building BMFF support: " EXIV2_ENABLE_BMFF )
OptionOutput( "Brotli support for JPEG XL: " EXIV2_ENABLE_BMFF AND BROTLI_FOUND )
OptionOutput( "Native language support: " EXIV2_ENABLE_NLS )
OptionOutput( "Building video support: " EXIV2_ENABLE_VIDEO )
OptionOutput( "Nikon lens database: " EXIV2_ENABLE_LENSDATA )
OptionOutput( "Building webready support: " EXIV2_ENABLE_WEBREADY )
OptionOutput( "Native language support: " EXIV2_ENABLE_NLS )
OptionOutput( "Conversion of Windows XP tags: " EXIV2_ENABLE_PRINTUCS2 )
OptionOutput( "Nikon lens database: " EXIV2_ENABLE_LENSDATA )
OptionOutput( "Building video support: " EXIV2_ENABLE_VIDEO )
OptionOutput( "Building webready support: " EXIV2_ENABLE_WEBREADY )
if ( EXIV2_ENABLE_WEBREADY )
OptionOutput( "USE Libcurl for HttpIo: " EXIV2_ENABLE_CURL )
OptionOutput( "USE Libcurl for HttpIo: " EXIV2_ENABLE_CURL )
OptionOutput( "USE Libssh for SshIo: " EXIV2_ENABLE_SSH )
endif ( EXIV2_ENABLE_WEBREADY )
if (WIN32)
OptionOutput( "Dynamic runtime override: " EXIV2_ENABLE_DYNAMIC_RUNTIME )
OptionOutput( "Dynamic runtime override: " EXIV2_ENABLE_DYNAMIC_RUNTIME)
OptionOutput( "Unicode paths (wstring): " EXIV2_ENABLE_WIN_UNICODE )
endif()
OptionOutput( "Building exiv2 command: " EXIV2_BUILD_EXIV2_COMMAND )
OptionOutput( "Building samples: " EXIV2_BUILD_SAMPLES AND EXIV2_BUILD_EXIV2_COMMAND )
OptionOutput( "Building unit tests: " EXIV2_BUILD_UNIT_TESTS AND BUILD_TESTING )
OptionOutput( "Building fuzz tests: " EXIV2_BUILD_FUZZ_TESTS )
OptionOutput( "Building doc: " EXIV2_BUILD_DOC )
OptionOutput( "Building with coverage flags: " BUILD_WITH_COVERAGE )
OptionOutput( "Building with filesystem access " EXIV2_ENABLE_FILESYSTEM_ACCESS )
OptionOutput( "Using ccache: " BUILD_WITH_CCACHE )
OptionOutput( "Building exiv2 command: " EXIV2_BUILD_EXIV2_COMMAND )
OptionOutput( "Building samples: " EXIV2_BUILD_SAMPLES )
OptionOutput( "Building PO files: " EXIV2_BUILD_PO )
OptionOutput( "Building unit tests: " EXIV2_BUILD_UNIT_TESTS )
OptionOutput( "Building doc: " EXIV2_BUILD_DOC )
OptionOutput( "Building with coverage flags: " BUILD_WITH_COVERAGE )
OptionOutput( "Using ccache: " BUILD_WITH_CCACHE )
message( STATUS "------------------------------------------------------------------" )
message(STATUS " WARNING: Deprecated features: EPS, Video, Ssh")
message( STATUS "------------------------------------------------------------------" )

@ -1,25 +0,0 @@
# Sample toolchain file for building for Windows from an Ubuntu 20.04 Linux system.
#
# Typical usage:
# *) install cross compiler: `sudo apt-get install mingw-w64`
# *) install zlib for mingw: sudo apt install libz-mingw-w64-dev
# *) mkdir buildMinGWRelease && cd buildMinGWRelease
# *) cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchain/Ubuntu20_04_mingw-w64-x86_64.cmake
# -DEXIV2_ENABLE_XMP=OFF -DEXIV2_TEAM_EXTRA_WARNINGS=ON
set(CMAKE_SYSTEM_NAME Windows)
set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)
# cross compilers to use for C, C++ and Fortran
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)
set(CMAKE_Fortran_COMPILER ${TOOLCHAIN_PREFIX}-gfortran)
set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
# target environment on the build host system
set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
# modify default behavior of FIND_XXX() commands
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

@ -1,25 +1,2 @@
coverage:
precision: 2
round: down
range: "60..100"
# we don't care about the coverage of files in these folders
ignore:
- "xmpsdk"
- "unitTests"
- "samples"
status:
project:
default:
threshold: 1 # decrease by up to 1% doesn't result in failure
branches:
- main
# check only the diff of the PR
patch:
default:
threshold: 1
branches:
- main
only_pulls: true
ignore:
- "xmpsdk" # Not interested about the coverage of XMKSDK

@ -4,7 +4,7 @@ from conans.model.version import Version
class Exiv2Conan(ConanFile):
settings = 'os', 'compiler', 'build_type', 'arch'
generators = 'cmake_find_package', 'cmake_paths'
generators = 'cmake'
options = {'unitTests': [True, False],
'xmp': [True, False],
'iconv': [True, False],
@ -17,30 +17,39 @@ class Exiv2Conan(ConanFile):
)
def configure(self):
self.options['libcurl'].shared = True
self.options['gtest'].shared = False
self.options['libcurl'].shared = False
self.options['libcurl'].with_openssl = True
self.options['gtest'].shared = True
def requirements(self):
self.requires('zlib/1.2.13')
self.requires('brotli/1.0.9')
self.requires('inih/55')
if self.options.webready:
self.requires('libcurl/7.85.0')
self.requires('zlib/1.2.11@conan/stable')
if os_info.is_windows and self.options.iconv:
self.requires('libiconv/1.17')
self.requires('libiconv/1.15@bincrafters/stable')
if self.options.unitTests:
self.requires('gtest/1.12.1')
if self.settings.compiler == "Visual Studio" and Version(self.settings.compiler.version.value) <= "12":
self.requires('gtest/1.8.0@bincrafters/stable')
else:
self.requires('gtest/1.8.1@bincrafters/stable')
if self.options.webready and not os_info.is_macos:
# Note: This difference in versions is just due to a combination of corner cases in the
# recipes and the OS & compiler versions used in Travis and AppVeyor. In normal cases we
# could use any of the versions.Also note that the issue was not with libcurl but with
# libopenssl (a transitive dependency)
if os_info.is_windows:
self.requires('libcurl/7.69.1')
self.options['libcurl'].with_openssl = False
self.options['libcurl'].with_winssl = True
else:
self.requires('libcurl/7.64.1@bincrafters/stable')
if self.options.xmp:
self.requires('XmpSdk/2016.7@piponazo/stable') # from conan-piponazo
else:
self.requires('expat/2.4.9')
self.requires('Expat/2.2.6@pix4d/stable')
def imports(self):
self.copy('*.dll', dst='bin', src='bin')
self.copy('*.dll', dst='conanDlls', src='bin')
self.copy('*.dylib', dst='bin', src='lib')

@ -1,33 +1,12 @@
// ***************************************************************** -*- C++ -*-
/*
* Copyright (C) 2004-2021 Exiv2 authors
* This program is part of the Exiv2 distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
*/
#include <QCoreApplication>
#include <exiv2/exiv2.hpp>
#include <iostream>
#include <vector>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
std::vector<std::regex> keys;
exv_grep_keys_t keys;
Exiv2::dumpLibraryInfo(std::cout,keys);
return 0;

@ -7,7 +7,7 @@
#
# Before to run this script you must set these shell variable :
# $EXIVCoverityToken with token of Exiv2 project given by Coverity SCAN
# $EXIVCoverityEmail with email address to send SCAN result.
# $EXIVCoverityEmail with email adress to send SCAN result.
#
# Coverity Scan bin dir must be appended to PATH variable.
#

@ -0,0 +1,235 @@
/*
* This code implements the MD5 message-digest algorithm.
* The algorithm is due to Ron Rivest. This code was
* written by Colin Plumb in 1993, no copyright is claimed.
* This code is in the public domain; do with it what you wish.
*
* Equivalent code is available from RSA Data Security, Inc.
* This code has been tested against that, and is equivalent,
* except that you don't need to include two pages of legalese
* with every copy.
*
* To compute the message digest of a chunk of bytes, declare an
* MD5_CTX structure, pass it to MD5Init, call MD5Update as
* needed on buffers full of bytes, and then call MD5Final, which
* will fill a supplied 16-byte array with the digest.
*
* Changed so as no longer to depend on Colin Plumb's `usual.h' header
* definitions; now uses stuff from dpkg's config.h.
* - Ian Jackson <ian@chiark.greenend.org.uk>.
* Still in the public domain.
*/
#include <cstring>
#include "MD5.h"
using namespace std;
static void
byteSwap(UWORD32 *buf, unsigned words)
{
const uint32_t byteOrderTest = 0x1;
if (((char *)&byteOrderTest)[0] == 0) {
md5byte *p = (md5byte *)buf;
do {
*buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 |
((unsigned)p[1] << 8 | p[0]);
p += 4;
} while (--words);
}
}
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants.
*/
void
MD5Init(struct MD5_CTX *ctx)
{
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
ctx->buf[2] = 0x98badcfe;
ctx->buf[3] = 0x10325476;
ctx->bytes[0] = 0;
ctx->bytes[1] = 0;
}
/*
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
void
MD5Update(struct MD5_CTX *ctx, md5byte const *buf, unsigned len)
{
UWORD32 t;
/* Update byte count */
t = ctx->bytes[0];
if ((ctx->bytes[0] = t + len) < t)
ctx->bytes[1]++; /* Carry from low to high */
t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */
if (t > len) {
memcpy((md5byte *)ctx->in + 64 - t, buf, len);
return;
}
/* First chunk is an odd size */
memcpy((md5byte *)ctx->in + 64 - t, buf, t);
byteSwap(ctx->in, 16);
MD5Transform(ctx->buf, ctx->in);
buf += t;
len -= t;
/* Process data in 64-byte chunks */
while (len >= 64) {
memcpy(ctx->in, buf, 64);
byteSwap(ctx->in, 16);
MD5Transform(ctx->buf, ctx->in);
buf += 64;
len -= 64;
}
/* Handle any remaining bytes of data. */
memcpy(ctx->in, buf, len);
}
/*
* Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
*/
void
MD5Final(md5byte digest[16], struct MD5_CTX *ctx)
{
int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */
md5byte *p = (md5byte *)ctx->in + count;
/* Set the first char of padding to 0x80. There is always room. */
*p++ = 0x80;
/* Bytes of padding needed to make 56 bytes (-8..55) */
count = 56 - 1 - count;
if (count < 0) { /* Padding forces an extra block */
memset(p, 0, count + 8);
byteSwap(ctx->in, 16);
MD5Transform(ctx->buf, ctx->in);
p = (md5byte *)ctx->in;
count = 56;
}
memset(p, 0, count);
byteSwap(ctx->in, 14);
/* Append length in bits and transform */
ctx->in[14] = ctx->bytes[0] << 3;
ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
MD5Transform(ctx->buf, ctx->in);
byteSwap(ctx->buf, 4);
memcpy(digest, ctx->buf, 16);
memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
}
/* The four core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f,w,x,y,z,in,s) \
(w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
/*
* The core of the MD5 algorithm, this alters an existing MD5 hash to
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
void
MD5Transform(UWORD32 buf[4], UWORD32 const in[16])
{
register UWORD32 a, b, c, d;
a = buf[0];
b = buf[1];
c = buf[2];
d = buf[3];
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}

@ -0,0 +1,50 @@
#ifndef __MD5_h__
#define __MD5_h__
/*
* This is the header file for the MD5 message-digest algorithm.
* The algorithm is due to Ron Rivest. This code was
* written by Colin Plumb in 1993, no copyright is claimed.
* This code is in the public domain; do with it what you wish.
*
* Equivalent code is available from RSA Data Security, Inc.
* This code has been tested against that, and is equivalent,
* except that you don't need to include two pages of legalese
* with every copy.
*
* To compute the message digest of a chunk of bytes, declare an
* MD5_CTX structure, pass it to MD5Init, call MD5Update as
* needed on buffers full of bytes, and then call MD5Final, which
* will fill a supplied 16-byte array with the digest.
*
* Changed so as no longer to depend on Colin Plumb's `usual.h'
* header definitions; now uses stuff from dpkg's config.h
* - Ian Jackson <ian@chiark.greenend.org.uk>.
* Still in the public domain.
*/
#include <sys/types.h>
#ifdef EXV_HAVE_STDINT_H
# include <stdint.h>
#endif
/* MSVC doesn't provide C99 types, but it has MS specific variants */
#ifdef _MSC_VER
typedef unsigned __int32 uint32_t;
#endif
typedef unsigned char md5byte;
typedef uint32_t UWORD32;
struct MD5_CTX {
UWORD32 buf[4];
UWORD32 bytes[2];
UWORD32 in[16];
};
extern void MD5Init(struct MD5_CTX *context);
extern void MD5Update(struct MD5_CTX *context, md5byte const *buf, unsigned len);
extern void MD5Final(unsigned char digest[16], struct MD5_CTX *context);
extern void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]);
#endif

@ -0,0 +1,144 @@
# ************************************************************* -*- Makefile -*-
#
# Copyright (C) 2004-2015 Andreas Huggel <ahuggel@gmx.net>
#
# This Makefile is part of the Exiv2 distribution.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# 3. The name of the author may not be used to endorse or promote
# products derived from this software without specific prior
# written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# File: Makefile
# Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
# History: 31-Jan-09, ahu: created
#
# Description:
# Simple Makefile to build the organize application. Requires installed
# exiv2 library and headers. Adapted from samples/Makefile.
#
# Restrictions:
# Requires GNU make.
#
# ******************************************************************************
# Default make target
all: ozbin
# Include system configuration
top_srcdir = ../..
include $(top_srcdir)/config/config.mk
include boost.mk
# ******************************************************************************
# Source files
# Source files for the organize application
OZMAIN = organize.cpp
OZSRC = helpers.cpp MD5.cpp
# ******************************************************************************
# Initialisations
SHELL = /bin/sh
.SUFFIXES:
.SUFFIXES: .c .cpp .o .so
.PRECIOUS: %.cpp
CPPFLAGS := -I$(BOOST_INC_DIR) `pkg-config exiv2 --cflags`
ifdef HAVE_STDINT
CPPFLAGS += -DEXV_HAVE_STDINT_H=1
endif
LDFLAGS := $(BOOST_LIBS) `pkg-config exiv2 --libs`
OZOBJ = $(OZSRC:.cpp=.o) $(OZMAIN:.cpp=.o)
OZBIN = $(OZMAIN:.cpp=)
OZEXE = $(OZMAIN:.cpp=$(EXEEXT))
ifdef DEP_TRACKING
DEP = $(OZMAIN:%.cpp=$(DEPDIR)/%.d) $(OZSRC:%.cpp=$(DEPDIR)/%.d)
endif
# ******************************************************************************
# Rules
ozbin: $(OZBIN)
$(OZOBJ): %.o: %.cpp
$(COMPILE.cc) -o $@ $<
@$(MAKEDEPEND)
@$(POSTDEPEND)
%.ii: %.cpp
set -e; \
$(CXXCPP) -E $(CPPFLAGS) $< | sed '/^[ ]*$$/d' > $@
# ******************************************************************************
# Targets
.PHONY: all ozbin relink binclean install uninstall mostlyclean clean distclean maintainer-clean
ifdef DEP_TRACKING
# Include targets from dependency files
-include $(DEP)
endif
$(OZBIN): $(OZOBJ)
$(LIBTOOL) --mode=link $(LINK.cc) -o $@ $(OZOBJ)
relink: binclean organize
install:
$(INSTALL_DIRS) $(DESTDIR)$(bindir)
@$(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $(OZEXE) $(DESTDIR)$(bindir)/$(OZEXE)
uninstall:
@$(LIBTOOL) --mode=uninstall $(RM) $(DESTDIR)$(bindir)/$(OZEXE)
-rmdir $(DESTDIR)$(bindir)
# Remove binaries, e.g., to relink them
binclean:
$(RM) $(OZEXE)
mostlyclean:
$(RM) core
$(RM) $(OZMAIN:.cpp=.ii) $(OZSRC:.cpp=.ii)
$(RM) $(OZMAIN:%.cpp=.libs/%.d) $(OZSRC:%.cpp=.libs/%.d)
-rmdir .libs
$(RM) $(OZOBJ)
clean: binclean mostlyclean
# Run `make distclean' from the top source directory to also remove
# files created by configuring the program.
distclean: clean
ifdef DEP_TRACKING
$(RM) $(DEP)
-rmdir $(DEPDIR)
endif
$(RM) *~ *.bak *#
# This command is intended for maintainers to use; it deletes files
# that may need special tools to rebuild.
maintainer-clean: uninstall distclean

@ -0,0 +1,3 @@
organize uses the Boost library (http://www.boost.org).
Configuration settings for Boost are in the file boost.mk
in this directory and should be changed as required.

@ -0,0 +1,3 @@
# Boost configuration for organize - change paths and library names as needed
BOOST_INC_DIR = /usr/local/include/boost-1_37
BOOST_LIBS = /usr/local/lib/libboost_system-gcc43-mt-1_37.a /usr/local/lib/libboost_filesystem-gcc43-mt-1_37.a /usr/local/lib/libboost_regex-gcc43-mt-1_37.a /usr/local/lib/libboost_program_options-gcc43-mt-1_37.a

@ -0,0 +1,640 @@
// ***************************************************************** -*- C++ -*-
/*
* Copyright (C) 2009 Brad Schick <schickb@gmail.com>
*
* This file is part of the organize tool.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
*/
/*
File: helpers.cpp
Author(s): Brad Schick (brad) <schickb@gmail.com>
History: 19-Jan-09, brad: created
*/
// *****************************************************************************
#include <boost/algorithm/string.hpp>
#include <boost/regex.hpp>
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
#include <exiv2/image.hpp>
#include <exiv2/easyaccess.hpp>
#include <exiv2/exif.hpp>
#include <exiv2/iptc.hpp>
#include <exiv2/tags.hpp>
//#include <exiv2/xmp.hpp>
#include <cassert>
#include <sstream>
#include <ctime>
#include "helpers.hpp"
#define BOOST_FILESYSTEM_NO_DEPRECATED
namespace fs = boost::filesystem;
typedef Exiv2::ExifData::const_iterator (*EasyAccessFct)(const Exiv2::ExifData& ed);
std::string scrub(const std::string &dirty, bool strip_space = false)
{
std::string scrub = boost::trim_copy(dirty);
if(strip_space) {
boost::regex space("\\s");
scrub = boost::regex_replace(scrub, space, "");
}
boost::regex dash("[:/\\\\|<>]");
boost::regex under("[\"'\\[\\]\\{\\}#=%\\$\\?,\\+\\*]");
scrub = boost::regex_replace(scrub, dash, "-");
return boost::regex_replace(scrub, under, "_");
}
bool exif_data(const Exiv2::Image *image, const char *key, Exiv2::ExifData::const_iterator &md)
{
assert(image && key);
bool ok = false;
try {
const Exiv2::ExifData &exifData = image->exifData();
Exiv2::ExifKey exifKey(key);
md = exifData.findKey(exifKey);
if(md != exifData.end() && md->typeId() != Exiv2::undefined)
ok = true;
}
catch(const Exiv2::AnyError&) {
}
return ok;
}
bool exif_data_easy(const Exiv2::Image *image, EasyAccessFct easy, Exiv2::ExifData::const_iterator &md)
{
assert(image && easy);
bool ok = false;
try {
const Exiv2::ExifData &exifData = image->exifData();
md = easy(exifData);
if(md != exifData.end() && md->typeId() != Exiv2::undefined)
ok = true;
}
catch(const Exiv2::AnyError&) {
}
return ok;
}
bool iptc_data(const Exiv2::Image *image, const char *key, Exiv2::IptcData::const_iterator &md)
{
bool ok = false;
assert(image && key);
try {
const Exiv2::IptcData &iptcData = image->iptcData();
Exiv2::IptcKey iptcKey(key);
md = iptcData.findKey(iptcKey);
if(md != iptcData.end() && md->typeId() != Exiv2::undefined)
ok = true;
}
catch(const Exiv2::AnyError&) {
}
return ok;
}
std::string exif_date(const Exiv2::Image *image, const fs::path &)
{
Exiv2::ExifData::const_iterator md;
bool done = exif_data(image, "Exif.Photo.DateTimeDigitized", md);
if(!done)
done = exif_data(image, "Exif.Photo.DateTimeOriginal", md);
if(!done)
return "";
std::string date = scrub(md->print().substr(0,10));
// Some files have zeros for dates, just fail in that case
if(boost::lexical_cast<int>(date.substr(0,4))==0)
return "";
return date;
}
std::string exif_year(const Exiv2::Image *image, const fs::path &path)
{
std::string date = exif_date(image, path);
if(date.length())
return date.substr(0,4);
else
return date;
}
std::string exif_month(const Exiv2::Image *image, const fs::path &path)
{
std::string date = exif_date(image, path);
if(date.length())
return date.substr(5,2);
else
return date;
}
std::string exif_day(const Exiv2::Image *image, const fs::path &path)
{
std::string date = exif_date(image, path);
if(date.length())
return date.substr(8,2);
else
return date;
}
bool iptc_get_date(const Exiv2::Image *image, Exiv2::DateValue::Date &date)
{
Exiv2::IptcData::const_iterator md;
bool done = iptc_data(image, "Iptc.Application2.DigitizationDate", md);
if(!done)
done = iptc_data(image, "Iptc.Application2.DateCreated", md);
if(!done)
return false;
date = ((Exiv2::DateValue*)md->getValue().get())->getDate();
return date.year > 0;
}
std::string iptc_date(const Exiv2::Image *image, const fs::path &)
{
Exiv2::DateValue::Date date;
if(iptc_get_date(image, date))
return str(boost::format("%4d-%02d-%02d") % date.year % date.month % date.day);
else
return "";
}
std::string iptc_year(const Exiv2::Image *image, const fs::path &)
{
Exiv2::DateValue::Date date;
if(iptc_get_date(image, date))
return str(boost::format("%4d") % date.year);
else
return "";
}
std::string iptc_month(const Exiv2::Image *image, const fs::path &)
{
Exiv2::DateValue::Date date;
if(iptc_get_date(image, date))
return str(boost::format("%02d") % date.month);
else
return "";
}
std::string iptc_day(const Exiv2::Image *image, const fs::path &)
{
Exiv2::DateValue::Date date;
if(iptc_get_date(image, date))
return str(boost::format("%02d") % date.day);
else
return "";
}
bool file_get_tm(const fs::path &path, std::tm &tm)
{
std::time_t timer = fs::last_write_time(path);
if(time > 0) {
tm = *localtime(&timer);
return true;
}
else {
return false;
}
}
std::string file_date(const Exiv2::Image *, const fs::path &path)
{
std::tm tm;
if(file_get_tm(path, tm))
return str(boost::format("%4d-%02d-%02d") % (tm.tm_year + 1900) % (tm.tm_mon + 1) % tm.tm_mday);
else
return "";
}
std::string file_year(const Exiv2::Image *, const fs::path &path)
{
std::tm tm;
if(file_get_tm(path, tm))
return str(boost::format("%4d") % (tm.tm_year + 1900));
else
return "";
}
std::string file_month(const Exiv2::Image *, const fs::path &path)
{
std::tm tm;
if(file_get_tm(path, tm))
return str(boost::format("%02d") % (tm.tm_mon + 1));
else
return "";
}
std::string file_day(const Exiv2::Image *, const fs::path &path)
{
std::tm tm;
if(file_get_tm(path, tm))
return str(boost::format("%02d") % tm.tm_mday);
else
return "";
}
/*
std::string xmp_date(const Exiv2::Image *image, const fs::path &)
{
return "";
}
std::string xmp_year(const Exiv2::Image *image, const fs::path &)
{
return "";
}
std::string xmp_month(const Exiv2::Image *image, const fs::path &)
{
return "";
}
std::string xmp_day(const Exiv2::Image *image, const fs::path &)
{
return "";
}*/
std::string exif_time(const Exiv2::Image *image, const fs::path &)
{
Exiv2::ExifData::const_iterator md;
bool done = exif_data(image, "Exif.Photo.DateTimeDigitized", md);
if(!done)
done = exif_data(image, "Exif.Photo.DateTimeOriginal", md);
if(!done)
return "";
std::string datetime = md->print();
// Some files have zeros for dates, just fail in that case
if(boost::lexical_cast<int>(datetime.substr(0,4)) == 0)
return "";
return scrub(datetime.substr(11));
}
std::string exif_hour(const Exiv2::Image *image, const fs::path &path)
{
std::string time = exif_time(image, path);
if(time.length())
return time.substr(0,2);
else
return time;
}
std::string exif_minute(const Exiv2::Image *image, const fs::path &path)
{
std::string time = exif_time(image, path);
if(time.length())
return time.substr(3,2);
else
return time;
}
std::string exif_second(const Exiv2::Image *image, const fs::path &path)
{
std::string time = exif_time(image, path);
if(time.length())
return time.substr(6,2);
else
return time;
}
bool iptc_get_time(const Exiv2::Image *image, Exiv2::TimeValue::Time &time)
{
Exiv2::IptcData::const_iterator md;
bool done = iptc_data(image, "Iptc.Application2.DigitizationTime", md);
if(!done)
done = iptc_data(image, "Iptc.Application2.TimeCreated", md);
if(!done)
return false;
time = ((Exiv2::TimeValue*)md->getValue().get())->getTime();
// Zero is a valid time, so this one is hard to check.
return true;
}
std::string iptc_time(const Exiv2::Image *image, const fs::path &)
{
Exiv2::TimeValue::Time time;
if(iptc_get_time(image, time))
return str(boost::format("%02d-%02d-%02d") % time.hour % time.minute % time.second);
else
return "";
}
std::string iptc_hour(const Exiv2::Image *image, const fs::path &)
{
Exiv2::TimeValue::Time time;
if(iptc_get_time(image, time))
return str(boost::format("%02d") % time.hour);
else
return "";
}
std::string iptc_minute(const Exiv2::Image *image, const fs::path &)
{
Exiv2::TimeValue::Time time;
if(iptc_get_time(image, time))
return str(boost::format("%02d") % time.minute);
else
return "";
}
std::string iptc_second(const Exiv2::Image *image, const fs::path &)
{
Exiv2::TimeValue::Time time;
if(iptc_get_time(image, time))
return str(boost::format("%02d") % time.second);
else
return "";
}
std::string file_time(const Exiv2::Image *, const fs::path &path)
{
std::tm tm;
if(file_get_tm(path, tm))
return str(boost::format("%02d-%02d-%02d") % tm.tm_hour % tm.tm_min % tm.tm_sec);
else
return "";
}
std::string file_hour(const Exiv2::Image *, const fs::path &path)
{
std::tm tm;
if(file_get_tm(path, tm))
return str(boost::format("%02d") % tm.tm_hour);
else
return "";
}
std::string file_minute(const Exiv2::Image *, const fs::path &path)
{
std::tm tm;
if(file_get_tm(path, tm))
return str(boost::format("%02d") % tm.tm_min);
else
return "";
}
std::string file_second(const Exiv2::Image *, const fs::path &path)
{
std::tm tm;
if(file_get_tm(path, tm))
return str(boost::format("%02d") % tm.tm_sec);
else
return "";
}
/*std::string xmp_time(const Exiv2::Image *image, const fs::path &)
{
return "";
}
std::string xmp_hour(const Exiv2::Image *image, const fs::path &)
{
return "";
}
std::string xmp_minute(const Exiv2::Image *image, const fs::path &)
{
return "";
}
std::string xmp_second(const Exiv2::Image *image, const fs::path &)
{
return "";
}*/
std::string exif_dimension(const Exiv2::Image *image, const fs::path &path)
{
return exif_width(image, path) + "-" + exif_height(image, path);
}
std::string exif_width(const Exiv2::Image *image, const fs::path &)
{
Exiv2::ExifData::const_iterator md;
bool done = exif_data(image, "Exif.Photo.PixelXDimension", md);
if(!done)
return "";
return scrub(md->print());
}
std::string exif_height(const Exiv2::Image *image, const fs::path &)
{
Exiv2::ExifData::const_iterator md;
bool done = exif_data(image, "Exif.Photo.PixelYDimension", md);
if(!done)
return "";
return scrub(md->print());
}
std::string file_dimension(const Exiv2::Image *image, const fs::path &path)
{
if(image)
return file_width(image, path) + "-" + file_height(image, path);
else
return "";
}
std::string file_width(const Exiv2::Image *image, const fs::path &)
{
if(image)
return str(boost::format("%02d") % image->pixelWidth());
else
return "";
}
std::string file_height(const Exiv2::Image *image, const fs::path &)
{
if(image)
return str(boost::format("%02d") % image->pixelHeight());
else
return "";
}
/*
std::string xmp_dimension(const Exiv2::Image *image, const fs::path &)
{
return ""
}
std::string xmp_width(const Exiv2::Image *image, const fs::path &)
{
return "";
}
std::string xmp_height(const Exiv2::Image *image, const fs::path &)
{
return "";
}*/
std::string exif_model(const Exiv2::Image *image, const fs::path &)
{
Exiv2::ExifData::const_iterator md;
bool done = exif_data(image, "Exif.Image.Model", md);
if(!done)
return "";
return scrub(md->print());
}
std::string exif_make(const Exiv2::Image *image, const fs::path &)
{
Exiv2::ExifData::const_iterator md;
bool done = exif_data(image, "Exif.Image.Make", md);
if(!done)
return "";
return scrub(md->print());
}
/*std::string xmp_model(const Exiv2::Image *image, const fs::path &)
{
return "";
}*/
std::string exif_speed(const Exiv2::Image *image, const fs::path &)
{
Exiv2::ExifData::const_iterator md;
bool done = exif_data(image, "Exif.Photo.ShutterSpeedValue", md);
if(!done)
done = exif_data(image, "Exif.Photo.ExposureTime", md);
if(!done)
return "";
return scrub(md->print());
}
/*std::string xmp_speed(const Exiv2::Image *image, const fs::path &)
{
return "";
}*/
std::string exif_aperture(const Exiv2::Image *image, const fs::path &)
{
Exiv2::ExifData::const_iterator md;
bool done = exif_data(image, "Exif.Photo.ApertureValue", md);
if(!done)
done = exif_data(image, "Exif.Photo.FNumber", md);
if(!done)
return "";
return scrub(md->print());
}
/*std::string xmp_aperture(const Exiv2::Image *image, const fs::path &)
{
return "";
}*/
std::string exif_focal(const Exiv2::Image *image, const fs::path &)
{
Exiv2::ExifData::const_iterator md;
bool done = exif_data(image, "Exif.Photo.FocalLength", md);
if(!done)
return "";
return scrub(md->print());
}
/*std::string xmp_focal(const Exiv2::Image *image, const fs::path &)
{
return "";
}*/
std::string exif_distance(const Exiv2::Image *image, const fs::path &)
{
Exiv2::ExifData::const_iterator md;
bool done = exif_data(image, "Exif.Photo.SubjectDistance", md);
if(!done)
return "";
return scrub(md->print());
}
/*std::string xmp_distance(const Exiv2::Image *image, const fs::path &)
{
return "";
}*/
std::string exif_meter(const Exiv2::Image *image, const fs::path &)
{
Exiv2::ExifData::const_iterator md;
bool done = exif_data(image, "Exif.Photo.MeteringMode", md);
if(!done)
return "";
return scrub(md->print());
}
std::string exif_macro(const Exiv2::Image *image, const fs::path &)
{
Exiv2::ExifData::const_iterator md;
bool done = exif_data_easy(image, Exiv2::macroMode, md);
if(!done)
return "";
return scrub(md->print());
}
std::string exif_orientation(const Exiv2::Image *image, const fs::path &)
{
Exiv2::ExifData::const_iterator md;
bool done = exif_data_easy(image, Exiv2::orientation, md);
if(!done)
return "";
return scrub(md->print(), true);
}
std::string exif_lens(const Exiv2::Image *image, const fs::path &)
{
Exiv2::ExifData::const_iterator md;
bool done = exif_data_easy(image, Exiv2::lensName, md);
if(!done)
return "";
return scrub(md->print());
}
std::string exif_iso(const Exiv2::Image *image, const fs::path &)
{
Exiv2::ExifData::const_iterator md;
bool done = exif_data_easy(image, Exiv2::isoSpeed, md);
if(!done)
return "";
return scrub(md->print());
}
/*std::string xmp_meter(const Exiv2::Image *image, const fs::path &)
{
return "";
}*/
std::string exif_keyword(const Exiv2::Image *image, const fs::path &)
{
Exiv2::ExifData::const_iterator md;
bool done = exif_data(image, "Exif.Photo.UserComment", md);
if(!done)
return "";
return scrub(md->print());
}
std::string iptc_keyword(const Exiv2::Image *image, const fs::path &)
{
Exiv2::IptcData::const_iterator md;
bool done = iptc_data(image, "Iptc.Application2.Keywords", md);
if(!done)
return "";
return scrub(md->print());
}
/*std::string xmp_keyword(const Exiv2::Image *image, const fs::path &)
{
return "";
}*/

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

Loading…
Cancel
Save