import compat-exiv2-026-0.26-3.el8
This commit is contained in:
commit
5b24c27ba2
1
.compat-exiv2-026.metadata
Normal file
1
.compat-exiv2-026.metadata
Normal file
@ -0,0 +1 @@
|
|||||||
|
cacac90fdafcb64d8de68743d4d19a44617fd2f7 SOURCES/exiv2-0.26.tar.gz
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
SOURCES/exiv2-0.26.tar.gz
|
25
SOURCES/0006-1296-Fix-submitted.patch
Normal file
25
SOURCES/0006-1296-Fix-submitted.patch
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
From 2f8681e120d277e418941c4361c83b5028f67fd8 Mon Sep 17 00:00:00 2001
|
||||||
|
From: clanmills <robin@clanmills.com>
|
||||||
|
Date: Sat, 27 May 2017 10:18:17 +0100
|
||||||
|
Subject: [PATCH 6/6] #1296 Fix submitted.
|
||||||
|
|
||||||
|
---
|
||||||
|
src/tiffcomposite.cpp | 2 ++
|
||||||
|
1 file changed, 2 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/src/tiffcomposite.cpp b/src/tiffcomposite.cpp
|
||||||
|
index c6b860d..0c9b9c4 100644
|
||||||
|
--- a/src/tiffcomposite.cpp
|
||||||
|
+++ b/src/tiffcomposite.cpp
|
||||||
|
@@ -1611,6 +1611,8 @@ namespace Exiv2 {
|
||||||
|
uint32_t TiffImageEntry::doWriteImage(IoWrapper& ioWrapper,
|
||||||
|
ByteOrder /*byteOrder*/) const
|
||||||
|
{
|
||||||
|
+ if ( !pValue() ) throw Error(21); // #1296
|
||||||
|
+
|
||||||
|
uint32_t len = pValue()->sizeDataArea();
|
||||||
|
if (len > 0) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
--
|
||||||
|
2.9.4
|
||||||
|
|
41
SOURCES/exiv2-CVE-2017-11683.patch
Normal file
41
SOURCES/exiv2-CVE-2017-11683.patch
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
From 1f1715c086d8dcdf5165b19164af9aee7aa12e98 Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Dan=20=C4=8Cerm=C3=A1k?= <dan.cermak@cgc-instruments.com>
|
||||||
|
Date: Fri, 6 Oct 2017 00:37:43 +0200
|
||||||
|
Subject: =?UTF-8?q?Use=20nullptr=20check=20instead=20of=20assertion,=20by?=
|
||||||
|
=?UTF-8?q?=20Rapha=C3=ABl=20Hertzog?=
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
Source:
|
||||||
|
https://github.com/Exiv2/exiv2/issues/57#issuecomment-333086302
|
||||||
|
|
||||||
|
tc can be a null pointer when the TIFF tag is unknown (the factory
|
||||||
|
then returns an auto_ptr(0)) => as this can happen for corrupted
|
||||||
|
files, an explicit check should be used because an assertion can be
|
||||||
|
turned of in release mode (with NDEBUG defined)
|
||||||
|
|
||||||
|
This also fixes #57
|
||||||
|
|
||||||
|
diff --git a/src/tiffvisitor.cpp b/src/tiffvisitor.cpp
|
||||||
|
index 74f8d078..4ab733d4 100644
|
||||||
|
--- a/src/tiffvisitor.cpp
|
||||||
|
+++ b/src/tiffvisitor.cpp
|
||||||
|
@@ -1294,11 +1294,12 @@ namespace Exiv2 {
|
||||||
|
}
|
||||||
|
uint16_t tag = getUShort(p, byteOrder());
|
||||||
|
TiffComponent::AutoPtr tc = TiffCreator::create(tag, object->group());
|
||||||
|
- // The assertion typically fails if a component is not configured in
|
||||||
|
- // the TIFF structure table
|
||||||
|
- assert(tc.get());
|
||||||
|
- tc->setStart(p);
|
||||||
|
- object->addChild(tc);
|
||||||
|
+ if (tc.get()) {
|
||||||
|
+ tc->setStart(p);
|
||||||
|
+ object->addChild(tc);
|
||||||
|
+ } else {
|
||||||
|
+ EXV_WARNING << "Unable to handle tag " << tag << ".\n";
|
||||||
|
+ }
|
||||||
|
p += 12;
|
||||||
|
}
|
||||||
|
|
36
SOURCES/exiv2-CVE-2017-14860.patch
Normal file
36
SOURCES/exiv2-CVE-2017-14860.patch
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
From 6ede8aa1975177705450abb816163f0b8d33a597 Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Dan=20=C4=8Cerm=C3=A1k?= <dan.cermak@cgc-instruments.com>
|
||||||
|
Date: Fri, 6 Oct 2017 23:09:08 +0200
|
||||||
|
Subject: Fix for CVE-2017-14860
|
||||||
|
|
||||||
|
A heap buffer overflow could occur in memcpy when icc.size_ is larger
|
||||||
|
than data.size_ - pad, as then memcpy would read out of bounds of data.
|
||||||
|
|
||||||
|
This commit adds a sanity check to iccLength (= icc.size_): if it is
|
||||||
|
larger than data.size_ - pad (i.e. an overflow would be caused) an
|
||||||
|
exception is thrown.
|
||||||
|
|
||||||
|
This fixes #71.
|
||||||
|
|
||||||
|
diff --git a/src/jp2image.cpp b/src/jp2image.cpp
|
||||||
|
index 1892fd43..09d023e2 100644
|
||||||
|
--- a/src/jp2image.cpp
|
||||||
|
+++ b/src/jp2image.cpp
|
||||||
|
@@ -269,10 +269,15 @@ namespace Exiv2
|
||||||
|
std::cout << "Exiv2::Jp2Image::readMetadata: "
|
||||||
|
<< "Color data found" << std::endl;
|
||||||
|
#endif
|
||||||
|
- long pad = 3 ; // 3 padding bytes 2 0 0
|
||||||
|
+ const long pad = 3 ; // 3 padding bytes 2 0 0
|
||||||
|
DataBuf data(subBox.length+8);
|
||||||
|
io_->read(data.pData_,data.size_);
|
||||||
|
- long iccLength = getULong(data.pData_+pad, bigEndian);
|
||||||
|
+ const long iccLength = getULong(data.pData_+pad, bigEndian);
|
||||||
|
+ // subtracting pad from data.size_ is safe:
|
||||||
|
+ // size_ is at least 8 and pad = 3
|
||||||
|
+ if (iccLength > data.size_ - pad) {
|
||||||
|
+ throw Error(58);
|
||||||
|
+ }
|
||||||
|
DataBuf icc(iccLength);
|
||||||
|
::memcpy(icc.pData_,data.pData_+pad,icc.size_);
|
||||||
|
#ifdef DEBUG
|
@ -0,0 +1,53 @@
|
|||||||
|
From d4e4288d839d0d9546a05986771f8738c382060c Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Dan=20=C4=8Cerm=C3=A1k?= <dan.cermak@cgc-instruments.com>
|
||||||
|
Date: Sat, 7 Oct 2017 23:08:36 +0200
|
||||||
|
Subject: Fix for CVE-2017-14864, CVE-2017-14862 and CVE-2017-14859
|
||||||
|
|
||||||
|
The invalid memory dereference in
|
||||||
|
Exiv2::getULong()/Exiv2::StringValueBase::read()/Exiv2::DataValue::read()
|
||||||
|
is caused further up the call-stack, by
|
||||||
|
v->read(pData, size, byteOrder) in TiffReader::readTiffEntry()
|
||||||
|
passing an invalid pData pointer (pData points outside of the Tiff
|
||||||
|
file). pData can be set out of bounds in the (size > 4) branch where
|
||||||
|
baseOffset() and offset are added to pData_ without checking whether
|
||||||
|
the result is still in the file. As offset comes from an untrusted
|
||||||
|
source, an attacker can craft an arbitrarily large offset into the
|
||||||
|
file.
|
||||||
|
|
||||||
|
This commit adds a check into the problematic branch, whether the
|
||||||
|
result of the addition would be out of bounds of the Tiff
|
||||||
|
file. Furthermore the whole operation is checked for possible
|
||||||
|
overflows.
|
||||||
|
|
||||||
|
diff --git a/src/tiffvisitor.cpp b/src/tiffvisitor.cpp
|
||||||
|
index 4ab733d4..ef13542e 100644
|
||||||
|
--- a/src/tiffvisitor.cpp
|
||||||
|
+++ b/src/tiffvisitor.cpp
|
||||||
|
@@ -47,6 +47,7 @@ EXIV2_RCSID("@(#) $Id$")
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <cassert>
|
||||||
|
+#include <limits>
|
||||||
|
|
||||||
|
// *****************************************************************************
|
||||||
|
namespace {
|
||||||
|
@@ -1517,7 +1518,19 @@ namespace Exiv2 {
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
if (size > 4) {
|
||||||
|
+ // setting pData to pData_ + baseOffset() + offset can result in pData pointing to invalid memory,
|
||||||
|
+ // as offset can be arbitrarily large
|
||||||
|
+ if ((static_cast<uintptr_t>(baseOffset()) > std::numeric_limits<uintptr_t>::max() - static_cast<uintptr_t>(offset))
|
||||||
|
+ || (static_cast<uintptr_t>(baseOffset() + offset) > std::numeric_limits<uintptr_t>::max() - reinterpret_cast<uintptr_t>(pData_)))
|
||||||
|
+ {
|
||||||
|
+ throw Error(59);
|
||||||
|
+ }
|
||||||
|
+ if (pData_ + static_cast<uintptr_t>(baseOffset()) + static_cast<uintptr_t>(offset) > pLast_) {
|
||||||
|
+ throw Error(58);
|
||||||
|
+ }
|
||||||
|
pData = const_cast<byte*>(pData_) + baseOffset() + offset;
|
||||||
|
+
|
||||||
|
+ // check for size being invalid
|
||||||
|
if (size > static_cast<uint32_t>(pLast_ - pData)) {
|
||||||
|
#ifndef SUPPRESS_WARNINGS
|
||||||
|
EXV_ERROR << "Upper boundary of data for "
|
37
SOURCES/exiv2-CVE-2017-17669.patch
Normal file
37
SOURCES/exiv2-CVE-2017-17669.patch
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
From 06aa7ab69d0c4f3d14644bd84fc9d1346154430d Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Dan=20=C4=8Cerm=C3=A1k?= <dan.cermak@cgc-instruments.com>
|
||||||
|
Date: Mon, 22 Jan 2018 23:56:08 +0100
|
||||||
|
Subject: Fix out of bounds read in src/pngchunk_int.cpp by @brianmay
|
||||||
|
|
||||||
|
- consider that key is advanced by 8 bytes if stripHeader is true
|
||||||
|
=> length is reduced by same amount
|
||||||
|
Fixed by adding offset to the check in the loop
|
||||||
|
- Rewrote loop so that keysize is checked before the next
|
||||||
|
iteration (preventing an out of bounds read)
|
||||||
|
|
||||||
|
diff --git a/src/pngchunk.cpp b/src/pngchunk.cpp
|
||||||
|
index da4ccd01..b54bcdac 100644
|
||||||
|
--- a/src/pngchunk.cpp
|
||||||
|
+++ b/src/pngchunk.cpp
|
||||||
|
@@ -107,15 +107,17 @@ namespace Exiv2 {
|
||||||
|
{
|
||||||
|
// From a tEXt, zTXt, or iTXt chunk,
|
||||||
|
// we get the key, it's a null terminated string at the chunk start
|
||||||
|
- if (data.size_ <= (stripHeader ? 8 : 0)) throw Error(14);
|
||||||
|
- const byte *key = data.pData_ + (stripHeader ? 8 : 0);
|
||||||
|
+ const int offset = stripHeader ? 8 : 0;
|
||||||
|
+ if (data.size_ <= offset) throw Error(14);
|
||||||
|
+ const byte *key = data.pData_ + offset;
|
||||||
|
|
||||||
|
// Find null string at end of key.
|
||||||
|
int keysize=0;
|
||||||
|
- for ( ; key[keysize] != 0 ; keysize++)
|
||||||
|
+ while (key[keysize] != 0)
|
||||||
|
{
|
||||||
|
+ keysize++;
|
||||||
|
// look if keysize is valid.
|
||||||
|
- if (keysize >= data.size_)
|
||||||
|
+ if (keysize+offset >= data.size_)
|
||||||
|
throw Error(14);
|
||||||
|
}
|
||||||
|
|
60
SOURCES/exiv2-CVE-2017-17723-1.patch
Normal file
60
SOURCES/exiv2-CVE-2017-17723-1.patch
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
From c037d7377bc7bd63acc3f240101ff44002d19027 Mon Sep 17 00:00:00 2001
|
||||||
|
From: clanmills <robin@clanmills.com>
|
||||||
|
Date: Tue, 26 Sep 2017 21:37:53 +0100
|
||||||
|
Subject: =?UTF-8?q?Fix=20https://github.com/Exiv2/exiv2/issues/55=20=20Tha?=
|
||||||
|
=?UTF-8?q?nk=20You,=20Rapha=C3=ABl=20Hertzog.?=
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/include/exiv2/value.hpp b/include/exiv2/value.hpp
|
||||||
|
index b61c0f44..2078c6bd 100644
|
||||||
|
--- a/include/exiv2/value.hpp
|
||||||
|
+++ b/include/exiv2/value.hpp
|
||||||
|
@@ -1663,7 +1663,7 @@ namespace Exiv2 {
|
||||||
|
template<>
|
||||||
|
inline long ValueType<Rational>::toLong(long n) const
|
||||||
|
{
|
||||||
|
- ok_ = (value_[n].second != 0);
|
||||||
|
+ ok_ = (value_[n].second != 0 && INT_MIN < value_[n].first && value_[n].first < INT_MAX );
|
||||||
|
if (!ok_) return 0;
|
||||||
|
return value_[n].first / value_[n].second;
|
||||||
|
}
|
||||||
|
diff --git a/test/bugfixes-test.sh b/test/bugfixes-test.sh
|
||||||
|
index f91c6759..c90ae559 100755
|
||||||
|
--- a/test/bugfixes-test.sh
|
||||||
|
+++ b/test/bugfixes-test.sh
|
||||||
|
@@ -602,6 +602,7 @@ source ./functions.source
|
||||||
|
runTest exiv2 -pX $filename | xmllint --format -
|
||||||
|
|
||||||
|
num=1231
|
||||||
|
+ printf "$num " >&3
|
||||||
|
for X in a b; do
|
||||||
|
filename=exiv2-bug$num$X.jpg
|
||||||
|
echo '------>' Bug $filename '<-------' >&2
|
||||||
|
@@ -622,6 +623,7 @@ source ./functions.source
|
||||||
|
runTest exiv2 -pa $filename
|
||||||
|
|
||||||
|
num=1252
|
||||||
|
+ printf "$num " >&3
|
||||||
|
for X in a b; do
|
||||||
|
filename=exiv2-bug$num$X.exv
|
||||||
|
echo '------>' Bug $filename '<-------' >&2
|
||||||
|
@@ -629,6 +631,13 @@ source ./functions.source
|
||||||
|
runTest exiv2 -pa --grep lens/i $filename
|
||||||
|
done
|
||||||
|
|
||||||
|
+ num=g55
|
||||||
|
+ printf "$num " >&3
|
||||||
|
+ filename=POC8
|
||||||
|
+ echo '------>' Bug $filename '<-------' >&2
|
||||||
|
+ copyTestFile $filename
|
||||||
|
+ runTest exiv2 $filename 2>/dev/null
|
||||||
|
+
|
||||||
|
) 3>&1 > $results 2>&1
|
||||||
|
|
||||||
|
printf "\n"
|
||||||
|
diff --git a/test/data/bugfixes-test.out b/test/data/bugfixes-test.out
|
||||||
|
index d8754025..53d45dc5 100644
|
||||||
|
Binary files a/test/data/bugfixes-test.out and b/test/data/bugfixes-test.out differ
|
80
SOURCES/exiv2-CVE-2017-17723-2.patch
Normal file
80
SOURCES/exiv2-CVE-2017-17723-2.patch
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
From 7f5b0778fa301b68c1c88e3820ec3afbd09dd0a5 Mon Sep 17 00:00:00 2001
|
||||||
|
From: clanmills <robin@clanmills.com>
|
||||||
|
Date: Wed, 27 Sep 2017 09:20:13 +0100
|
||||||
|
Subject: Fix https://github.com/Exiv2/exiv2/issues/55
|
||||||
|
|
||||||
|
(cherry picked from commit 6e3855aed7ba8bb4731fc4087ca7f9078b2f3d97)
|
||||||
|
|
||||||
|
diff --git a/include/exiv2/value.hpp b/include/exiv2/value.hpp
|
||||||
|
index 2078c6bd..b7d76fef 100644
|
||||||
|
--- a/include/exiv2/value.hpp
|
||||||
|
+++ b/include/exiv2/value.hpp
|
||||||
|
@@ -1659,11 +1659,13 @@ namespace Exiv2 {
|
||||||
|
ok_ = true;
|
||||||
|
return static_cast<long>(value_[n]);
|
||||||
|
}
|
||||||
|
+// #55 crash when value_[n].first == LONG_MIN
|
||||||
|
+#define LARGE_INT 1000000
|
||||||
|
// Specialization for rational
|
||||||
|
template<>
|
||||||
|
inline long ValueType<Rational>::toLong(long n) const
|
||||||
|
{
|
||||||
|
- ok_ = (value_[n].second != 0 && INT_MIN < value_[n].first && value_[n].first < INT_MAX );
|
||||||
|
+ ok_ = (value_[n].second != 0 && -LARGE_INT < value_[n].first && value_[n].first < LARGE_INT);
|
||||||
|
if (!ok_) return 0;
|
||||||
|
return value_[n].first / value_[n].second;
|
||||||
|
}
|
||||||
|
@@ -1671,7 +1673,7 @@ namespace Exiv2 {
|
||||||
|
template<>
|
||||||
|
inline long ValueType<URational>::toLong(long n) const
|
||||||
|
{
|
||||||
|
- ok_ = (value_[n].second != 0);
|
||||||
|
+ ok_ = (value_[n].second != 0 && value_[n].first < LARGE_INT);
|
||||||
|
if (!ok_) return 0;
|
||||||
|
return value_[n].first / value_[n].second;
|
||||||
|
}
|
||||||
|
diff --git a/src/basicio.cpp b/src/basicio.cpp
|
||||||
|
index 95589cd2..f2e1518b 100644
|
||||||
|
--- a/src/basicio.cpp
|
||||||
|
+++ b/src/basicio.cpp
|
||||||
|
@@ -990,6 +990,7 @@ namespace Exiv2 {
|
||||||
|
DataBuf FileIo::read(long rcount)
|
||||||
|
{
|
||||||
|
assert(p_->fp_ != 0);
|
||||||
|
+ if ( (size_t) rcount > size() ) throw Error(57);
|
||||||
|
DataBuf buf(rcount);
|
||||||
|
long readCount = read(buf.pData_, buf.size_);
|
||||||
|
buf.size_ = readCount;
|
||||||
|
diff --git a/src/error.cpp b/src/error.cpp
|
||||||
|
index 80378c19..e90a9c0a 100644
|
||||||
|
--- a/src/error.cpp
|
||||||
|
+++ b/src/error.cpp
|
||||||
|
@@ -106,6 +106,9 @@ namespace {
|
||||||
|
{ 52, N_("%1 has invalid XMP value type `%2'") }, // %1=key, %2=value type
|
||||||
|
{ 53, N_("Not a valid ICC Profile") },
|
||||||
|
{ 54, N_("Not valid XMP") },
|
||||||
|
+ { 55, N_("tiff directory length is too large") },
|
||||||
|
+ { 56, N_("invalid type value detected in Image::printIFDStructure") },
|
||||||
|
+ { 57, N_("invalid memory allocation request") },
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
diff --git a/src/image.cpp b/src/image.cpp
|
||||||
|
index 0d828045..ec5b873e 100644
|
||||||
|
--- a/src/image.cpp
|
||||||
|
+++ b/src/image.cpp
|
||||||
|
@@ -399,7 +399,13 @@ namespace Exiv2 {
|
||||||
|
;
|
||||||
|
|
||||||
|
// if ( offset > io.size() ) offset = 0; // Denial of service?
|
||||||
|
- DataBuf buf(size*count + pad+20); // allocate a buffer
|
||||||
|
+
|
||||||
|
+ // #55 memory allocation crash test/data/POC8
|
||||||
|
+ long long allocate = (long long) (size*count + pad+20);
|
||||||
|
+ if ( allocate > (long long) io.size() ) {
|
||||||
|
+ throw Error(57);
|
||||||
|
+ }
|
||||||
|
+ DataBuf buf(allocate); // allocate a buffer
|
||||||
|
std::memcpy(buf.pData_,dir.pData_+8,4); // copy dir[8:11] into buffer (short strings)
|
||||||
|
if ( count*size > 4 ) { // read into buffer
|
||||||
|
size_t restore = io.tell(); // save
|
351
SOURCES/exiv2-CVE-2017-17725.patch
Normal file
351
SOURCES/exiv2-CVE-2017-17725.patch
Normal file
@ -0,0 +1,351 @@
|
|||||||
|
From 7c6f59619616a01e242401cf4c8e06428539a035 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Luis Diaz Mas <piponazo@gmail.com>
|
||||||
|
Date: Sat, 16 Dec 2017 16:05:08 +0100
|
||||||
|
Subject: Fix arithmetic operation overflow
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/jp2image.cpp b/src/jp2image.cpp
|
||||||
|
index 09d023e2..a308bfd9 100644
|
||||||
|
--- a/src/jp2image.cpp
|
||||||
|
+++ b/src/jp2image.cpp
|
||||||
|
@@ -41,6 +41,7 @@ EXIV2_RCSID("@(#) $Id$")
|
||||||
|
#include "error.hpp"
|
||||||
|
#include "futils.hpp"
|
||||||
|
#include "types.hpp"
|
||||||
|
+#include "safe_op.hpp"
|
||||||
|
|
||||||
|
// + standard includes
|
||||||
|
#include <string>
|
||||||
|
@@ -269,15 +270,16 @@ namespace Exiv2
|
||||||
|
std::cout << "Exiv2::Jp2Image::readMetadata: "
|
||||||
|
<< "Color data found" << std::endl;
|
||||||
|
#endif
|
||||||
|
+
|
||||||
|
const long pad = 3 ; // 3 padding bytes 2 0 0
|
||||||
|
- DataBuf data(subBox.length+8);
|
||||||
|
+ DataBuf data(Safe::add(subBox.length, static_cast<uint32_t>(8)));
|
||||||
|
io_->read(data.pData_,data.size_);
|
||||||
|
const long iccLength = getULong(data.pData_+pad, bigEndian);
|
||||||
|
// subtracting pad from data.size_ is safe:
|
||||||
|
// size_ is at least 8 and pad = 3
|
||||||
|
if (iccLength > data.size_ - pad) {
|
||||||
|
throw Error(58);
|
||||||
|
- }
|
||||||
|
+ }
|
||||||
|
DataBuf icc(iccLength);
|
||||||
|
::memcpy(icc.pData_,data.pData_+pad,icc.size_);
|
||||||
|
#ifdef DEBUG
|
||||||
|
diff --git a/src/safe_op.hpp b/src/safe_op.hpp
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..55d690e3
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/safe_op.hpp
|
||||||
|
@@ -0,0 +1,308 @@
|
||||||
|
+// ********************************************************* -*- C++ -*-
|
||||||
|
+/*
|
||||||
|
+ * Copyright (C) 2004-2017 Exiv2 maintainers
|
||||||
|
+ *
|
||||||
|
+ * 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.
|
||||||
|
+ */
|
||||||
|
+/*!
|
||||||
|
+ @file safe_op.hpp
|
||||||
|
+ @brief Overflow checks for integers
|
||||||
|
+ @author Dan Čermák (D4N)
|
||||||
|
+ <a href="mailto:dan.cermak@cgc-instruments.com">dan.cermak@cgc-instruments.com</a>
|
||||||
|
+ @date 14-Dec-17, D4N: created
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#ifndef SAFE_OP_HPP_
|
||||||
|
+#define SAFE_OP_HPP_
|
||||||
|
+
|
||||||
|
+#include <limits>
|
||||||
|
+#include <stdexcept>
|
||||||
|
+
|
||||||
|
+#ifdef _MSC_VER
|
||||||
|
+#include <Intsafe.h>
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+/*!
|
||||||
|
+ * @brief Arithmetic operations with overflow checks
|
||||||
|
+ */
|
||||||
|
+namespace Safe
|
||||||
|
+{
|
||||||
|
+ /*!
|
||||||
|
+ * @brief Helper structs for providing integer overflow checks.
|
||||||
|
+ *
|
||||||
|
+ * This namespace contains the internal helper structs fallback_add_overflow
|
||||||
|
+ * and builtin_add_overflow. Both have a public static member function add
|
||||||
|
+ * with the following interface:
|
||||||
|
+ *
|
||||||
|
+ * bool add(T summand_1, T summand_2, T& result)
|
||||||
|
+ *
|
||||||
|
+ * where T is the type over which the struct is templated.
|
||||||
|
+ *
|
||||||
|
+ * The function performs a check whether the addition summand_1 + summand_2
|
||||||
|
+ * can be performed without an overflow. If the operation would overflow,
|
||||||
|
+ * true is returned and the addition is not performed if it would result in
|
||||||
|
+ * undefined behavior. If no overflow occurs, the sum is saved in result and
|
||||||
|
+ * false is returned.
|
||||||
|
+ *
|
||||||
|
+ * fallback_add_overflow implements a portable but slower overflow check.
|
||||||
|
+ * builtin_add_overflow uses compiler builtins (when available) and should
|
||||||
|
+ * be considerably faster. As builtins are not available for all types,
|
||||||
|
+ * builtin_add_overflow falls back to fallback_add_overflow when no builtin
|
||||||
|
+ * is available.
|
||||||
|
+ */
|
||||||
|
+ namespace Internal
|
||||||
|
+ {
|
||||||
|
+ /*!
|
||||||
|
+ * @brief Helper struct to determine whether a type is signed or unsigned
|
||||||
|
+
|
||||||
|
+ * This struct is a backport of std::is_signed from C++11. It has a public
|
||||||
|
+ * enum with the property VALUE which is true when the type is signed or
|
||||||
|
+ * false if it is unsigned.
|
||||||
|
+ */
|
||||||
|
+ template <typename T>
|
||||||
|
+ struct is_signed
|
||||||
|
+ {
|
||||||
|
+ enum
|
||||||
|
+ {
|
||||||
|
+ VALUE = T(-1) < T(0)
|
||||||
|
+ };
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ /*!
|
||||||
|
+ * @brief Helper struct for SFINAE, from C++11
|
||||||
|
+
|
||||||
|
+ * This struct has a public typedef called type typedef'd to T if B is
|
||||||
|
+ * true. Otherwise there is no typedef.
|
||||||
|
+ */
|
||||||
|
+ template <bool B, class T = void>
|
||||||
|
+ struct enable_if
|
||||||
|
+ {
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ /*!
|
||||||
|
+ * @brief Specialization of enable_if for the case B == true
|
||||||
|
+ */
|
||||||
|
+ template <class T>
|
||||||
|
+ struct enable_if<true, T>
|
||||||
|
+ {
|
||||||
|
+ typedef T type;
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ /*!
|
||||||
|
+ * @brief Fallback overflow checker, specialized via SFINAE
|
||||||
|
+ *
|
||||||
|
+ * This struct implements a 'fallback' addition with an overflow check,
|
||||||
|
+ * i.e. it does not rely on compiler intrinsics. It is specialized via
|
||||||
|
+ * SFINAE for signed and unsigned integer types and provides a public
|
||||||
|
+ * static member function add.
|
||||||
|
+ */
|
||||||
|
+ template <typename T, typename = void>
|
||||||
|
+ struct fallback_add_overflow;
|
||||||
|
+
|
||||||
|
+ /*!
|
||||||
|
+ * @brief Overload of fallback_add_overflow for signed integers
|
||||||
|
+ */
|
||||||
|
+ template <typename T>
|
||||||
|
+ struct fallback_add_overflow<T, typename enable_if<is_signed<T>::VALUE>::type>
|
||||||
|
+ {
|
||||||
|
+ /*!
|
||||||
|
+ * @brief Adds the two summands only if no overflow occurs
|
||||||
|
+ *
|
||||||
|
+ * This function performs a check if summand_1 + summand_2 would
|
||||||
|
+ * overflow and returns true in that case. If no overflow occurs,
|
||||||
|
+ * the sum is saved in result and false is returned.
|
||||||
|
+ *
|
||||||
|
+ * @return true on overflow, false on no overflow
|
||||||
|
+ *
|
||||||
|
+ * The check for an overflow is performed before the addition to
|
||||||
|
+ * ensure that no undefined behavior occurs. The value in result is
|
||||||
|
+ * only valid when the function returns false.
|
||||||
|
+ *
|
||||||
|
+ * Further information:
|
||||||
|
+ * https://wiki.sei.cmu.edu/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
|
||||||
|
+ */
|
||||||
|
+ static bool add(T summand_1, T summand_2, T& result)
|
||||||
|
+ {
|
||||||
|
+ if (((summand_2 >= 0) && (summand_1 > std::numeric_limits<T>::max() - summand_2)) ||
|
||||||
|
+ ((summand_2 < 0) && (summand_1 < std::numeric_limits<T>::min() - summand_2))) {
|
||||||
|
+ return true;
|
||||||
|
+ } else {
|
||||||
|
+ result = summand_1 + summand_2;
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ /*!
|
||||||
|
+ * @brief Overload of fallback_add_overflow for unsigned integers
|
||||||
|
+ */
|
||||||
|
+ template <typename T>
|
||||||
|
+ struct fallback_add_overflow<T, typename enable_if<!is_signed<T>::VALUE>::type>
|
||||||
|
+ {
|
||||||
|
+ /*!
|
||||||
|
+ * @brief Adds the two summands only if no overflow occurs
|
||||||
|
+ *
|
||||||
|
+ * This function performs a check if summand_1 + summand_2 would
|
||||||
|
+ * overflow and returns true in that case. If no overflow occurs,
|
||||||
|
+ * the sum is saved in result and false is returned.
|
||||||
|
+ *
|
||||||
|
+ * @return true on overflow, false on no overflow
|
||||||
|
+ *
|
||||||
|
+ * Further information:
|
||||||
|
+ * https://wiki.sei.cmu.edu/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap
|
||||||
|
+ */
|
||||||
|
+ static bool add(T summand_1, T summand_2, T& result)
|
||||||
|
+ {
|
||||||
|
+ if (summand_1 > std::numeric_limits<T>::max() - summand_2) {
|
||||||
|
+ return true;
|
||||||
|
+ } else {
|
||||||
|
+ result = summand_1 + summand_2;
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ /*!
|
||||||
|
+ * @brief Overflow checker using compiler intrinsics
|
||||||
|
+ *
|
||||||
|
+ * This struct provides an add function with the same interface &
|
||||||
|
+ * behavior as fallback_add_overload::add but it relies on compiler
|
||||||
|
+ * intrinsics instead. This version should be considerably faster than
|
||||||
|
+ * the fallback version as it can fully utilize available CPU
|
||||||
|
+ * instructions & the compiler's diagnostic.
|
||||||
|
+ *
|
||||||
|
+ * However, as some compilers don't provide intrinsics for certain
|
||||||
|
+ * types, the default implementation of add is the version from falback.
|
||||||
|
+ *
|
||||||
|
+ * The struct is explicitly specialized for each type via #ifdefs for
|
||||||
|
+ * each compiler.
|
||||||
|
+ */
|
||||||
|
+ template <typename T>
|
||||||
|
+ struct builtin_add_overflow
|
||||||
|
+ {
|
||||||
|
+ /*!
|
||||||
|
+ * @brief Add summand_1 and summand_2 and check for overflows.
|
||||||
|
+ *
|
||||||
|
+ * This is the default add() function that uses
|
||||||
|
+ * fallback_add_overflow<T>::add(). All specializations must have
|
||||||
|
+ * exactly the same interface and behave the same way.
|
||||||
|
+ */
|
||||||
|
+ static inline bool add(T summand_1, T summand_2, T& result)
|
||||||
|
+ {
|
||||||
|
+ return fallback_add_overflow<T>::add(summand_1, summand_2, result);
|
||||||
|
+ }
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
+
|
||||||
|
+/*!
|
||||||
|
+ * This macro pastes a specialization of builtin_add_overflow using gcc's &
|
||||||
|
+ * clang's __builtin_(s/u)add(l)(l)_overlow()
|
||||||
|
+ *
|
||||||
|
+ * The add function is implemented by forwarding the parameters to the intrinsic
|
||||||
|
+ * and returning its value.
|
||||||
|
+ *
|
||||||
|
+ * The intrinsics are documented here:
|
||||||
|
+ * https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html#Integer-Overflow-Builtins
|
||||||
|
+ */
|
||||||
|
+#define SPECIALIZE_builtin_add_overflow(type, builtin_name) \
|
||||||
|
+ template <> \
|
||||||
|
+ struct builtin_add_overflow<type> \
|
||||||
|
+ { \
|
||||||
|
+ static inline bool add(type summand_1, type summand_2, type& result) \
|
||||||
|
+ { \
|
||||||
|
+ return builtin_name(summand_1, summand_2, &result); \
|
||||||
|
+ } \
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ SPECIALIZE_builtin_add_overflow(int, __builtin_sadd_overflow);
|
||||||
|
+ SPECIALIZE_builtin_add_overflow(long, __builtin_saddl_overflow);
|
||||||
|
+ SPECIALIZE_builtin_add_overflow(long long, __builtin_saddll_overflow);
|
||||||
|
+
|
||||||
|
+ SPECIALIZE_builtin_add_overflow(unsigned int, __builtin_uadd_overflow);
|
||||||
|
+ SPECIALIZE_builtin_add_overflow(unsigned long, __builtin_uaddl_overflow);
|
||||||
|
+ SPECIALIZE_builtin_add_overflow(unsigned long long, __builtin_uaddll_overflow);
|
||||||
|
+
|
||||||
|
+#undef SPECIALIZE_builtin_add_overflow
|
||||||
|
+
|
||||||
|
+#elif defined(_MSC_VER)
|
||||||
|
+
|
||||||
|
+/*!
|
||||||
|
+ * This macro pastes a specialization of builtin_add_overflow using MSVC's
|
||||||
|
+ * U(Int/Long/LongLong)Add.
|
||||||
|
+ *
|
||||||
|
+ * The add function is implemented by forwarding the parameters to the
|
||||||
|
+ * intrinsic. As MSVC's intrinsics return S_OK on success, this specialization
|
||||||
|
+ * returns whether the intrinsics return value does not equal S_OK. This ensures
|
||||||
|
+ * a uniform interface of the add function (false is returned when no overflow
|
||||||
|
+ * occurs, true on overflow).
|
||||||
|
+ *
|
||||||
|
+ * The intrinsics are documented here:
|
||||||
|
+ * https://msdn.microsoft.com/en-us/library/windows/desktop/ff516460(v=vs.85).aspx
|
||||||
|
+ */
|
||||||
|
+#define SPECIALIZE_builtin_add_overflow_WIN(type, builtin_name) \
|
||||||
|
+ template <> \
|
||||||
|
+ struct builtin_add_overflow<type> \
|
||||||
|
+ { \
|
||||||
|
+ static inline bool add(type summand_1, type summand_2, type& result) \
|
||||||
|
+ { \
|
||||||
|
+ return builtin_name(summand_1, summand_2, &result) != S_OK; \
|
||||||
|
+ } \
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ SPECIALIZE_builtin_add_overflow_WIN(unsigned int, UIntAdd);
|
||||||
|
+ SPECIALIZE_builtin_add_overflow_WIN(unsigned long, ULongAdd);
|
||||||
|
+ SPECIALIZE_builtin_add_overflow_WIN(unsigned long long, ULongLongAdd);
|
||||||
|
+
|
||||||
|
+#undef SPECIALIZE_builtin_add_overflow_WIN
|
||||||
|
+
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+ } // namespace Internal
|
||||||
|
+
|
||||||
|
+ /*!
|
||||||
|
+ * @brief Safe addition, throws an exception on overflow.
|
||||||
|
+ *
|
||||||
|
+ * This function returns the result of summand_1 and summand_2 only when the
|
||||||
|
+ * operation would not overflow, otherwise an exception of type
|
||||||
|
+ * std::overflow_error is thrown.
|
||||||
|
+ *
|
||||||
|
+ * @param[in] summand_1, summand_2 summands to be summed up
|
||||||
|
+ * @return the sum of summand_1 and summand_2
|
||||||
|
+ * @throws std::overflow_error if the addition would overflow
|
||||||
|
+ *
|
||||||
|
+ * This function utilizes compiler builtins when available and should have a
|
||||||
|
+ * very small performance hit then. When builtins are unavailable, a more
|
||||||
|
+ * extensive check is required.
|
||||||
|
+ *
|
||||||
|
+ * Builtins are available for the following configurations:
|
||||||
|
+ * - GCC/Clang for signed and unsigned int, long and long long (not char & short)
|
||||||
|
+ * - MSVC for unsigned int, long and long long
|
||||||
|
+ */
|
||||||
|
+ template <typename T>
|
||||||
|
+ T add(T summand_1, T summand_2)
|
||||||
|
+ {
|
||||||
|
+ T res = 0;
|
||||||
|
+ if (Internal::builtin_add_overflow<T>::add(summand_1, summand_2, res)) {
|
||||||
|
+ throw std::overflow_error("Overflow in addition");
|
||||||
|
+ }
|
||||||
|
+ return res;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+} // namespace Safe
|
||||||
|
+
|
||||||
|
+#endif // SAFE_OP_HPP_
|
344
SOURCES/exiv2-CVE-2018-10958.patch
Normal file
344
SOURCES/exiv2-CVE-2018-10958.patch
Normal file
@ -0,0 +1,344 @@
|
|||||||
|
diff --git a/include/exiv2/error.hpp b/include/exiv2/error.hpp
|
||||||
|
index 24a70bf6..cc67725b 100644
|
||||||
|
--- a/include/exiv2/error.hpp
|
||||||
|
+++ b/include/exiv2/error.hpp
|
||||||
|
@@ -192,6 +192,74 @@ namespace Exiv2 {
|
||||||
|
return os << error.what();
|
||||||
|
}
|
||||||
|
|
||||||
|
+ //! Complete list of all Exiv2 error codes
|
||||||
|
+ enum ErrorCode {
|
||||||
|
+ kerGeneralError = -1,
|
||||||
|
+ kerSuccess = 0,
|
||||||
|
+ kerErrorMessage,
|
||||||
|
+ kerCallFailed,
|
||||||
|
+ kerNotAnImage,
|
||||||
|
+ kerInvalidDataset,
|
||||||
|
+ kerInvalidRecord,
|
||||||
|
+ kerInvalidKey,
|
||||||
|
+ kerInvalidTag,
|
||||||
|
+ kerValueNotSet,
|
||||||
|
+ kerDataSourceOpenFailed,
|
||||||
|
+ kerFileOpenFailed,
|
||||||
|
+ kerFileContainsUnknownImageType,
|
||||||
|
+ kerMemoryContainsUnknownImageType,
|
||||||
|
+ kerUnsupportedImageType,
|
||||||
|
+ kerFailedToReadImageData,
|
||||||
|
+ kerNotAJpeg,
|
||||||
|
+ kerFailedToMapFileForReadWrite,
|
||||||
|
+ kerFileRenameFailed,
|
||||||
|
+ kerTransferFailed,
|
||||||
|
+ kerMemoryTransferFailed,
|
||||||
|
+ kerInputDataReadFailed,
|
||||||
|
+ kerImageWriteFailed,
|
||||||
|
+ kerNoImageInInputData,
|
||||||
|
+ kerInvalidIfdId,
|
||||||
|
+ //! Entry::setValue: Value too large
|
||||||
|
+ kerValueTooLarge,
|
||||||
|
+ //! Entry::setDataArea: Value too large
|
||||||
|
+ kerDataAreaValueTooLarge,
|
||||||
|
+ kerOffsetOutOfRange,
|
||||||
|
+ kerUnsupportedDataAreaOffsetType,
|
||||||
|
+ kerInvalidCharset,
|
||||||
|
+ kerUnsupportedDateFormat,
|
||||||
|
+ kerUnsupportedTimeFormat,
|
||||||
|
+ kerWritingImageFormatUnsupported,
|
||||||
|
+ kerInvalidSettingForImage,
|
||||||
|
+ kerNotACrwImage,
|
||||||
|
+ kerFunctionNotSupported,
|
||||||
|
+ kerNoNamespaceInfoForXmpPrefix,
|
||||||
|
+ kerNoPrefixForNamespace,
|
||||||
|
+ kerTooLargeJpegSegment,
|
||||||
|
+ kerUnhandledXmpdatum,
|
||||||
|
+ kerUnhandledXmpNode,
|
||||||
|
+ kerXMPToolkitError,
|
||||||
|
+ kerDecodeLangAltPropertyFailed,
|
||||||
|
+ kerDecodeLangAltQualifierFailed,
|
||||||
|
+ kerEncodeLangAltPropertyFailed,
|
||||||
|
+ kerPropertyNameIdentificationFailed,
|
||||||
|
+ kerSchemaNamespaceNotRegistered,
|
||||||
|
+ kerNoNamespaceForPrefix,
|
||||||
|
+ kerAliasesNotSupported,
|
||||||
|
+ kerInvalidXmpText,
|
||||||
|
+ kerTooManyTiffDirectoryEntries,
|
||||||
|
+ kerMultipleTiffArrayElementTagsInDirectory,
|
||||||
|
+ kerWrongTiffArrayElementTagType,
|
||||||
|
+ kerInvalidKeyXmpValue,
|
||||||
|
+ kerInvalidIccProfile,
|
||||||
|
+ kerInvalidXMP,
|
||||||
|
+ kerTiffDirectoryTooLarge,
|
||||||
|
+ kerInvalidTypeValue,
|
||||||
|
+ kerInvalidMalloc,
|
||||||
|
+ kerCorruptedMetadata,
|
||||||
|
+ kerArithmeticOverflow,
|
||||||
|
+ kerMallocFailed,
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
/*!
|
||||||
|
@brief Simple error class used for exceptions. An output operator is
|
||||||
|
provided to print errors to a stream.
|
||||||
|
|
||||||
|
diff --git a/src/enforce.hpp b/src/enforce.hpp
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..b2d77eea
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/enforce.hpp
|
||||||
|
@@ -0,0 +1,96 @@
|
||||||
|
+// ********************************************************* -*- C++ -*-
|
||||||
|
+/*
|
||||||
|
+ * Copyright (C) 2004-2018 Exiv2 maintainers
|
||||||
|
+ *
|
||||||
|
+ * 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.
|
||||||
|
+ */
|
||||||
|
+/*!
|
||||||
|
+ @file enforce.hpp
|
||||||
|
+ @brief Port of D's enforce() to C++ & Exiv2
|
||||||
|
+ @author Dan Čermák (D4N)
|
||||||
|
+ <a href="mailto:dan.cermak@cgc-instruments.com">dan.cermak@cgc-instruments.com</a>
|
||||||
|
+ @date 11-March-18, D4N: created
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <string>
|
||||||
|
+
|
||||||
|
+#include "error.hpp"
|
||||||
|
+
|
||||||
|
+/*!
|
||||||
|
+ * @brief Ensure that condition is true, otherwise throw an exception of the
|
||||||
|
+ * type exception_t
|
||||||
|
+ *
|
||||||
|
+ * @tparam exception_t Exception type that is thrown, must provide a
|
||||||
|
+ * constructor that accepts a single argument to which arg1 is forwarded.
|
||||||
|
+ *
|
||||||
|
+ * @todo once we have C++>=11 use variadic templates and std::forward to remove
|
||||||
|
+ * all overloads of enforce
|
||||||
|
+ */
|
||||||
|
+template <typename exception_t, typename T>
|
||||||
|
+inline void enforce(bool condition, const T& arg1)
|
||||||
|
+{
|
||||||
|
+ if (!condition) {
|
||||||
|
+ throw exception_t(arg1);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/*!
|
||||||
|
+ * @brief Ensure that condition is true, otherwise throw an Exiv2::Error with
|
||||||
|
+ * the given error_code.
|
||||||
|
+ */
|
||||||
|
+inline void enforce(bool condition, Exiv2::ErrorCode err_code)
|
||||||
|
+{
|
||||||
|
+ if (!condition) {
|
||||||
|
+ throw Exiv2::Error(err_code);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/*!
|
||||||
|
+ * @brief Ensure that condition is true, otherwise throw an Exiv2::Error with
|
||||||
|
+ * the given error_code & arg1.
|
||||||
|
+ */
|
||||||
|
+template <typename T>
|
||||||
|
+inline void enforce(bool condition, Exiv2::ErrorCode err_code, const T& arg1)
|
||||||
|
+{
|
||||||
|
+ if (!condition) {
|
||||||
|
+ throw Exiv2::Error(err_code, arg1);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/*!
|
||||||
|
+ * @brief Ensure that condition is true, otherwise throw an Exiv2::Error with
|
||||||
|
+ * the given error_code, arg1 & arg2.
|
||||||
|
+ */
|
||||||
|
+template <typename T, typename U>
|
||||||
|
+inline void enforce(bool condition, Exiv2::ErrorCode err_code, const T& arg1, const U& arg2)
|
||||||
|
+{
|
||||||
|
+ if (!condition) {
|
||||||
|
+ throw Exiv2::Error(err_code, arg1, arg2);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/*!
|
||||||
|
+ * @brief Ensure that condition is true, otherwise throw an Exiv2::Error with
|
||||||
|
+ * the given error_code, arg1, arg2 & arg3.
|
||||||
|
+ */
|
||||||
|
+template <typename T, typename U, typename V>
|
||||||
|
+inline void enforce(bool condition, Exiv2::ErrorCode err_code, const T& arg1, const U& arg2, const V& arg3)
|
||||||
|
+{
|
||||||
|
+ if (!condition) {
|
||||||
|
+ throw Exiv2::Error(err_code, arg1, arg2, arg3);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
|
||||||
|
diff --git a/src/pngchunk.cpp b/src/pngchunk.cpp
|
||||||
|
index 4dcca4d..aae0f5f 100644
|
||||||
|
--- a/src/pngchunk.cpp
|
||||||
|
+++ b/src/pngchunk.cpp
|
||||||
|
@@ -37,6 +37,7 @@ EXIV2_RCSID("@(#) $Id$")
|
||||||
|
#include "iptc.hpp"
|
||||||
|
#include "image.hpp"
|
||||||
|
#include "error.hpp"
|
||||||
|
+#include "enforce.hpp"
|
||||||
|
|
||||||
|
// + standard includes
|
||||||
|
#include <sstream>
|
||||||
|
@@ -46,6 +47,7 @@ EXIV2_RCSID("@(#) $Id$")
|
||||||
|
#include <iostream>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdio>
|
||||||
|
+#include <algorithm>
|
||||||
|
|
||||||
|
#include <zlib.h> // To uncompress or compress text chunk
|
||||||
|
|
||||||
|
@@ -86,7 +88,7 @@ namespace Exiv2 {
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
std::cout << "Exiv2::PngChunk::decodeTXTChunk: TXT chunk data: "
|
||||||
|
- << std::string((const char*)arr.pData_, arr.size_) << "\n";
|
||||||
|
+ << std::string((const char*)arr.pData_, arr.size_) << std::endl;
|
||||||
|
#endif
|
||||||
|
parseChunkContent(pImage, key.pData_, key.size_, arr);
|
||||||
|
|
||||||
|
@@ -99,7 +101,7 @@ namespace Exiv2 {
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
std::cout << "Exiv2::PngChunk::decodeTXTChunk: TXT chunk key: "
|
||||||
|
- << std::string((const char*)key.pData_, key.size_) << "\n";
|
||||||
|
+ << std::string((const char*)key.pData_, key.size_) << std::endl;
|
||||||
|
#endif
|
||||||
|
return parseTXTChunk(data, key.size_, type);
|
||||||
|
|
||||||
|
@@ -164,12 +166,18 @@ namespace Exiv2 {
|
||||||
|
}
|
||||||
|
else if(type == iTXt_Chunk)
|
||||||
|
{
|
||||||
|
+ const int nullSeparators = std::count(&data.pData_[keysize+3], &data.pData_[data.size_], '\0');
|
||||||
|
+
|
||||||
|
+ enforce(nullSeparators >= 2, Exiv2::kerCorruptedMetadata);
|
||||||
|
+
|
||||||
|
// Extract a deflate compressed or uncompressed UTF-8 text chunk
|
||||||
|
|
||||||
|
// we get the compression flag after the key
|
||||||
|
- const byte* compressionFlag = data.pData_ + keysize + 1;
|
||||||
|
+ const byte compressionFlag = data.pData_[keysize + 1];
|
||||||
|
// we get the compression method after the compression flag
|
||||||
|
- const byte* compressionMethod = data.pData_ + keysize + 2;
|
||||||
|
+ const byte compressionMethod = data.pData_[keysize + 2];
|
||||||
|
+ enforce(compressionFlag == 0x00 || compressionFlag == 0x01, Exiv2::kerCorruptedMetadata);
|
||||||
|
+ enforce(compressionMethod == 0x00, Exiv2::kerCorruptedMetadata);
|
||||||
|
// language description string after the compression technique spec
|
||||||
|
std::string languageText((const char*)(data.pData_ + keysize + 3));
|
||||||
|
unsigned int languageTextSize = static_cast<unsigned int>(languageText.size());
|
||||||
|
@@ -177,7 +185,7 @@ namespace Exiv2 {
|
||||||
|
std::string translatedKeyText((const char*)(data.pData_ + keysize + 3 + languageTextSize +1));
|
||||||
|
unsigned int translatedKeyTextSize = static_cast<unsigned int>(translatedKeyText.size());
|
||||||
|
|
||||||
|
- if ( compressionFlag[0] == 0x00 )
|
||||||
|
+ if ( compressionFlag == 0x00 )
|
||||||
|
{
|
||||||
|
// then it's an uncompressed iTXt chunk
|
||||||
|
#ifdef DEBUG
|
||||||
|
@@ -191,7 +199,7 @@ namespace Exiv2 {
|
||||||
|
arr.alloc(textsize);
|
||||||
|
arr = DataBuf(text, textsize);
|
||||||
|
}
|
||||||
|
- else if ( compressionFlag[0] == 0x01 && compressionMethod[0] == 0x00 )
|
||||||
|
+ else if ( compressionFlag == 0x01 && compressionMethod == 0x00 )
|
||||||
|
{
|
||||||
|
// then it's a zlib compressed iTXt chunk
|
||||||
|
#ifdef DEBUG
|
||||||
|
diff --git a/src/pngimage.cpp b/src/pngimage.cpp
|
||||||
|
index ed7399a..991da6c 100644
|
||||||
|
--- a/src/pngimage.cpp
|
||||||
|
+++ b/src/pngimage.cpp
|
||||||
|
@@ -375,7 +375,7 @@ namespace Exiv2 {
|
||||||
|
void PngImage::readMetadata()
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
- std::cerr << "Exiv2::PngImage::readMetadata: Reading PNG file " << io_->path() << "\n";
|
||||||
|
+ std::cerr << "Exiv2::PngImage::readMetadata: Reading PNG file " << io_->path() << std::endl;
|
||||||
|
#endif
|
||||||
|
if (io_->open() != 0)
|
||||||
|
{
|
||||||
|
@@ -398,7 +398,7 @@ namespace Exiv2 {
|
||||||
|
// Read chunk header.
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
- std::cout << "Exiv2::PngImage::readMetadata: Position: " << io_->tell() << "\n";
|
||||||
|
+ std::cout << "Exiv2::PngImage::readMetadata: Position: " << io_->tell() << std::endl;
|
||||||
|
#endif
|
||||||
|
std::memset(cheaderBuf.pData_, 0x0, cheaderBuf.size_);
|
||||||
|
long bufRead = io_->read(cheaderBuf.pData_, cheaderBuf.size_);
|
||||||
|
@@ -432,14 +432,14 @@ namespace Exiv2 {
|
||||||
|
{
|
||||||
|
// Last chunk found: we stop parsing.
|
||||||
|
#ifdef DEBUG
|
||||||
|
- std::cout << "Exiv2::PngImage::readMetadata: Found IEND chunk (length: " << dataOffset << ")\n";
|
||||||
|
+ std::cout << "Exiv2::PngImage::readMetadata: Found IEND chunk with length: " << dataOffset << std::endl;
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (!memcmp(cheaderBuf.pData_ + 4, "IHDR", 4))
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
- std::cout << "Exiv2::PngImage::readMetadata: Found IHDR chunk (length: " << dataOffset << ")\n";
|
||||||
|
+ std::cout << "Exiv2::PngImage::readMetadata: Found IHDR chunk with length: " << dataOffset << std::endl;
|
||||||
|
#endif
|
||||||
|
if (cdataBuf.size_ >= 8) {
|
||||||
|
PngChunk::decodeIHDRChunk(cdataBuf, &pixelWidth_, &pixelHeight_);
|
||||||
|
@@ -448,21 +448,21 @@ namespace Exiv2 {
|
||||||
|
else if (!memcmp(cheaderBuf.pData_ + 4, "tEXt", 4))
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
- std::cout << "Exiv2::PngImage::readMetadata: Found tEXt chunk (length: " << dataOffset << ")\n";
|
||||||
|
+ std::cout << "Exiv2::PngImage::readMetadata: Found tEXt chunk with length: " << dataOffset << std::endl;
|
||||||
|
#endif
|
||||||
|
PngChunk::decodeTXTChunk(this, cdataBuf, PngChunk::tEXt_Chunk);
|
||||||
|
}
|
||||||
|
else if (!memcmp(cheaderBuf.pData_ + 4, "zTXt", 4))
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
- std::cout << "Exiv2::PngImage::readMetadata: Found zTXt chunk (length: " << dataOffset << ")\n";
|
||||||
|
+ std::cout << "Exiv2::PngImage::readMetadata: Found zTXt chunk with length: " << dataOffset << std::endl;
|
||||||
|
#endif
|
||||||
|
PngChunk::decodeTXTChunk(this, cdataBuf, PngChunk::zTXt_Chunk);
|
||||||
|
}
|
||||||
|
else if (!memcmp(cheaderBuf.pData_ + 4, "iTXt", 4))
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
- std::cout << "Exiv2::PngImage::readMetadata: Found iTXt chunk (length: " << dataOffset << ")\n";
|
||||||
|
+ std::cout << "Exiv2::PngImage::readMetadata: Found iTXt chunk with length: " << dataOffset << std::endl;
|
||||||
|
#endif
|
||||||
|
PngChunk::decodeTXTChunk(this, cdataBuf, PngChunk::iTXt_Chunk);
|
||||||
|
}
|
||||||
|
@@ -481,7 +481,7 @@ namespace Exiv2 {
|
||||||
|
|
||||||
|
// Move to the next chunk: chunk data size + 4 CRC bytes.
|
||||||
|
#ifdef DEBUG
|
||||||
|
- std::cout << "Exiv2::PngImage::readMetadata: Seek to offset: " << dataOffset + 4 << "\n";
|
||||||
|
+ std::cout << "Exiv2::PngImage::readMetadata: Seek to offset: " << dataOffset + 4 << std::endl;
|
||||||
|
#endif
|
||||||
|
io_->seek(dataOffset + 4 , BasicIo::cur);
|
||||||
|
if (io_->error() || io_->eof()) throw Error(14);
|
||||||
|
@@ -511,8 +511,8 @@ namespace Exiv2 {
|
||||||
|
if (!outIo.isopen()) throw Error(21);
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
- std::cout << "Exiv2::PngImage::doWriteMetadata: Writing PNG file " << io_->path() << "\n";
|
||||||
|
- std::cout << "Exiv2::PngImage::doWriteMetadata: tmp file created " << outIo.path() << "\n";
|
||||||
|
+ std::cout << "Exiv2::PngImage::doWriteMetadata: Writing PNG file " << io_->path() << std::endl;
|
||||||
|
+ std::cout << "Exiv2::PngImage::doWriteMetadata: tmp file created " << outIo.path() << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Ensure that this is the correct image type
|
61
SOURCES/exiv2-CVE-2018-10998.patch
Normal file
61
SOURCES/exiv2-CVE-2018-10998.patch
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
diff --git a/src/exiv2.cpp b/src/exiv2.cpp
|
||||||
|
index d6a45e1..dbd2834 100644
|
||||||
|
--- a/src/exiv2.cpp
|
||||||
|
+++ b/src/exiv2.cpp
|
||||||
|
@@ -150,31 +150,35 @@ int main(int argc, char* const argv[])
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
- // Create the required action class
|
||||||
|
- Action::TaskFactory& taskFactory = Action::TaskFactory::instance();
|
||||||
|
- Action::Task::AutoPtr task
|
||||||
|
- = taskFactory.create(Action::TaskType(params.action_));
|
||||||
|
- assert(task.get());
|
||||||
|
-
|
||||||
|
- // Process all files
|
||||||
|
int rc = 0;
|
||||||
|
- int n = 1;
|
||||||
|
- int s = static_cast<int>(params.files_.size());
|
||||||
|
- int w = s > 9 ? s > 99 ? 3 : 2 : 1;
|
||||||
|
- for (Params::Files::const_iterator i = params.files_.begin();
|
||||||
|
- i != params.files_.end(); ++i) {
|
||||||
|
- if (params.verbose_) {
|
||||||
|
- std::cout << _("File") << " " << std::setw(w) << std::right << n++ << "/" << s << ": "
|
||||||
|
- << *i << std::endl;
|
||||||
|
+ try {
|
||||||
|
+ // Create the required action class
|
||||||
|
+ Action::TaskFactory& taskFactory = Action::TaskFactory::instance();
|
||||||
|
+ Action::Task::AutoPtr task = taskFactory.create(Action::TaskType(params.action_));
|
||||||
|
+ assert(task.get());
|
||||||
|
+
|
||||||
|
+ // Process all files
|
||||||
|
+ int n = 1;
|
||||||
|
+ int s = static_cast<int>(params.files_.size());
|
||||||
|
+ int w = s > 9 ? s > 99 ? 3 : 2 : 1;
|
||||||
|
+ for (Params::Files::const_iterator i = params.files_.begin(); i != params.files_.end(); ++i) {
|
||||||
|
+ if (params.verbose_) {
|
||||||
|
+ std::cout << _("File") << " " << std::setw(w) << std::right << n++ << "/" << s << ": " << *i
|
||||||
|
+ << std::endl;
|
||||||
|
+ }
|
||||||
|
+ int ret = task->run(*i);
|
||||||
|
+ if (rc == 0)
|
||||||
|
+ rc = ret;
|
||||||
|
}
|
||||||
|
- int ret = task->run(*i);
|
||||||
|
- if (rc == 0) rc = ret;
|
||||||
|
- }
|
||||||
|
|
||||||
|
- taskFactory.cleanup();
|
||||||
|
- params.cleanup();
|
||||||
|
- Exiv2::XmpParser::terminate();
|
||||||
|
+ taskFactory.cleanup();
|
||||||
|
+ params.cleanup();
|
||||||
|
+ Exiv2::XmpParser::terminate();
|
||||||
|
|
||||||
|
+ } catch (const std::exception& exc) {
|
||||||
|
+ std::cerr << "Uncaught exception: " << exc.what() << std::endl;
|
||||||
|
+ rc = 1;
|
||||||
|
+ }
|
||||||
|
// Return a positive one byte code for better consistency across platforms
|
||||||
|
return static_cast<unsigned int>(rc) % 256;
|
||||||
|
} // main
|
31
SOURCES/exiv2-CVE-2018-11531.patch
Normal file
31
SOURCES/exiv2-CVE-2018-11531.patch
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
diff --git a/src/preview.cpp b/src/preview.cpp
|
||||||
|
index c34c8bd..69f8e01 100644
|
||||||
|
--- a/src/preview.cpp
|
||||||
|
+++ b/src/preview.cpp
|
||||||
|
@@ -36,6 +36,7 @@ EXIV2_RCSID("@(#) $Id$")
|
||||||
|
|
||||||
|
#include "preview.hpp"
|
||||||
|
#include "futils.hpp"
|
||||||
|
+#include "enforce.hpp"
|
||||||
|
|
||||||
|
#include "image.hpp"
|
||||||
|
#include "cr2image.hpp"
|
||||||
|
@@ -807,13 +808,14 @@ namespace {
|
||||||
|
else {
|
||||||
|
// FIXME: the buffer is probably copied twice, it should be optimized
|
||||||
|
DataBuf buf(size_);
|
||||||
|
- Exiv2::byte* pos = buf.pData_;
|
||||||
|
+ uint32_t idxBuf = 0;
|
||||||
|
for (int i = 0; i < sizes.count(); i++) {
|
||||||
|
uint32_t offset = dataValue.toLong(i);
|
||||||
|
uint32_t size = sizes.toLong(i);
|
||||||
|
- if (offset + size <= static_cast<uint32_t>(io.size()))
|
||||||
|
- memcpy(pos, base + offset, size);
|
||||||
|
- pos += size;
|
||||||
|
+ enforce(idxBuf + size < size_, kerCorruptedMetadata);
|
||||||
|
+ if (size!=0 && offset + size <= static_cast<uint32_t>(io.size()))
|
||||||
|
+ memcpy(&buf.pData_[idxBuf], base + offset, size);
|
||||||
|
+ idxBuf += size;
|
||||||
|
}
|
||||||
|
dataValue.setDataArea(buf.pData_, buf.size_);
|
||||||
|
}
|
60
SOURCES/exiv2-CVE-2018-12264-CVE-2018-12265.patch
Normal file
60
SOURCES/exiv2-CVE-2018-12264-CVE-2018-12265.patch
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
diff --git a/src/preview.cpp b/src/preview.cpp
|
||||||
|
index 69f8e01..d20de04 100644
|
||||||
|
--- a/src/preview.cpp
|
||||||
|
+++ b/src/preview.cpp
|
||||||
|
@@ -37,6 +37,7 @@ EXIV2_RCSID("@(#) $Id$")
|
||||||
|
#include "preview.hpp"
|
||||||
|
#include "futils.hpp"
|
||||||
|
#include "enforce.hpp"
|
||||||
|
+#include "safe_op.hpp"
|
||||||
|
|
||||||
|
#include "image.hpp"
|
||||||
|
#include "cr2image.hpp"
|
||||||
|
@@ -386,7 +387,7 @@ namespace {
|
||||||
|
return AutoPtr();
|
||||||
|
|
||||||
|
if (loaderList_[id].imageMimeType_ &&
|
||||||
|
- std::string(loaderList_[id].imageMimeType_) != std::string(image.mimeType()))
|
||||||
|
+ std::string(loaderList_[id].imageMimeType_) != image.mimeType())
|
||||||
|
return AutoPtr();
|
||||||
|
|
||||||
|
AutoPtr loader = loaderList_[id].create_(id, image, loaderList_[id].parIdx_);
|
||||||
|
@@ -548,7 +549,8 @@ namespace {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (offset_ + size_ > static_cast<uint32_t>(image_.io().size())) return;
|
||||||
|
+ if (Safe::add(offset_, size_) > static_cast<uint32_t>(image_.io().size()))
|
||||||
|
+ return;
|
||||||
|
|
||||||
|
valid_ = true;
|
||||||
|
}
|
||||||
|
@@ -802,7 +804,7 @@ namespace {
|
||||||
|
// this saves one copying of the buffer
|
||||||
|
uint32_t offset = dataValue.toLong(0);
|
||||||
|
uint32_t size = sizes.toLong(0);
|
||||||
|
- if (offset + size <= static_cast<uint32_t>(io.size()))
|
||||||
|
+ if (Safe::add(offset, size) <= static_cast<uint32_t>(io.size()))
|
||||||
|
dataValue.setDataArea(base + offset, size);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
@@ -812,8 +814,8 @@ namespace {
|
||||||
|
for (int i = 0; i < sizes.count(); i++) {
|
||||||
|
uint32_t offset = dataValue.toLong(i);
|
||||||
|
uint32_t size = sizes.toLong(i);
|
||||||
|
- enforce(idxBuf + size < size_, kerCorruptedMetadata);
|
||||||
|
- if (size!=0 && offset + size <= static_cast<uint32_t>(io.size()))
|
||||||
|
+ enforce(Safe::add(idxBuf, size) < size_, kerCorruptedMetadata);
|
||||||
|
+ if (size!=0 && Safe::add(offset, size) <= static_cast<uint32_t>(io.size()))
|
||||||
|
memcpy(&buf.pData_[idxBuf], base + offset, size);
|
||||||
|
idxBuf += size;
|
||||||
|
}
|
||||||
|
@@ -930,7 +932,7 @@ namespace {
|
||||||
|
|
||||||
|
DataBuf decodeBase64(const std::string& src)
|
||||||
|
{
|
||||||
|
- const unsigned long srcSize = static_cast<const unsigned long>(src.size());
|
||||||
|
+ const unsigned long srcSize = src.size();
|
||||||
|
|
||||||
|
// create decoding table
|
||||||
|
unsigned long invalid = 64;
|
49
SOURCES/exiv2-CVE-2018-14046.patch
Normal file
49
SOURCES/exiv2-CVE-2018-14046.patch
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
diff --git a/src/webpimage.cpp b/src/webpimage.cpp
|
||||||
|
index e4057d6..f1dd77c 100644
|
||||||
|
--- a/src/webpimage.cpp
|
||||||
|
+++ b/src/webpimage.cpp
|
||||||
|
@@ -44,6 +44,8 @@
|
||||||
|
#include "tiffimage.hpp"
|
||||||
|
#include "tiffimage_int.hpp"
|
||||||
|
#include "convert.hpp"
|
||||||
|
+#include "enforce.hpp"
|
||||||
|
+
|
||||||
|
#include <cmath>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <string>
|
||||||
|
@@ -516,6 +518,8 @@ namespace Exiv2 {
|
||||||
|
DataBuf payload(size);
|
||||||
|
|
||||||
|
if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8X) && !has_canvas_data) {
|
||||||
|
+ enforce(size >= 10, Exiv2::kerCorruptedMetadata);
|
||||||
|
+
|
||||||
|
has_canvas_data = true;
|
||||||
|
byte size_buf[WEBP_TAG_SIZE];
|
||||||
|
|
||||||
|
@@ -531,6 +535,8 @@ namespace Exiv2 {
|
||||||
|
size_buf[3] = 0;
|
||||||
|
pixelHeight_ = Exiv2::getULong(size_buf, littleEndian) + 1;
|
||||||
|
} else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8) && !has_canvas_data) {
|
||||||
|
+ enforce(size >= 10, Exiv2::kerCorruptedMetadata);
|
||||||
|
+
|
||||||
|
has_canvas_data = true;
|
||||||
|
io_->read(payload.pData_, payload.size_);
|
||||||
|
byte size_buf[WEBP_TAG_SIZE];
|
||||||
|
@@ -547,6 +553,8 @@ namespace Exiv2 {
|
||||||
|
size_buf[3] = 0;
|
||||||
|
pixelHeight_ = Exiv2::getULong(size_buf, littleEndian) & 0x3fff;
|
||||||
|
} else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8L) && !has_canvas_data) {
|
||||||
|
+ enforce(size >= 5, Exiv2::kerCorruptedMetadata);
|
||||||
|
+
|
||||||
|
has_canvas_data = true;
|
||||||
|
byte size_buf_w[2];
|
||||||
|
byte size_buf_h[3];
|
||||||
|
@@ -564,6 +572,8 @@ namespace Exiv2 {
|
||||||
|
size_buf_h[1] = ((size_buf_h[1] >> 6) & 0x3) | ((size_buf_h[2] & 0xF) << 0x2);
|
||||||
|
pixelHeight_ = Exiv2::getUShort(size_buf_h, littleEndian) + 1;
|
||||||
|
} else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_ANMF) && !has_canvas_data) {
|
||||||
|
+ enforce(size >= 12, Exiv2::kerCorruptedMetadata);
|
||||||
|
+
|
||||||
|
has_canvas_data = true;
|
||||||
|
byte size_buf[WEBP_TAG_SIZE];
|
||||||
|
|
239
SOURCES/exiv2-CVE-2018-16336.patch
Normal file
239
SOURCES/exiv2-CVE-2018-16336.patch
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
|
||||||
|
index aecd621..cbbd859 100644
|
||||||
|
--- a/src/CMakeLists.txt
|
||||||
|
+++ b/src/CMakeLists.txt
|
||||||
|
@@ -26,6 +26,7 @@ SET( LIBEXIV2_PRIVATE_HDR canonmn_int.hpp
|
||||||
|
pngchunk_int.hpp
|
||||||
|
rcsid_int.hpp
|
||||||
|
rw2image_int.hpp
|
||||||
|
+ safe_op.hpp
|
||||||
|
samsungmn_int.hpp
|
||||||
|
sigmamn_int.hpp
|
||||||
|
sonymn_int.hpp
|
||||||
|
@@ -102,6 +103,7 @@ SET( LIBEXIV2_SRC asfvideo.cpp
|
||||||
|
futils.cpp
|
||||||
|
fujimn.cpp
|
||||||
|
gifimage.cpp
|
||||||
|
+ helper_functions.cpp
|
||||||
|
http.cpp
|
||||||
|
image.cpp
|
||||||
|
ini.cpp
|
||||||
|
diff --git a/src/helper_functions.cpp b/src/helper_functions.cpp
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000..623fbc1
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/helper_functions.cpp
|
||||||
|
@@ -0,0 +1,39 @@
|
||||||
|
+// ********************************************************* -*- C++ -*-
|
||||||
|
+/*
|
||||||
|
+ * Copyright (C) 2004-2018 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.
|
||||||
|
+ */
|
||||||
|
+/*!
|
||||||
|
+ @file helper_functions.cpp
|
||||||
|
+ @brief A collection of helper functions
|
||||||
|
+ @author Dan Čermák (D4N)
|
||||||
|
+ <a href="mailto:dan.cermak@cgc-instruments.com">dan.cermak@cgc-instruments.com</a>
|
||||||
|
+ @date 25-May-18, D4N: created
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include "helper_functions.hpp"
|
||||||
|
+
|
||||||
|
+#include <string.h>
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+std::string string_from_unterminated(const char* data, size_t data_length)
|
||||||
|
+{
|
||||||
|
+ const size_t StringLength = strnlen(data, data_length);
|
||||||
|
+
|
||||||
|
+ return std::string(data, StringLength);
|
||||||
|
+}
|
||||||
|
diff --git a/src/helper_functions.hpp b/src/helper_functions.hpp
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000..d70cbc1
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/helper_functions.hpp
|
||||||
|
@@ -0,0 +1,50 @@
|
||||||
|
+// ********************************************************* -*- C++ -*-
|
||||||
|
+/*
|
||||||
|
+ * Copyright (C) 2004-2018 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.
|
||||||
|
+ */
|
||||||
|
+/*!
|
||||||
|
+ @file helper_functions.hpp
|
||||||
|
+ @brief A collection of helper functions
|
||||||
|
+ @author Dan Čermák (D4N)
|
||||||
|
+ <a href="mailto:dan.cermak@cgc-instruments.com">dan.cermak@cgc-instruments.com</a>
|
||||||
|
+ @date 25-May-18, D4N: created
|
||||||
|
+ */
|
||||||
|
+#ifndef HELPER_FUNCTIONS_HPP
|
||||||
|
+#define HELPER_FUNCTIONS_HPP
|
||||||
|
+
|
||||||
|
+#include <string>
|
||||||
|
+
|
||||||
|
+/*!
|
||||||
|
+ @brief Convert a (potentially not null terminated) array into a
|
||||||
|
+ std::string.
|
||||||
|
+
|
||||||
|
+ Convert a C style string that may or may not be null terminated safely
|
||||||
|
+ into a std::string. The string's termination is either set at the first \0
|
||||||
|
+ or after data_length characters.
|
||||||
|
+
|
||||||
|
+ @param[in] data A c-string from which the std::string shall be
|
||||||
|
+ constructed. Does not need to be null terminated.
|
||||||
|
+ @param[in] data_length An upper bound for the string length (must be at most
|
||||||
|
+ the allocated length of `buffer`). If no null terminator is found in data,
|
||||||
|
+ then the resulting std::string will be null terminated at `data_length`.
|
||||||
|
+
|
||||||
|
+ */
|
||||||
|
+std::string string_from_unterminated(const char* data, size_t data_length);
|
||||||
|
+
|
||||||
|
+#endif // HELPER_FUNCTIONS_HPP
|
||||||
|
diff --git a/src/pngchunk.cpp b/src/pngchunk.cpp
|
||||||
|
index 29ffcfa..e4e3274 100644
|
||||||
|
--- a/src/pngchunk.cpp
|
||||||
|
+++ b/src/pngchunk.cpp
|
||||||
|
@@ -38,6 +38,8 @@ EXIV2_RCSID("@(#) $Id$")
|
||||||
|
#include "image.hpp"
|
||||||
|
#include "error.hpp"
|
||||||
|
#include "enforce.hpp"
|
||||||
|
+#include "helper_functions.hpp"
|
||||||
|
+#include "safe_op.hpp"
|
||||||
|
|
||||||
|
// + standard includes
|
||||||
|
#include <sstream>
|
||||||
|
@@ -137,6 +139,8 @@ namespace Exiv2 {
|
||||||
|
|
||||||
|
if(type == zTXt_Chunk)
|
||||||
|
{
|
||||||
|
+ enforce(data.size_ >= Safe::add(keysize, 2), Exiv2::kerCorruptedMetadata);
|
||||||
|
+
|
||||||
|
// Extract a deflate compressed Latin-1 text chunk
|
||||||
|
|
||||||
|
// we get the compression method after the key
|
||||||
|
@@ -153,11 +157,13 @@ namespace Exiv2 {
|
||||||
|
// compressed string after the compression technique spec
|
||||||
|
const byte* compressedText = data.pData_ + keysize + 2;
|
||||||
|
unsigned int compressedTextSize = data.size_ - keysize - 2;
|
||||||
|
+ enforce(compressedTextSize < data.size_, kerCorruptedMetadata);
|
||||||
|
|
||||||
|
zlibUncompress(compressedText, compressedTextSize, arr);
|
||||||
|
}
|
||||||
|
else if(type == tEXt_Chunk)
|
||||||
|
{
|
||||||
|
+ enforce(data.size_ >= Safe::add(keysize, 1), Exiv2::kerCorruptedMetadata);
|
||||||
|
// Extract a non-compressed Latin-1 text chunk
|
||||||
|
|
||||||
|
// the text comes after the key, but isn't null terminated
|
||||||
|
@@ -168,6 +174,7 @@ namespace Exiv2 {
|
||||||
|
}
|
||||||
|
else if(type == iTXt_Chunk)
|
||||||
|
{
|
||||||
|
+ enforce(data.size_ >= Safe::add(keysize, 3), Exiv2::kerCorruptedMetadata);
|
||||||
|
const int nullSeparators = std::count(&data.pData_[keysize+3], &data.pData_[data.size_], '\0');
|
||||||
|
|
||||||
|
enforce(nullSeparators >= 2, Exiv2::kerCorruptedMetadata);
|
||||||
|
@@ -180,42 +187,46 @@ namespace Exiv2 {
|
||||||
|
const byte compressionMethod = data.pData_[keysize + 2];
|
||||||
|
enforce(compressionFlag == 0x00 || compressionFlag == 0x01, Exiv2::kerCorruptedMetadata);
|
||||||
|
enforce(compressionMethod == 0x00, Exiv2::kerCorruptedMetadata);
|
||||||
|
+
|
||||||
|
// language description string after the compression technique spec
|
||||||
|
- std::string languageText((const char*)(data.pData_ + keysize + 3));
|
||||||
|
- unsigned int languageTextSize = static_cast<unsigned int>(languageText.size());
|
||||||
|
+ const size_t languageTextMaxSize = data.size_ - keysize - 3;
|
||||||
|
+ std::string languageText =
|
||||||
|
+ string_from_unterminated((const char*)(data.pData_ + Safe::add(keysize, 3)), languageTextMaxSize);
|
||||||
|
+ const unsigned int languageTextSize = static_cast<unsigned int>(languageText.size());
|
||||||
|
+ enforce(data.size_ >= Safe::add(static_cast<unsigned int>(Safe::add(keysize, 4)), languageTextSize),
|
||||||
|
+ Exiv2::kerCorruptedMetadata);
|
||||||
|
+
|
||||||
|
// translated keyword string after the language description
|
||||||
|
- std::string translatedKeyText((const char*)(data.pData_ + keysize + 3 + languageTextSize +1));
|
||||||
|
- unsigned int translatedKeyTextSize = static_cast<unsigned int>(translatedKeyText.size());
|
||||||
|
+ std::string translatedKeyText =
|
||||||
|
+ string_from_unterminated((const char*)(data.pData_ + keysize + 3 + languageTextSize + 1),
|
||||||
|
+ data.size_ - (keysize + 3 + languageTextSize + 1));
|
||||||
|
+ const unsigned int translatedKeyTextSize = static_cast<unsigned int>(translatedKeyText.size());
|
||||||
|
|
||||||
|
- if ( compressionFlag == 0x00 )
|
||||||
|
- {
|
||||||
|
- // then it's an uncompressed iTXt chunk
|
||||||
|
-#ifdef DEBUG
|
||||||
|
- std::cout << "Exiv2::PngChunk::parseTXTChunk: We found an uncompressed iTXt field\n";
|
||||||
|
-#endif
|
||||||
|
+ if ((compressionFlag == 0x00) || (compressionFlag == 0x01 && compressionMethod == 0x00)) {
|
||||||
|
+ enforce(Safe::add(static_cast<unsigned int>(keysize + 3 + languageTextSize + 1),
|
||||||
|
+ Safe::add(translatedKeyTextSize, 1u)) <= data.size_,
|
||||||
|
+ Exiv2::kerCorruptedMetadata);
|
||||||
|
|
||||||
|
- // the text comes after the translated keyword, but isn't null terminated
|
||||||
|
const byte* text = data.pData_ + keysize + 3 + languageTextSize + 1 + translatedKeyTextSize + 1;
|
||||||
|
- long textsize = data.size_ - (keysize + 3 + languageTextSize + 1 + translatedKeyTextSize + 1);
|
||||||
|
+ const long textsize = data.size_ - (keysize + 3 + languageTextSize + 1 + translatedKeyTextSize + 1);
|
||||||
|
|
||||||
|
- arr.alloc(textsize);
|
||||||
|
- arr = DataBuf(text, textsize);
|
||||||
|
- }
|
||||||
|
- else if ( compressionFlag == 0x01 && compressionMethod == 0x00 )
|
||||||
|
- {
|
||||||
|
- // then it's a zlib compressed iTXt chunk
|
||||||
|
+ if (compressionFlag == 0x00) {
|
||||||
|
+ // then it's an uncompressed iTXt chunk
|
||||||
|
#ifdef DEBUG
|
||||||
|
- std::cout << "Exiv2::PngChunk::parseTXTChunk: We found a zlib compressed iTXt field\n";
|
||||||
|
+ std::cout << "Exiv2::PngChunk::parseTXTChunk: We found an uncompressed iTXt field\n";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
- // the compressed text comes after the translated keyword, but isn't null terminated
|
||||||
|
- const byte* compressedText = data.pData_ + keysize + 3 + languageTextSize + 1 + translatedKeyTextSize + 1;
|
||||||
|
- long compressedTextSize = data.size_ - (keysize + 3 + languageTextSize + 1 + translatedKeyTextSize + 1);
|
||||||
|
-
|
||||||
|
- zlibUncompress(compressedText, compressedTextSize, arr);
|
||||||
|
- }
|
||||||
|
- else
|
||||||
|
- {
|
||||||
|
+ arr.alloc(textsize);
|
||||||
|
+ arr = DataBuf(text, textsize);
|
||||||
|
+ } else if (compressionFlag == 0x01 && compressionMethod == 0x00) {
|
||||||
|
+ // then it's a zlib compressed iTXt chunk
|
||||||
|
+#ifdef DEBUG
|
||||||
|
+ std::cout << "Exiv2::PngChunk::parseTXTChunk: We found a zlib compressed iTXt field\n";
|
||||||
|
+#endif
|
||||||
|
+ // the compressed text comes after the translated keyword, but isn't null terminated
|
||||||
|
+ zlibUncompress(text, textsize, arr);
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
// then it isn't zlib compressed and we are sunk
|
||||||
|
#ifdef DEBUG
|
||||||
|
std::cerr << "Exiv2::PngChunk::parseTXTChunk: Non-standard iTXt compression method.\n";
|
76
SOURCES/exiv2-CVE-2018-5772.patch
Normal file
76
SOURCES/exiv2-CVE-2018-5772.patch
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
diff --git a/src/cr2image.cpp b/src/cr2image.cpp
|
||||||
|
index 2907426..b6fa315 100644
|
||||||
|
--- a/src/cr2image.cpp
|
||||||
|
+++ b/src/cr2image.cpp
|
||||||
|
@@ -107,8 +107,6 @@ namespace Exiv2 {
|
||||||
|
throw Error(3, "CR2");
|
||||||
|
}
|
||||||
|
clearMetadata();
|
||||||
|
- std::ofstream devnull;
|
||||||
|
- printStructure(devnull, kpsRecursive, 0);
|
||||||
|
ByteOrder bo = Cr2Parser::decode(exifData_,
|
||||||
|
iptcData_,
|
||||||
|
xmpData_,
|
||||||
|
diff --git a/src/crwimage.cpp b/src/crwimage.cpp
|
||||||
|
index ca79aa7..11cd14c 100644
|
||||||
|
--- a/src/crwimage.cpp
|
||||||
|
+++ b/src/crwimage.cpp
|
||||||
|
@@ -131,15 +131,8 @@ namespace Exiv2 {
|
||||||
|
throw Error(33);
|
||||||
|
}
|
||||||
|
clearMetadata();
|
||||||
|
- // read all metadata into memory
|
||||||
|
- // we should put this into clearMetadata(), however it breaks the test suite!
|
||||||
|
- try {
|
||||||
|
- std::ofstream devnull;
|
||||||
|
- printStructure(devnull,kpsRecursive,0);
|
||||||
|
- } catch (Exiv2::Error& /* e */) {
|
||||||
|
- DataBuf file(io().size());
|
||||||
|
- io_->read(file.pData_,file.size_);
|
||||||
|
- }
|
||||||
|
+ DataBuf file( (long) io().size());
|
||||||
|
+ io_->read(file.pData_,file.size_);
|
||||||
|
|
||||||
|
CrwParser::decode(this, io_->mmap(), io_->size());
|
||||||
|
|
||||||
|
diff --git a/src/orfimage.cpp b/src/orfimage.cpp
|
||||||
|
index c516591..9a17a50 100644
|
||||||
|
--- a/src/orfimage.cpp
|
||||||
|
+++ b/src/orfimage.cpp
|
||||||
|
@@ -119,8 +119,6 @@ namespace Exiv2 {
|
||||||
|
throw Error(3, "ORF");
|
||||||
|
}
|
||||||
|
clearMetadata();
|
||||||
|
- std::ofstream devnull;
|
||||||
|
- printStructure(devnull, kpsRecursive, 0);
|
||||||
|
ByteOrder bo = OrfParser::decode(exifData_,
|
||||||
|
iptcData_,
|
||||||
|
xmpData_,
|
||||||
|
diff --git a/src/rw2image.cpp b/src/rw2image.cpp
|
||||||
|
index 95f3b28..764de6f 100644
|
||||||
|
--- a/src/rw2image.cpp
|
||||||
|
+++ b/src/rw2image.cpp
|
||||||
|
@@ -130,8 +130,6 @@ namespace Exiv2 {
|
||||||
|
throw Error(3, "RW2");
|
||||||
|
}
|
||||||
|
clearMetadata();
|
||||||
|
- std::ofstream devnull;
|
||||||
|
- printStructure(devnull, kpsRecursive, 0);
|
||||||
|
ByteOrder bo = Rw2Parser::decode(exifData_,
|
||||||
|
iptcData_,
|
||||||
|
xmpData_,
|
||||||
|
diff --git a/src/tiffimage.cpp b/src/tiffimage.cpp
|
||||||
|
index f20c69e..9e6eda4 100644
|
||||||
|
--- a/src/tiffimage.cpp
|
||||||
|
+++ b/src/tiffimage.cpp
|
||||||
|
@@ -185,10 +185,6 @@ namespace Exiv2 {
|
||||||
|
}
|
||||||
|
clearMetadata();
|
||||||
|
|
||||||
|
- // recursively print the structure to /dev/null to ensure all metadata is in memory
|
||||||
|
- // must be recursive to handle NEFs which stores the raw image in a subIFDs
|
||||||
|
- std::ofstream devnull;
|
||||||
|
- printStructure(devnull,kpsRecursive,0);
|
||||||
|
ByteOrder bo = TiffParser::decode(exifData_,
|
||||||
|
iptcData_,
|
||||||
|
xmpData_,
|
466
SOURCES/exiv2-CVE-2018-8976.patch
Normal file
466
SOURCES/exiv2-CVE-2018-8976.patch
Normal file
@ -0,0 +1,466 @@
|
|||||||
|
diff --git a/src/jpgimage.cpp b/src/jpgimage.cpp
|
||||||
|
index 9afcb58..ca83f14 100644
|
||||||
|
--- a/src/jpgimage.cpp
|
||||||
|
+++ b/src/jpgimage.cpp
|
||||||
|
@@ -34,6 +34,7 @@ EXIV2_RCSID("@(#) $Id$")
|
||||||
|
#include "image_int.hpp"
|
||||||
|
#include "error.hpp"
|
||||||
|
#include "futils.hpp"
|
||||||
|
+#include "enforce.hpp"
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
@@ -328,12 +329,14 @@ namespace Exiv2 {
|
||||||
|
int c = -1;
|
||||||
|
// Skips potential padding between markers
|
||||||
|
while ((c=io_->getb()) != 0xff) {
|
||||||
|
- if (c == EOF) return -1;
|
||||||
|
+ if (c == EOF)
|
||||||
|
+ return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Markers can start with any number of 0xff
|
||||||
|
while ((c=io_->getb()) == 0xff) {
|
||||||
|
- if (c == EOF) return -2;
|
||||||
|
+ if (c == EOF)
|
||||||
|
+ return -2;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
@@ -564,85 +567,88 @@ namespace Exiv2 {
|
||||||
|
out << Internal::stringFormat("%8ld | 0xff%02x %-5s", \
|
||||||
|
io_->tell()-2,marker,nm[marker].c_str())
|
||||||
|
|
||||||
|
- void JpegBase::printStructure(std::ostream& out, PrintStructureOption option,int depth)
|
||||||
|
+ void JpegBase::printStructure(std::ostream& out, PrintStructureOption option, int depth)
|
||||||
|
{
|
||||||
|
- if (io_->open() != 0) throw Error(9, io_->path(), strError());
|
||||||
|
+ if (io_->open() != 0)
|
||||||
|
+ throw Error(9, io_->path(), strError());
|
||||||
|
// Ensure that this is the correct image type
|
||||||
|
if (!isThisType(*io_, false)) {
|
||||||
|
- if (io_->error() || io_->eof()) throw Error(14);
|
||||||
|
+ if (io_->error() || io_->eof())
|
||||||
|
+ throw Error(14);
|
||||||
|
throw Error(15);
|
||||||
|
}
|
||||||
|
|
||||||
|
- bool bPrint = option==kpsBasic || option==kpsRecursive;
|
||||||
|
+ bool bPrint = option == kpsBasic || option == kpsRecursive;
|
||||||
|
Exiv2::Uint32Vector iptcDataSegs;
|
||||||
|
|
||||||
|
- if ( bPrint || option == kpsXMP || option == kpsIccProfile || option == kpsIptcErase ) {
|
||||||
|
+ if (bPrint || option == kpsXMP || option == kpsIccProfile || option == kpsIptcErase) {
|
||||||
|
|
||||||
|
// nmonic for markers
|
||||||
|
- std::string nm[256] ;
|
||||||
|
- nm[0xd8]="SOI" ;
|
||||||
|
- nm[0xd9]="EOI" ;
|
||||||
|
- nm[0xda]="SOS" ;
|
||||||
|
- nm[0xdb]="DQT" ;
|
||||||
|
- nm[0xdd]="DRI" ;
|
||||||
|
- nm[0xfe]="COM" ;
|
||||||
|
+ std::string nm[256];
|
||||||
|
+ nm[0xd8] = "SOI";
|
||||||
|
+ nm[0xd9] = "EOI";
|
||||||
|
+ nm[0xda] = "SOS";
|
||||||
|
+ nm[0xdb] = "DQT";
|
||||||
|
+ nm[0xdd] = "DRI";
|
||||||
|
+ nm[0xfe] = "COM";
|
||||||
|
|
||||||
|
// 0xe0 .. 0xef are APPn
|
||||||
|
// 0xc0 .. 0xcf are SOFn (except 4)
|
||||||
|
- nm[0xc4]="DHT" ;
|
||||||
|
- for ( int i = 0 ; i <= 15 ; i++ ) {
|
||||||
|
+ nm[0xc4] = "DHT";
|
||||||
|
+ for (int i = 0; i <= 15; i++) {
|
||||||
|
char MN[10];
|
||||||
|
- sprintf(MN,"APP%d",i);
|
||||||
|
- nm[0xe0+i] = MN;
|
||||||
|
- if ( i != 4 ) {
|
||||||
|
- sprintf(MN,"SOF%d",i);
|
||||||
|
- nm[0xc0+i] = MN;
|
||||||
|
+ sprintf(MN, "APP%d", i);
|
||||||
|
+ nm[0xe0 + i] = MN;
|
||||||
|
+ if (i != 4) {
|
||||||
|
+ sprintf(MN, "SOF%d", i);
|
||||||
|
+ nm[0xc0 + i] = MN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// which markers have a length field?
|
||||||
|
bool mHasLength[256];
|
||||||
|
- for ( int i = 0 ; i < 256 ; i ++ )
|
||||||
|
- mHasLength[i]
|
||||||
|
- = ( i >= sof0_ && i <= sof15_)
|
||||||
|
- || ( i >= app0_ && i <= (app0_ | 0x0F))
|
||||||
|
- || ( i == dht_ || i == dqt_ || i == dri_ || i == com_ || i == sos_ )
|
||||||
|
- ;
|
||||||
|
+ for (int i = 0; i < 256; i++)
|
||||||
|
+ mHasLength[i] = (i >= sof0_ && i <= sof15_) || (i >= app0_ && i <= (app0_ | 0x0F)) ||
|
||||||
|
+ (i == dht_ || i == dqt_ || i == dri_ || i == com_ || i == sos_);
|
||||||
|
|
||||||
|
// Container for the signature
|
||||||
|
- bool bExtXMP = false;
|
||||||
|
- long bufRead = 0;
|
||||||
|
- const long bufMinSize = 36;
|
||||||
|
- DataBuf buf(bufMinSize);
|
||||||
|
+ bool bExtXMP = false;
|
||||||
|
+ long bufRead = 0;
|
||||||
|
+ const long bufMinSize = 36;
|
||||||
|
+ DataBuf buf(bufMinSize);
|
||||||
|
|
||||||
|
// Read section marker
|
||||||
|
int marker = advanceToMarker();
|
||||||
|
- if (marker < 0) throw Error(15);
|
||||||
|
+ if (marker < 0)
|
||||||
|
+ throw Error(15);
|
||||||
|
|
||||||
|
- bool done = false;
|
||||||
|
- bool first= true;
|
||||||
|
+ bool done = false;
|
||||||
|
+ bool first = true;
|
||||||
|
while (!done) {
|
||||||
|
// print marker bytes
|
||||||
|
- if ( first && bPrint ) {
|
||||||
|
+ if (first && bPrint) {
|
||||||
|
out << "STRUCTURE OF JPEG FILE: " << io_->path() << std::endl;
|
||||||
|
- out << " address | marker | length | data" << std::endl ;
|
||||||
|
+ out << " address | marker | length | data" << std::endl;
|
||||||
|
REPORT_MARKER;
|
||||||
|
}
|
||||||
|
- first = false;
|
||||||
|
+ first = false;
|
||||||
|
bool bLF = bPrint;
|
||||||
|
|
||||||
|
// Read size and signature
|
||||||
|
std::memset(buf.pData_, 0x0, buf.size_);
|
||||||
|
bufRead = io_->read(buf.pData_, bufMinSize);
|
||||||
|
- if (io_->error()) throw Error(14);
|
||||||
|
- if (bufRead < 2) throw Error(15);
|
||||||
|
- uint16_t size = mHasLength[marker] ? getUShort(buf.pData_, bigEndian) : 0 ;
|
||||||
|
- if ( bPrint && mHasLength[marker] ) out << Internal::stringFormat(" | %7d ", size);
|
||||||
|
+ if (io_->error())
|
||||||
|
+ throw Error(14);
|
||||||
|
+ if (bufRead < 2)
|
||||||
|
+ throw Error(15);
|
||||||
|
+ uint16_t size = mHasLength[marker] ? getUShort(buf.pData_, bigEndian) : 0;
|
||||||
|
+ if (bPrint && mHasLength[marker])
|
||||||
|
+ out << Internal::stringFormat(" | %7d ", size);
|
||||||
|
|
||||||
|
// print signature for APPn
|
||||||
|
if (marker >= app0_ && marker <= (app0_ | 0x0F)) {
|
||||||
|
// http://www.adobe.com/content/dam/Adobe/en/devnet/xmp/pdfs/XMPSpecificationPart3.pdf p75
|
||||||
|
- const char* signature = (const char*) buf.pData_+2;
|
||||||
|
+ const char* signature = (const char*)buf.pData_ + 2;
|
||||||
|
|
||||||
|
// 728 rmills@rmillsmbp:~/gnu/exiv2/ttt $ exiv2 -pS test/data/exiv2-bug922.jpg
|
||||||
|
// STRUCTURE OF JPEG FILE: test/data/exiv2-bug922.jpg
|
||||||
|
@@ -651,13 +657,13 @@ namespace Exiv2 {
|
||||||
|
// 2 | 0xe1 APP1 | 911 | Exif..MM.*.......%.........#....
|
||||||
|
// 915 | 0xe1 APP1 | 870 | http://ns.adobe.com/xap/1.0/.<x:
|
||||||
|
// 1787 | 0xe1 APP1 | 65460 | http://ns.adobe.com/xmp/extensio
|
||||||
|
- if ( option == kpsXMP && std::string(signature).find("http://ns.adobe.com/x")== 0 ) {
|
||||||
|
+ if (option == kpsXMP && std::string(signature).find("http://ns.adobe.com/x") == 0) {
|
||||||
|
// extract XMP
|
||||||
|
- if ( size > 0 ) {
|
||||||
|
- io_->seek(-bufRead , BasicIo::cur);
|
||||||
|
- byte* xmp = new byte[size+1];
|
||||||
|
- io_->read(xmp,size);
|
||||||
|
- int start = 0 ;
|
||||||
|
+ if (size > 0) {
|
||||||
|
+ io_->seek(-bufRead, BasicIo::cur);
|
||||||
|
+ byte* xmp = new byte[size + 1];
|
||||||
|
+ io_->read(xmp, size);
|
||||||
|
+ int start = 0;
|
||||||
|
|
||||||
|
// http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/xmp/pdfs/XMPSpecificationPart3.pdf
|
||||||
|
// if we find HasExtendedXMP, set the flag and ignore this block
|
||||||
|
@@ -666,79 +672,80 @@ namespace Exiv2 {
|
||||||
|
// we could implement out of sequence with a dictionary of sequence/offset
|
||||||
|
// and dumping the XMP in a post read operation similar to kpsIptcErase
|
||||||
|
// for the moment, dumping 'on the fly' is working fine
|
||||||
|
- if ( ! bExtXMP ) {
|
||||||
|
- while (xmp[start]) start++;
|
||||||
|
+ if (!bExtXMP) {
|
||||||
|
+ while (xmp[start])
|
||||||
|
+ start++;
|
||||||
|
start++;
|
||||||
|
- if ( ::strstr((char*)xmp+start,"HasExtendedXMP") ) {
|
||||||
|
- start = size ; // ignore this packet, we'll get on the next time around
|
||||||
|
+ if (::strstr((char*)xmp + start, "HasExtendedXMP")) {
|
||||||
|
+ start = size; // ignore this packet, we'll get on the next time around
|
||||||
|
bExtXMP = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
- start = 2+35+32+4+4; // Adobe Spec, p19
|
||||||
|
+ start = 2 + 35 + 32 + 4 + 4; // Adobe Spec, p19
|
||||||
|
}
|
||||||
|
|
||||||
|
- out.write((const char*)(xmp+start),size-start);
|
||||||
|
- delete [] xmp;
|
||||||
|
+ out.write((const char*)(xmp + start), size - start);
|
||||||
|
+ delete[] xmp;
|
||||||
|
bufRead = size;
|
||||||
|
done = !bExtXMP;
|
||||||
|
}
|
||||||
|
- } else if ( option == kpsIccProfile && std::strcmp(signature,iccId_) == 0 ) {
|
||||||
|
+ } else if (option == kpsIccProfile && std::strcmp(signature, iccId_) == 0) {
|
||||||
|
// extract ICCProfile
|
||||||
|
- if ( size > 0 ) {
|
||||||
|
- io_->seek(-bufRead, BasicIo::cur); // back to buffer (after marker)
|
||||||
|
- io_->seek( 14+2, BasicIo::cur); // step over header
|
||||||
|
- DataBuf icc(size-(14+2));
|
||||||
|
- io_->read( icc.pData_,icc.size_);
|
||||||
|
- out.write((const char*)icc.pData_,icc.size_);
|
||||||
|
+ if (size > 0) {
|
||||||
|
+ io_->seek(-bufRead, BasicIo::cur); // back to buffer (after marker)
|
||||||
|
+ io_->seek(14 + 2, BasicIo::cur); // step over header
|
||||||
|
+ DataBuf icc(size - (14 + 2));
|
||||||
|
+ io_->read(icc.pData_, icc.size_);
|
||||||
|
+ out.write((const char*)icc.pData_, icc.size_);
|
||||||
|
#ifdef DEBUG
|
||||||
|
std::cout << "iccProfile size = " << icc.size_ << std::endl;
|
||||||
|
#endif
|
||||||
|
bufRead = size;
|
||||||
|
}
|
||||||
|
- } else if ( option == kpsIptcErase && std::strcmp(signature,"Photoshop 3.0") == 0 ) {
|
||||||
|
+ } else if (option == kpsIptcErase && std::strcmp(signature, "Photoshop 3.0") == 0) {
|
||||||
|
// delete IPTC data segment from JPEG
|
||||||
|
- if ( size > 0 ) {
|
||||||
|
- io_->seek(-bufRead , BasicIo::cur);
|
||||||
|
+ if (size > 0) {
|
||||||
|
+ io_->seek(-bufRead, BasicIo::cur);
|
||||||
|
iptcDataSegs.push_back(io_->tell());
|
||||||
|
iptcDataSegs.push_back(size);
|
||||||
|
}
|
||||||
|
- } else if ( bPrint ) {
|
||||||
|
- out << "| " << Internal::binaryToString(buf,size>32?32:size,size>0?2:0);
|
||||||
|
- if ( std::strcmp(signature,iccId_) == 0 ) {
|
||||||
|
- int chunk = (int) signature[12];
|
||||||
|
- int chunks = (int) signature[13];
|
||||||
|
- out << Internal::stringFormat(" chunk %d/%d",chunk,chunks);
|
||||||
|
+ } else if (bPrint) {
|
||||||
|
+ out << "| " << Internal::binaryToString(buf, size > 32 ? 32 : size, size > 0 ? 2 : 0);
|
||||||
|
+ if (std::strcmp(signature, iccId_) == 0) {
|
||||||
|
+ int chunk = (int)signature[12];
|
||||||
|
+ int chunks = (int)signature[13];
|
||||||
|
+ out << Internal::stringFormat(" chunk %d/%d", chunk, chunks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// for MPF: http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/MPF.html
|
||||||
|
// for FLIR: http://owl.phy.queensu.ca/~phil/exiftool/TagNames/FLIR.html
|
||||||
|
- bool bFlir = option == kpsRecursive && marker == (app0_+1) && std::strcmp(signature,"FLIR")==0;
|
||||||
|
- bool bExif = option == kpsRecursive && marker == (app0_+1) && std::strcmp(signature,"Exif")==0;
|
||||||
|
- bool bMPF = option == kpsRecursive && marker == (app0_+2) && std::strcmp(signature,"MPF")==0;
|
||||||
|
- bool bPS = option == kpsRecursive && std::strcmp(signature,"Photoshop 3.0")==0;
|
||||||
|
- if( bFlir || bExif || bMPF || bPS ) {
|
||||||
|
+ bool bFlir = option == kpsRecursive && marker == (app0_ + 1) && std::strcmp(signature, "FLIR") == 0;
|
||||||
|
+ bool bExif = option == kpsRecursive && marker == (app0_ + 1) && std::strcmp(signature, "Exif") == 0;
|
||||||
|
+ bool bMPF = option == kpsRecursive && marker == (app0_ + 2) && std::strcmp(signature, "MPF") == 0;
|
||||||
|
+ bool bPS = option == kpsRecursive && std::strcmp(signature, "Photoshop 3.0") == 0;
|
||||||
|
+ if (bFlir || bExif || bMPF || bPS) {
|
||||||
|
// extract Exif data block which is tiff formatted
|
||||||
|
- if ( size > 0 ) {
|
||||||
|
+ if (size > 0) {
|
||||||
|
out << std::endl;
|
||||||
|
|
||||||
|
// allocate storage and current file position
|
||||||
|
- byte* exif = new byte[size];
|
||||||
|
- uint32_t restore = io_->tell();
|
||||||
|
+ byte* exif = new byte[size];
|
||||||
|
+ uint32_t restore = io_->tell();
|
||||||
|
|
||||||
|
// copy the data to memory
|
||||||
|
- io_->seek(-bufRead , BasicIo::cur);
|
||||||
|
- io_->read(exif,size);
|
||||||
|
- uint32_t start = std::strcmp(signature,"Exif")==0 ? 8 : 6;
|
||||||
|
- uint32_t max = (uint32_t) size -1;
|
||||||
|
+ io_->seek(-bufRead, BasicIo::cur);
|
||||||
|
+ io_->read(exif, size);
|
||||||
|
+ uint32_t start = std::strcmp(signature, "Exif") == 0 ? 8 : 6;
|
||||||
|
+ uint32_t max = (uint32_t)size - 1;
|
||||||
|
|
||||||
|
// is this an fff block?
|
||||||
|
- if ( bFlir ) {
|
||||||
|
- start = 0 ;
|
||||||
|
+ if (bFlir) {
|
||||||
|
+ start = 0;
|
||||||
|
bFlir = false;
|
||||||
|
- while ( start < max ) {
|
||||||
|
- if ( std::strcmp((const char*)(exif+start),"FFF")==0 ) {
|
||||||
|
- bFlir = true ;
|
||||||
|
+ while (start < max) {
|
||||||
|
+ if (std::strcmp((const char*)(exif + start), "FFF") == 0) {
|
||||||
|
+ bFlir = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
start++;
|
||||||
|
@@ -747,78 +754,90 @@ namespace Exiv2 {
|
||||||
|
|
||||||
|
// there is a header in FLIR, followed by a tiff block
|
||||||
|
// Hunt down the tiff using brute force
|
||||||
|
- if ( bFlir ) {
|
||||||
|
+ if (bFlir) {
|
||||||
|
// FLIRFILEHEAD* pFFF = (FLIRFILEHEAD*) (exif+start) ;
|
||||||
|
- while ( start < max ) {
|
||||||
|
- if ( exif[start] == 'I' && exif[start+1] == 'I' ) break;
|
||||||
|
- if ( exif[start] == 'M' && exif[start+1] == 'M' ) break;
|
||||||
|
+ while (start < max) {
|
||||||
|
+ if (exif[start] == 'I' && exif[start + 1] == 'I')
|
||||||
|
+ break;
|
||||||
|
+ if (exif[start] == 'M' && exif[start + 1] == 'M')
|
||||||
|
+ break;
|
||||||
|
start++;
|
||||||
|
}
|
||||||
|
- if ( start < max ) std::cout << " FFF start = " << start << std::endl ;
|
||||||
|
+ if ( start < max )
|
||||||
|
+ std::cout << " FFF start = " << start << std::endl;
|
||||||
|
// << " index = " << pFFF->dwIndexOff << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if ( bPS ) {
|
||||||
|
- IptcData::printStructure(out,exif,size,depth);
|
||||||
|
+ if (bPS) {
|
||||||
|
+ IptcData::printStructure(out, exif, size, depth);
|
||||||
|
} else {
|
||||||
|
// create a copy on write memio object with the data, then print the structure
|
||||||
|
- BasicIo::AutoPtr p = BasicIo::AutoPtr(new MemIo(exif+start,size-start));
|
||||||
|
- if ( start < max ) printTiffStructure(*p,out,option,depth);
|
||||||
|
+ BasicIo::AutoPtr p = BasicIo::AutoPtr(new MemIo(exif + start, size - start));
|
||||||
|
+ if (start < max)
|
||||||
|
+ printTiffStructure(*p, out, option, depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
// restore and clean up
|
||||||
|
- io_->seek(restore,Exiv2::BasicIo::beg);
|
||||||
|
- delete [] exif;
|
||||||
|
- bLF = false;
|
||||||
|
+ io_->seek(restore, Exiv2::BasicIo::beg);
|
||||||
|
+ delete[] exif;
|
||||||
|
+ bLF = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// print COM marker
|
||||||
|
- if ( bPrint && marker == com_ ) {
|
||||||
|
- int n = (size-2)>32?32:size-2; // size includes 2 for the two bytes for size!
|
||||||
|
- out << "| " << Internal::binaryToString(buf,n,2); // start after the two bytes
|
||||||
|
+ if (bPrint && marker == com_) {
|
||||||
|
+ int n = (size - 2) > 32 ? 32 : size - 2; // size includes 2 for the two bytes for size!
|
||||||
|
+ out << "| " << Internal::binaryToString(buf, n, 2); // start after the two bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip the segment if the size is known
|
||||||
|
- if (io_->seek(size - bufRead, BasicIo::cur)) throw Error(14);
|
||||||
|
+ if (io_->seek(size - bufRead, BasicIo::cur))
|
||||||
|
+ throw Error(14);
|
||||||
|
|
||||||
|
- if ( bLF ) out << std::endl;
|
||||||
|
+ if (bLF)
|
||||||
|
+ out << std::endl;
|
||||||
|
|
||||||
|
if (marker != sos_) {
|
||||||
|
// Read the beginning of the next segment
|
||||||
|
marker = advanceToMarker();
|
||||||
|
+ enforce(marker>=0, kerNoImageInInputData);
|
||||||
|
REPORT_MARKER;
|
||||||
|
}
|
||||||
|
done |= marker == eoi_ || marker == sos_;
|
||||||
|
- if ( done && bPrint ) out << std::endl;
|
||||||
|
+ if (done && bPrint)
|
||||||
|
+ out << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- if ( option == kpsIptcErase && iptcDataSegs.size() ) {
|
||||||
|
+ if (option == kpsIptcErase && iptcDataSegs.size()) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
std::cout << "iptc data blocks: " << iptcDataSegs.size() << std::endl;
|
||||||
|
- uint32_t toggle = 0 ;
|
||||||
|
- for ( Uint32Vector_i i = iptcDataSegs.begin(); i != iptcDataSegs.end() ; i++ ) {
|
||||||
|
- std::cout << *i ;
|
||||||
|
- if ( toggle++ % 2 ) std::cout << std::endl; else std::cout << ' ' ;
|
||||||
|
+ uint32_t toggle = 0;
|
||||||
|
+ for (Uint32Vector_i i = iptcDataSegs.begin(); i != iptcDataSegs.end(); i++) {
|
||||||
|
+ std::cout << *i;
|
||||||
|
+ if (toggle++ % 2)
|
||||||
|
+ std::cout << std::endl;
|
||||||
|
+ else
|
||||||
|
+ std::cout << ' ';
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
- uint32_t count = (uint32_t) iptcDataSegs.size();
|
||||||
|
+ uint32_t count = (uint32_t)iptcDataSegs.size();
|
||||||
|
|
||||||
|
// figure out which blocks to copy
|
||||||
|
- uint64_t* pos = new uint64_t[count+2];
|
||||||
|
- pos[0] = 0 ;
|
||||||
|
+ uint64_t* pos = new uint64_t[count + 2];
|
||||||
|
+ pos[0] = 0;
|
||||||
|
// copy the data that is not iptc
|
||||||
|
Uint32Vector_i it = iptcDataSegs.begin();
|
||||||
|
- for ( uint64_t i = 0 ; i < count ; i++ ) {
|
||||||
|
- bool bOdd = (i%2)!=0;
|
||||||
|
- bool bEven = !bOdd;
|
||||||
|
- pos[i+1] = bEven ? *it : pos[i] + *it;
|
||||||
|
+ for (uint64_t i = 0; i < count; i++) {
|
||||||
|
+ bool bOdd = (i % 2) != 0;
|
||||||
|
+ bool bEven = !bOdd;
|
||||||
|
+ pos[i + 1] = bEven ? *it : pos[i] + *it;
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
- pos[count+1] = io_->size() - pos[count];
|
||||||
|
+ pos[count + 1] = io_->size() - pos[count];
|
||||||
|
#ifdef DEBUG
|
||||||
|
- for ( uint64_t i = 0 ; i < count+2 ; i++ ) std::cout << pos[i] << " " ;
|
||||||
|
+ for (uint64_t i = 0; i < count + 2; i++)
|
||||||
|
+ std::cout << pos[i] << " ";
|
||||||
|
std::cout << std::endl;
|
||||||
|
#endif
|
||||||
|
// $ dd bs=1 skip=$((0)) count=$((13164)) if=ETH0138028.jpg of=E1.jpg
|
||||||
|
@@ -829,29 +848,30 @@ namespace Exiv2 {
|
||||||
|
// binary copy io_ to a temporary file
|
||||||
|
BasicIo::AutoPtr tempIo(new MemIo);
|
||||||
|
|
||||||
|
- assert (tempIo.get() != 0);
|
||||||
|
- for ( uint64_t i = 0 ; i < (count/2)+1 ; i++ ) {
|
||||||
|
- uint64_t start = pos[2*i]+2 ; // step JPG 2 byte marker
|
||||||
|
- if ( start == 2 ) start = 0 ; // read the file 2 byte SOI
|
||||||
|
- long length = (long) (pos[2*i+1] - start) ;
|
||||||
|
- if ( length ) {
|
||||||
|
+ assert(tempIo.get() != 0);
|
||||||
|
+ for (uint64_t i = 0; i < (count / 2) + 1; i++) {
|
||||||
|
+ uint64_t start = pos[2 * i] + 2; // step JPG 2 byte marker
|
||||||
|
+ if (start == 2)
|
||||||
|
+ start = 0; // read the file 2 byte SOI
|
||||||
|
+ long length = (long)(pos[2 * i + 1] - start);
|
||||||
|
+ if (length) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
- std::cout << start <<":"<< length << std::endl;
|
||||||
|
+ std::cout << start << ":" << length << std::endl;
|
||||||
|
#endif
|
||||||
|
- io_->seek(start,BasicIo::beg);
|
||||||
|
+ io_->seek(start, BasicIo::beg);
|
||||||
|
DataBuf buf(length);
|
||||||
|
- io_->read(buf.pData_,buf.size_);
|
||||||
|
- tempIo->write(buf.pData_,buf.size_);
|
||||||
|
+ io_->read(buf.pData_, buf.size_);
|
||||||
|
+ tempIo->write(buf.pData_, buf.size_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- delete [] pos;
|
||||||
|
+ delete[] pos;
|
||||||
|
|
||||||
|
io_->seek(0, BasicIo::beg);
|
||||||
|
- io_->transfer(*tempIo); // may throw
|
||||||
|
+ io_->transfer(*tempIo); // may throw
|
||||||
|
io_->seek(0, BasicIo::beg);
|
||||||
|
readMetadata();
|
||||||
|
}
|
||||||
|
- } // JpegBase::printStructure
|
||||||
|
+ } // JpegBase::printStructure
|
||||||
|
|
||||||
|
void JpegBase::writeMetadata()
|
||||||
|
{
|
21
SOURCES/exiv2-CVE-2018-8977.patch
Normal file
21
SOURCES/exiv2-CVE-2018-8977.patch
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
diff --git a/src/canonmn.cpp b/src/canonmn.cpp
|
||||||
|
index 450c7d9..f768c05 100644
|
||||||
|
--- a/src/canonmn.cpp
|
||||||
|
+++ b/src/canonmn.cpp
|
||||||
|
@@ -1774,9 +1774,13 @@ namespace Exiv2 {
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// 1140
|
||||||
|
- if( metadata->findKey(ExifKey("Exif.Image.Model" ))->value().toString() == "Canon EOS 30D"
|
||||||
|
- && metadata->findKey(ExifKey("Exif.CanonCs.Lens" ))->value().toString() == "24 24 1"
|
||||||
|
- && metadata->findKey(ExifKey("Exif.CanonCs.MaxAperture"))->value().toString() == "95" // F2.8
|
||||||
|
+ const ExifData::const_iterator itModel = metadata->findKey(ExifKey("Exif.Image.Model"));
|
||||||
|
+ const ExifData::const_iterator itLens = metadata->findKey(ExifKey("Exif.CanonCs.Lens"));
|
||||||
|
+ const ExifData::const_iterator itApert = metadata->findKey(ExifKey("Exif.CanonCs.MaxAperture"));
|
||||||
|
+
|
||||||
|
+ if( itModel != metadata->end() && itModel->value().toString() == "Canon EOS 30D"
|
||||||
|
+ && itLens != metadata->end() && itLens->value().toString() == "24 24 1"
|
||||||
|
+ && itApert != metadata->end() && itApert->value().toString() == "95" // F2.8
|
||||||
|
){
|
||||||
|
return os << "Canon EF-S 24mm f/2.8 STM" ;
|
||||||
|
}
|
176
SOURCES/exiv2-additional-security-fixes.patch
Normal file
176
SOURCES/exiv2-additional-security-fixes.patch
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
diff --git a/src/actions.cpp b/src/actions.cpp
|
||||||
|
index 0ebe850..3cd398e 100644
|
||||||
|
--- a/src/actions.cpp
|
||||||
|
+++ b/src/actions.cpp
|
||||||
|
@@ -59,6 +59,7 @@ EXIV2_RCSID("@(#) $Id$")
|
||||||
|
#include <ctime>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cassert>
|
||||||
|
+#include <stdexcept>
|
||||||
|
#include <sys/types.h> // for stat()
|
||||||
|
#include <sys/stat.h> // for stat()
|
||||||
|
#ifdef EXV_HAVE_UNISTD_H
|
||||||
|
@@ -236,33 +237,43 @@ namespace Action {
|
||||||
|
}
|
||||||
|
|
||||||
|
int Print::run(const std::string& path)
|
||||||
|
- try {
|
||||||
|
- path_ = path;
|
||||||
|
- int rc = 0;
|
||||||
|
- Exiv2::PrintStructureOption option = Exiv2::kpsNone ;
|
||||||
|
- switch (Params::instance().printMode_) {
|
||||||
|
- case Params::pmSummary: rc = printSummary(); break;
|
||||||
|
- case Params::pmList: rc = printList(); break;
|
||||||
|
- case Params::pmComment: rc = printComment(); break;
|
||||||
|
- case Params::pmPreview: rc = printPreviewList(); break;
|
||||||
|
- case Params::pmStructure: rc = printStructure(std::cout,Exiv2::kpsBasic) ; break;
|
||||||
|
- case Params::pmRecursive: rc = printStructure(std::cout,Exiv2::kpsRecursive) ; break;
|
||||||
|
-
|
||||||
|
- case Params::pmXMP:
|
||||||
|
- option = option == Exiv2::kpsNone ? Exiv2::kpsXMP : option; // drop
|
||||||
|
- case Params::pmIccProfile:{
|
||||||
|
- option = option == Exiv2::kpsNone ? Exiv2::kpsIccProfile : option;
|
||||||
|
- _setmode(_fileno(stdout),O_BINARY);
|
||||||
|
- rc = printStructure(std::cout,option);
|
||||||
|
- } break;
|
||||||
|
+ {
|
||||||
|
+ try {
|
||||||
|
+ path_ = path;
|
||||||
|
+ int rc = 0;
|
||||||
|
+ Exiv2::PrintStructureOption option = Exiv2::kpsNone ;
|
||||||
|
+ switch (Params::instance().printMode_) {
|
||||||
|
+ case Params::pmSummary: rc = printSummary(); break;
|
||||||
|
+ case Params::pmList: rc = printList(); break;
|
||||||
|
+ case Params::pmComment: rc = printComment(); break;
|
||||||
|
+ case Params::pmPreview: rc = printPreviewList(); break;
|
||||||
|
+ case Params::pmStructure: rc = printStructure(std::cout,Exiv2::kpsBasic) ; break;
|
||||||
|
+ case Params::pmRecursive: rc = printStructure(std::cout,Exiv2::kpsRecursive) ; break;
|
||||||
|
+
|
||||||
|
+ case Params::pmXMP:
|
||||||
|
+ if (option == Exiv2::kpsNone)
|
||||||
|
+ option = Exiv2::kpsXMP;
|
||||||
|
+ // drop
|
||||||
|
+ case Params::pmIccProfile:
|
||||||
|
+ if (option == Exiv2::kpsNone)
|
||||||
|
+ option = Exiv2::kpsIccProfile;
|
||||||
|
+ _setmode(_fileno(stdout),O_BINARY);
|
||||||
|
+ rc = printStructure(std::cout,option);
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ return rc;
|
||||||
|
}
|
||||||
|
- return rc;
|
||||||
|
- }
|
||||||
|
- catch(const Exiv2::AnyError& e) {
|
||||||
|
- std::cerr << "Exiv2 exception in print action for file "
|
||||||
|
- << path << ":\n" << e << "\n";
|
||||||
|
- return 1;
|
||||||
|
- } // Print::run
|
||||||
|
+ catch(const Exiv2::AnyError& e) {
|
||||||
|
+ std::cerr << "Exiv2 exception in print action for file "
|
||||||
|
+ << path << ":\n" << e << "\n";
|
||||||
|
+ return 1;
|
||||||
|
+ }
|
||||||
|
+ catch(const std::overflow_error& e) {
|
||||||
|
+ std::cerr << "std::overflow_error exception in print action for file "
|
||||||
|
+ << path << ":\n" << e.what() << "\n";
|
||||||
|
+ return 1;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
|
||||||
|
int Print::printStructure(std::ostream& out, Exiv2::PrintStructureOption option)
|
||||||
|
{
|
||||||
|
diff --git a/src/error.cpp b/src/error.cpp
|
||||||
|
index e90a9c0..5d63957 100644
|
||||||
|
--- a/src/error.cpp
|
||||||
|
+++ b/src/error.cpp
|
||||||
|
@@ -109,6 +109,8 @@ namespace {
|
||||||
|
{ 55, N_("tiff directory length is too large") },
|
||||||
|
{ 56, N_("invalid type value detected in Image::printIFDStructure") },
|
||||||
|
{ 57, N_("invalid memory allocation request") },
|
||||||
|
+ { 58, N_("corrupted image metadata") },
|
||||||
|
+ { 59, N_("Arithmetic operation overflow") },
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
diff --git a/src/nikonmn.cpp b/src/nikonmn.cpp
|
||||||
|
index 571ab80..34bf601 100644
|
||||||
|
--- a/src/nikonmn.cpp
|
||||||
|
+++ b/src/nikonmn.cpp
|
||||||
|
@@ -299,6 +299,8 @@ namespace Exiv2 {
|
||||||
|
const Value& value,
|
||||||
|
const ExifData* exifData)
|
||||||
|
{
|
||||||
|
+ if ( ! exifData ) return os << "undefined" ;
|
||||||
|
+
|
||||||
|
if ( value.count() >= 9 ) {
|
||||||
|
ByteOrder bo = getKeyString("Exif.MakerNote.ByteOrder",exifData) == "MM" ? bigEndian : littleEndian;
|
||||||
|
byte p[4];
|
||||||
|
diff --git a/src/pentaxmn.cpp b/src/pentaxmn.cpp
|
||||||
|
index 4fc38be..b22cb43 100644
|
||||||
|
--- a/src/pentaxmn.cpp
|
||||||
|
+++ b/src/pentaxmn.cpp
|
||||||
|
@@ -1167,6 +1167,8 @@ namespace Exiv2 {
|
||||||
|
|
||||||
|
std::ostream& PentaxMakerNote::printShutterCount(std::ostream& os, const Value& value, const ExifData* metadata)
|
||||||
|
{
|
||||||
|
+ if ( ! metadata ) return os << "undefined" ;
|
||||||
|
+
|
||||||
|
ExifData::const_iterator dateIt = metadata->findKey(
|
||||||
|
ExifKey("Exif.PentaxDng.Date"));
|
||||||
|
if (dateIt == metadata->end()) {
|
||||||
|
diff --git a/src/pngchunk.cpp b/src/pngchunk.cpp
|
||||||
|
index da4ccd0..4dcca4d 100644
|
||||||
|
--- a/src/pngchunk.cpp
|
||||||
|
+++ b/src/pngchunk.cpp
|
||||||
|
@@ -68,6 +68,8 @@ namespace Exiv2 {
|
||||||
|
int* outWidth,
|
||||||
|
int* outHeight)
|
||||||
|
{
|
||||||
|
+ assert(data.size_ >= 8);
|
||||||
|
+
|
||||||
|
// Extract image width and height from IHDR chunk.
|
||||||
|
|
||||||
|
*outWidth = getLong((const byte*)data.pData_, bigEndian);
|
||||||
|
diff --git a/src/pngimage.cpp b/src/pngimage.cpp
|
||||||
|
index 11b4198..ed7399a 100644
|
||||||
|
--- a/src/pngimage.cpp
|
||||||
|
+++ b/src/pngimage.cpp
|
||||||
|
@@ -441,7 +441,9 @@ namespace Exiv2 {
|
||||||
|
#ifdef DEBUG
|
||||||
|
std::cout << "Exiv2::PngImage::readMetadata: Found IHDR chunk (length: " << dataOffset << ")\n";
|
||||||
|
#endif
|
||||||
|
- PngChunk::decodeIHDRChunk(cdataBuf, &pixelWidth_, &pixelHeight_);
|
||||||
|
+ if (cdataBuf.size_ >= 8) {
|
||||||
|
+ PngChunk::decodeIHDRChunk(cdataBuf, &pixelWidth_, &pixelHeight_);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
else if (!memcmp(cheaderBuf.pData_ + 4, "tEXt", 4))
|
||||||
|
{
|
||||||
|
diff --git a/src/tiffvisitor.cpp b/src/tiffvisitor.cpp
|
||||||
|
index 74f8d07..fad39b6 100644
|
||||||
|
--- a/src/tiffvisitor.cpp
|
||||||
|
+++ b/src/tiffvisitor.cpp
|
||||||
|
@@ -1493,6 +1493,11 @@ namespace Exiv2 {
|
||||||
|
}
|
||||||
|
p += 4;
|
||||||
|
uint32_t isize= 0; // size of Exif.Sony1.PreviewImage
|
||||||
|
+
|
||||||
|
+ if (count > std::numeric_limits<uint32_t>::max() / typeSize) {
|
||||||
|
+ throw Error(59);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
uint32_t size = typeSize * count;
|
||||||
|
uint32_t offset = getLong(p, byteOrder());
|
||||||
|
byte* pData = p;
|
||||||
|
@@ -1536,7 +1541,9 @@ namespace Exiv2 {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Value::AutoPtr v = Value::create(typeId);
|
||||||
|
- assert(v.get());
|
||||||
|
+ if (!v.get()) {
|
||||||
|
+ throw Error(58);
|
||||||
|
+ }
|
||||||
|
if ( !isize ) {
|
||||||
|
v->read(pData, size, byteOrder());
|
||||||
|
} else {
|
25
SOURCES/exiv2-do-not-build-documentation.patch
Normal file
25
SOURCES/exiv2-do-not-build-documentation.patch
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||||
|
index 7034bb6..f091078 100644
|
||||||
|
--- a/CMakeLists.txt
|
||||||
|
+++ b/CMakeLists.txt
|
||||||
|
@@ -217,13 +217,13 @@ ADD_CUSTOM_TARGET(geotag-test COMMAND env EXIV2_BINDIR="${CMAKE_BINARY_DIR}"/bin
|
||||||
|
# effectively does a make doc on the root directory
|
||||||
|
# has to run 'make config' and './configure'
|
||||||
|
# and copy bin/taglist to <exiv2dir>/bin/taglist for use by 'make doc'
|
||||||
|
-IF( MINGW OR UNIX OR APPLE)
|
||||||
|
- ADD_CUSTOM_TARGET(doc
|
||||||
|
- WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/doc"
|
||||||
|
- COMMAND chmod +x ./cmake_doc.sh
|
||||||
|
- COMMAND ./cmake_doc.sh "${CMAKE_BINARY_DIR}"
|
||||||
|
- )
|
||||||
|
-ENDIF()
|
||||||
|
+# IF( MINGW OR UNIX OR APPLE)
|
||||||
|
+# ADD_CUSTOM_TARGET(doc
|
||||||
|
+# WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/doc"
|
||||||
|
+# COMMAND chmod +x ./cmake_doc.sh
|
||||||
|
+# COMMAND ./cmake_doc.sh "${CMAKE_BINARY_DIR}"
|
||||||
|
+# )
|
||||||
|
+# ENDIF()
|
||||||
|
|
||||||
|
# That's all Folks!
|
||||||
|
##
|
43
SOURCES/exiv2-simplify-compiler-info-in-cmake.patch
Normal file
43
SOURCES/exiv2-simplify-compiler-info-in-cmake.patch
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
From f9e3c712fe23a9cb661c998fc4fd14e7e5d641f5 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Luis Diaz Mas <piponazo@gmail.com>
|
||||||
|
Date: Thu, 17 Aug 2017 22:40:50 +0200
|
||||||
|
Subject: Simplify compiler info handling in CMake
|
||||||
|
|
||||||
|
(cherry picked from commit 69fb40fdc6d5797d10a025b9f5123978dda3bfa4)
|
||||||
|
|
||||||
|
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||||
|
index f2103c44..e49fb78b 100644
|
||||||
|
--- a/CMakeLists.txt
|
||||||
|
+++ b/CMakeLists.txt
|
||||||
|
@@ -67,8 +67,8 @@ ENDIF()
|
||||||
|
# set include path for FindXXX.cmake files
|
||||||
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/config/")
|
||||||
|
|
||||||
|
-IF( MINGW OR UNIX )
|
||||||
|
- IF ( CMAKE_CXX_COMPILER STREQUAL "g++" OR CMAKE_C_COMPILER STREQUAL "gcc" )
|
||||||
|
+if( MINGW OR UNIX )
|
||||||
|
+ if (${CMAKE_CXX_COMPILER_ID} STREQUAL GNU)
|
||||||
|
ADD_DEFINITIONS(-Wall
|
||||||
|
-Wcast-align
|
||||||
|
-Wpointer-arith
|
||||||
|
@@ -79,18 +79,8 @@ IF( MINGW OR UNIX )
|
||||||
|
)
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
- execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version OUTPUT_VARIABLE COMPILER_VERSION)
|
||||||
|
- string(REGEX MATCHALL "[a-z\+]+" GCC_COMPILER_COMPONENTS ${COMPILER_VERSION})
|
||||||
|
- list(GET GCC_COMPILER_COMPONENTS 0 COMPILER)
|
||||||
|
-
|
||||||
|
- execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
|
||||||
|
- string(REGEX MATCHALL "[0-9]+" GCC_VERSION_COMPONENTS ${GCC_VERSION})
|
||||||
|
- list(GET GCC_VERSION_COMPONENTS 0 GCC_MAJOR)
|
||||||
|
- list(GET GCC_VERSION_COMPONENTS 1 GCC_MINOR)
|
||||||
|
-
|
||||||
|
- message(STATUS Compiler: ${COMPILER} " Major:" ${GCC_MAJOR} " Minor:" ${GCC_MINOR})
|
||||||
|
-
|
||||||
|
- IF ( CYGWIN OR ( ${GCC_MAJOR} GREATER 5 ))
|
||||||
|
+ message(STATUS "Compiler info: ${CMAKE_CXX_COMPILER_ID} (${CMAKE_CXX_COMPILER}) ; version: ${CMAKE_CXX_COMPILER_VERSION}")
|
||||||
|
+ IF ( CYGWIN OR (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 5.0))
|
||||||
|
ADD_DEFINITIONS( -std=gnu++98 ) # to support snprintf
|
||||||
|
ELSE()
|
||||||
|
ADD_DEFINITIONS( -std=c++98 )
|
39
SOURCES/exiv2-wrong-brackets.patch
Normal file
39
SOURCES/exiv2-wrong-brackets.patch
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
From 1e07c98dfcbd8ac10ee02088f08235f5e1700148 Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Dan=20=C4=8Cerm=C3=A1k?= <dan.cermak@cgc-instruments.com>
|
||||||
|
Date: Wed, 27 Sep 2017 23:38:49 +0200
|
||||||
|
Subject: Fixed wrong brackets: size*count + pad can overflow before the cast
|
||||||
|
|
||||||
|
=> Should fix #76 (most of the work has been done by Robin Mills in
|
||||||
|
6e3855aed7ba8bb4731fc4087ca7f9078b2f3d97)
|
||||||
|
|
||||||
|
The problem with #76 is the contents of the 26th IFD, with the
|
||||||
|
following contents:
|
||||||
|
tag: 0x8649
|
||||||
|
type: 0x1
|
||||||
|
count: 0xffff ffff
|
||||||
|
offset: 0x4974
|
||||||
|
|
||||||
|
The issue is the size of count (uint32_t), as adding anything to it
|
||||||
|
causes an overflow. Especially the expression:
|
||||||
|
(size*count + pad+20)
|
||||||
|
results in an overflow and gives 20 as a result instead of
|
||||||
|
0x100000014, thus the condition in the if in the next line is false
|
||||||
|
and the program continues to run (until it crashes at io.read).
|
||||||
|
|
||||||
|
To properly account for the overflow, the brackets have to be removed,
|
||||||
|
as then the result is saved in the correctly sized type and not cast
|
||||||
|
after being calculated in the smaller type.
|
||||||
|
|
||||||
|
diff --git a/src/image.cpp b/src/image.cpp
|
||||||
|
index ec5b873e..199671b9 100644
|
||||||
|
--- a/src/image.cpp
|
||||||
|
+++ b/src/image.cpp
|
||||||
|
@@ -401,7 +401,7 @@ namespace Exiv2 {
|
||||||
|
// if ( offset > io.size() ) offset = 0; // Denial of service?
|
||||||
|
|
||||||
|
// #55 memory allocation crash test/data/POC8
|
||||||
|
- long long allocate = (long long) (size*count + pad+20);
|
||||||
|
+ long long allocate = (long long) size*count + pad+20;
|
||||||
|
if ( allocate > (long long) io.size() ) {
|
||||||
|
throw Error(57);
|
||||||
|
}
|
108
SPECS/compat-exiv2-026.spec
Normal file
108
SPECS/compat-exiv2-026.spec
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
Name: compat-exiv2-026
|
||||||
|
Version: 0.26
|
||||||
|
Release: 3%{?dist}
|
||||||
|
Summary: Compatibility package with the exiv2 library in version 0.26
|
||||||
|
|
||||||
|
License: GPLv2+
|
||||||
|
URL: http://www.exiv2.org/
|
||||||
|
Source0: https://github.com/Exiv2/%{name}/archive/exiv2-%{version}.tar.gz
|
||||||
|
|
||||||
|
Patch0: exiv2-simplify-compiler-info-in-cmake.patch
|
||||||
|
Patch1: exiv2-do-not-build-documentation.patch
|
||||||
|
|
||||||
|
## upstream patches (lookaside cache)
|
||||||
|
Patch6: 0006-1296-Fix-submitted.patch
|
||||||
|
|
||||||
|
# Security fixes
|
||||||
|
Patch10: exiv2-CVE-2017-17723-1.patch
|
||||||
|
Patch11: exiv2-CVE-2017-17723-2.patch
|
||||||
|
Patch12: exiv2-wrong-brackets.patch
|
||||||
|
Patch13: exiv2-CVE-2017-11683.patch
|
||||||
|
Patch14: exiv2-CVE-2017-14860.patch
|
||||||
|
Patch15: exiv2-CVE-2017-14864-CVE-2017-14862-CVE-2017-14859.patch
|
||||||
|
Patch16: exiv2-CVE-2017-17725.patch
|
||||||
|
Patch17: exiv2-CVE-2017-17669.patch
|
||||||
|
Patch18: exiv2-additional-security-fixes.patch
|
||||||
|
Patch19: exiv2-CVE-2018-10958.patch
|
||||||
|
Patch20: exiv2-CVE-2018-10998.patch
|
||||||
|
Patch21: exiv2-CVE-2018-11531.patch
|
||||||
|
Patch22: exiv2-CVE-2018-12264-CVE-2018-12265.patch
|
||||||
|
Patch23: exiv2-CVE-2018-14046.patch
|
||||||
|
Patch24: exiv2-CVE-2018-5772.patch
|
||||||
|
Patch25: exiv2-CVE-2018-8976.patch
|
||||||
|
Patch26: exiv2-CVE-2018-8977.patch
|
||||||
|
Patch27: exiv2-CVE-2018-16336.patch
|
||||||
|
|
||||||
|
## upstreamable patches
|
||||||
|
|
||||||
|
BuildRequires: cmake
|
||||||
|
BuildRequires: expat-devel
|
||||||
|
BuildRequires: gettext
|
||||||
|
BuildRequires: pkgconfig
|
||||||
|
BuildRequires: pkgconfig(libcurl)
|
||||||
|
BuildRequires: pkgconfig(libssh)
|
||||||
|
BuildRequires: zlib-devel
|
||||||
|
|
||||||
|
Conflicts: exiv2-libs < 0.27
|
||||||
|
|
||||||
|
%description
|
||||||
|
A command line utility to access image metadata, allowing one to:
|
||||||
|
* print the Exif metadata of Jpeg images as summary info, interpreted values,
|
||||||
|
or the plain data for each tag
|
||||||
|
* print the Iptc metadata of Jpeg images
|
||||||
|
* print the Jpeg comment of Jpeg images
|
||||||
|
* set, add and delete Exif and Iptc metadata of Jpeg images
|
||||||
|
* adjust the Exif timestamp (that's how it all started...)
|
||||||
|
* rename Exif image files according to the Exif timestamp
|
||||||
|
* extract, insert and delete Exif metadata (including thumbnails),
|
||||||
|
Iptc metadata and Jpeg comments
|
||||||
|
|
||||||
|
%prep
|
||||||
|
%autosetup -n exiv2-%{version} -p1
|
||||||
|
|
||||||
|
|
||||||
|
%build
|
||||||
|
# exiv2: embedded copy of exempi should be compiled with BanAllEntityUsage
|
||||||
|
# https://bugzilla.redhat.com/show_bug.cgi?id=888769
|
||||||
|
export CPPFLAGS="-DBanAllEntityUsage=1"
|
||||||
|
|
||||||
|
%{cmake} \
|
||||||
|
-DEXIV2_ENABLE_BUILD_PO:BOOL=OFF \
|
||||||
|
-DEXIV2_ENABLE_BUILD_SAMPLES:BOOL=OFF \
|
||||||
|
-DEXIV2_ENABLE_LIBXMP:BOOL=ON .
|
||||||
|
# FIXME: build this because it adds Threads library and it doesn't build without
|
||||||
|
# it from some reason
|
||||||
|
|
||||||
|
make %{?_smp_mflags}
|
||||||
|
|
||||||
|
%install
|
||||||
|
make install/fast DESTDIR=%{buildroot}
|
||||||
|
|
||||||
|
## unpackaged files
|
||||||
|
rm -rf %{buildroot}%{_bindir}/exiv2
|
||||||
|
rm -rf %{buildroot}%{_includedir}/exiv2
|
||||||
|
rm -rf %{buildroot}%{_libdir}/libexiv2.la
|
||||||
|
rm -rf %{buildroot}%{_libdir}/libxmp.a
|
||||||
|
rm -rf %{buildroot}%{_libdir}/pkgconfig/exiv2.pc
|
||||||
|
rm -rf %{buildroot}%{_libdir}/pkgconfig/exiv2.lsm
|
||||||
|
rm -rf %{buildroot}%{_datadir}/locale/*
|
||||||
|
rm -rf %{buildroot}%{_mandir}/*
|
||||||
|
rm -rf mv %{buildroot}%{_libdir}/libexiv2.so
|
||||||
|
|
||||||
|
|
||||||
|
%files
|
||||||
|
%doc COPYING README
|
||||||
|
%{_libdir}/libexiv2.so.26*
|
||||||
|
|
||||||
|
|
||||||
|
%changelog
|
||||||
|
* Thu Nov 21 2019 Jan Grulich <jgrulich@redhat.com> - 0.26-3
|
||||||
|
- Remove pre-built msvc binaries
|
||||||
|
Resolves: bz#1757349
|
||||||
|
|
||||||
|
* Wed Oct 09 2019 Tomas Pelka <tpelka@redhat.com> - 0.26-2
|
||||||
|
- bump version in order to pick up with gating
|
||||||
|
|
||||||
|
* Mon Oct 07 2019 Jan Grulich <jgrulich@redhat.com> - 0.26-1
|
||||||
|
- Spec file based on exiv2 package to provide old libraries before API change
|
||||||
|
Resolves: bz#1757349
|
Loading…
Reference in New Issue
Block a user