import exiv2-0.27.2-5.el8
This commit is contained in:
parent
b822b34a84
commit
fa38d575c3
@ -1 +1 @@
|
|||||||
25b9b93dc1df3bd449fa250ddfb84bc11fb4812b SOURCES/exiv2-0.26.tar.gz
|
4e740e21f2e0d1fc4c81241ddc3a939f39b326c7 SOURCES/exiv2-0.27.2.tar.gz
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -1 +1 @@
|
|||||||
SOURCES/exiv2-0.26.tar.gz
|
SOURCES/exiv2-0.27.2.tar.gz
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
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
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
|||||||
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
|
|
@ -1,53 +0,0 @@
|
|||||||
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 "
|
|
@ -1,37 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
|||||||
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
|
|
@ -1,80 +0,0 @@
|
|||||||
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
|
|
@ -1,351 +0,0 @@
|
|||||||
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_
|
|
@ -1,344 +0,0 @@
|
|||||||
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
|
|
@ -1,61 +0,0 @@
|
|||||||
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
|
|
@ -1,31 +0,0 @@
|
|||||||
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_);
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
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;
|
|
@ -1,49 +0,0 @@
|
|||||||
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];
|
|
||||||
|
|
@ -1,239 +0,0 @@
|
|||||||
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";
|
|
@ -1,76 +0,0 @@
|
|||||||
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_,
|
|
@ -1,466 +0,0 @@
|
|||||||
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()
|
|
||||||
{
|
|
@ -1,21 +0,0 @@
|
|||||||
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" ;
|
|
||||||
}
|
|
97
SOURCES/exiv2-CVE-2019-20421.patch
Normal file
97
SOURCES/exiv2-CVE-2019-20421.patch
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
From 1b917c3f7dd86336a9f6fda4456422c419dfe88c Mon Sep 17 00:00:00 2001
|
||||||
|
From: clanmills <robin@clanmills.com>
|
||||||
|
Date: Tue, 1 Oct 2019 17:39:44 +0100
|
||||||
|
Subject: [PATCH] Fix #1011 fix_1011_jp2_readmetadata_loop
|
||||||
|
|
||||||
|
---
|
||||||
|
src/jp2image.cpp | 25 +++++++++++++++----
|
||||||
|
test/data/Jp2Image_readMetadata_loop.poc | Bin 0 -> 738 bytes
|
||||||
|
tests/bugfixes/github/test_CVE_2017_17725.py | 4 +--
|
||||||
|
tests/bugfixes/github/test_issue_1011.py | 13 ++++++++++
|
||||||
|
4 files changed, 35 insertions(+), 7 deletions(-)
|
||||||
|
create mode 100755 test/data/Jp2Image_readMetadata_loop.poc
|
||||||
|
create mode 100644 tests/bugfixes/github/test_issue_1011.py
|
||||||
|
|
||||||
|
diff --git a/src/jp2image.cpp b/src/jp2image.cpp
|
||||||
|
index d5cd1340a..0de088d62 100644
|
||||||
|
--- a/src/jp2image.cpp
|
||||||
|
+++ b/src/jp2image.cpp
|
||||||
|
@@ -18,10 +18,6 @@
|
||||||
|
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
-/*
|
||||||
|
- File: jp2image.cpp
|
||||||
|
-*/
|
||||||
|
-
|
||||||
|
// *****************************************************************************
|
||||||
|
|
||||||
|
// included header files
|
||||||
|
@@ -197,6 +193,16 @@ namespace Exiv2
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void boxes_check(size_t b,size_t m)
|
||||||
|
+{
|
||||||
|
+ if ( b > m ) {
|
||||||
|
+#ifdef EXIV2_DEBUG_MESSAGES
|
||||||
|
+ std::cout << "Exiv2::Jp2Image::readMetadata box maximum exceeded" << std::endl;
|
||||||
|
+#endif
|
||||||
|
+ throw Error(kerCorruptedMetadata);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void Jp2Image::readMetadata()
|
||||||
|
{
|
||||||
|
#ifdef EXIV2_DEBUG_MESSAGES
|
||||||
|
@@ -219,9 +225,12 @@ namespace Exiv2
|
||||||
|
Jp2BoxHeader subBox = {0,0};
|
||||||
|
Jp2ImageHeaderBox ihdr = {0,0,0,0,0,0,0,0};
|
||||||
|
Jp2UuidBox uuid = {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
|
||||||
|
+ size_t boxes = 0 ;
|
||||||
|
+ size_t boxem = 1000 ; // boxes max
|
||||||
|
|
||||||
|
while (io_->read((byte*)&box, sizeof(box)) == sizeof(box))
|
||||||
|
{
|
||||||
|
+ boxes_check(boxes++,boxem );
|
||||||
|
position = io_->tell();
|
||||||
|
box.length = getLong((byte*)&box.length, bigEndian);
|
||||||
|
box.type = getLong((byte*)&box.type, bigEndian);
|
||||||
|
@@ -251,8 +260,12 @@ namespace Exiv2
|
||||||
|
|
||||||
|
while (io_->read((byte*)&subBox, sizeof(subBox)) == sizeof(subBox) && subBox.length )
|
||||||
|
{
|
||||||
|
+ boxes_check(boxes++, boxem) ;
|
||||||
|
subBox.length = getLong((byte*)&subBox.length, bigEndian);
|
||||||
|
subBox.type = getLong((byte*)&subBox.type, bigEndian);
|
||||||
|
+ if (subBox.length > io_->size() ) {
|
||||||
|
+ throw Error(kerCorruptedMetadata);
|
||||||
|
+ }
|
||||||
|
#ifdef EXIV2_DEBUG_MESSAGES
|
||||||
|
std::cout << "Exiv2::Jp2Image::readMetadata: "
|
||||||
|
<< "subBox = " << toAscii(subBox.type) << " length = " << subBox.length << std::endl;
|
||||||
|
@@ -308,7 +321,9 @@ namespace Exiv2
|
||||||
|
}
|
||||||
|
|
||||||
|
io_->seek(restore,BasicIo::beg);
|
||||||
|
- io_->seek(subBox.length, Exiv2::BasicIo::cur);
|
||||||
|
+ if ( io_->seek(subBox.length, Exiv2::BasicIo::cur) != 0 ) {
|
||||||
|
+ throw Error(kerCorruptedMetadata);
|
||||||
|
+ }
|
||||||
|
restore = io_->tell();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
diff --git a/tests/bugfixes/github/test_CVE_2017_17725.py b/tests/bugfixes/github/test_CVE_2017_17725.py
|
||||||
|
index 1127b9806..670a75d8d 100644
|
||||||
|
--- a/tests/bugfixes/github/test_CVE_2017_17725.py
|
||||||
|
+++ b/tests/bugfixes/github/test_CVE_2017_17725.py
|
||||||
|
@@ -11,7 +11,7 @@ class TestCvePoC(metaclass=system_tests.CaseMeta):
|
||||||
|
filename = "$data_path/poc_2017-12-12_issue188"
|
||||||
|
commands = ["$exiv2 " + filename]
|
||||||
|
stdout = [""]
|
||||||
|
- stderr = ["""$exiv2_overflow_exception_message """ + filename + """:
|
||||||
|
-$addition_overflow_message
|
||||||
|
+ stderr = ["""$exiv2_exception_message """ + filename + """:
|
||||||
|
+$kerCorruptedMetadata
|
||||||
|
"""]
|
||||||
|
retval = [1]
|
@ -1,176 +0,0 @@
|
|||||||
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 {
|
|
@ -1,21 +0,0 @@
|
|||||||
diff -up exiv2-trunk/config/Doxyfile.doxygen exiv2-trunk/config/Doxyfile
|
|
||||||
--- exiv2-trunk/config/Doxyfile.doxygen 2017-05-02 09:17:33.631909015 -0500
|
|
||||||
+++ exiv2-trunk/config/Doxyfile 2017-05-02 09:18:03.019200824 -0500
|
|
||||||
@@ -1688,7 +1688,7 @@ HIDE_UNDOC_RELATIONS = YES
|
|
||||||
# toolkit from AT&T and Lucent Bell Labs. The other options in this section
|
|
||||||
# have no effect if this option is set to NO (the default)
|
|
||||||
|
|
||||||
-HAVE_DOT = YES
|
|
||||||
+#HAVE_DOT = YES
|
|
||||||
|
|
||||||
# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
|
|
||||||
# allowed to run in parallel. When set to 0 (the default) doxygen will
|
|
||||||
@@ -1705,7 +1705,7 @@ DOT_NUM_THREADS = 0
|
|
||||||
# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
|
|
||||||
# directory containing the font.
|
|
||||||
|
|
||||||
-DOT_FONTNAME = Arial
|
|
||||||
+#DOT_FONTNAME = Arial
|
|
||||||
|
|
||||||
# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
|
|
||||||
# The default size is 10pt.
|
|
@ -1,84 +0,0 @@
|
|||||||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
|
||||||
index 7034bb6..27e90de 100644
|
|
||||||
--- a/CMakeLists.txt
|
|
||||||
+++ b/CMakeLists.txt
|
|
||||||
@@ -217,13 +217,16 @@ 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()
|
|
||||||
+
|
|
||||||
+include(config/generateDoc.cmake REQUIRED)
|
|
||||||
+generate_documentation("${PROJECT_SOURCE_DIR}/config/Doxyfile")
|
|
||||||
|
|
||||||
# That's all Folks!
|
|
||||||
##
|
|
||||||
diff --git a/config/Doxyfile b/config/Doxyfile
|
|
||||||
index db62e1d..5d357a7 100644
|
|
||||||
--- a/config/Doxyfile
|
|
||||||
+++ b/config/Doxyfile
|
|
||||||
@@ -52,7 +52,7 @@ PROJECT_LOGO =
|
|
||||||
# If a relative path is entered, it will be relative to the location
|
|
||||||
# where doxygen was started. If left blank the current directory will be used.
|
|
||||||
|
|
||||||
-OUTPUT_DIRECTORY =
|
|
||||||
+OUTPUT_DIRECTORY = doc
|
|
||||||
|
|
||||||
# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
|
|
||||||
# 4096 sub-directories (in 2 levels) under the output directory of each output
|
|
||||||
@@ -1637,7 +1637,7 @@ TAGFILES =
|
|
||||||
# When a file name is specified after GENERATE_TAGFILE, doxygen will create
|
|
||||||
# a tag file that is based on the input files it reads.
|
|
||||||
|
|
||||||
-GENERATE_TAGFILE = html/exiv2.xml
|
|
||||||
+GENERATE_TAGFILE = doc/html/exiv2.xml
|
|
||||||
|
|
||||||
# If the ALLEXTERNALS tag is set to YES all external classes will be listed
|
|
||||||
# in the class index. If set to NO only the inherited external classes
|
|
||||||
diff --git a/config/generateDoc.cmake b/config/generateDoc.cmake
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..2b66078
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/config/generateDoc.cmake
|
|
||||||
@@ -0,0 +1,28 @@
|
|
||||||
+# -helper macro to add a "doc" target with CMake build system.
|
|
||||||
+# and configure doxy.config.in to doxy.config
|
|
||||||
+#
|
|
||||||
+# target "doc" allows building the documentation with doxygen/dot on WIN32, Linux and Mac
|
|
||||||
+#
|
|
||||||
+
|
|
||||||
+find_package(Doxygen REQUIRED)
|
|
||||||
+
|
|
||||||
+macro(generate_documentation DOX_CONFIG_FILE)
|
|
||||||
+ if(NOT EXISTS "${DOX_CONFIG_FILE}")
|
|
||||||
+ message(FATAL_ERROR "Configuration file for doxygen not found")
|
|
||||||
+ endif()
|
|
||||||
+
|
|
||||||
+ #Define variables
|
|
||||||
+ set(INCDIR "${PROJECT_SOURCE_DIR}/include/exiv2")
|
|
||||||
+ set(SRCDIR "${PROJECT_SOURCE_DIR}/src")
|
|
||||||
+ set(ROOTDIR "${PROJECT_SOURCE_DIR}")
|
|
||||||
+ #set(TESTSDIR "${PROJECT_SOURCE_DIR}/tests")
|
|
||||||
+
|
|
||||||
+ configure_file(${DOX_CONFIG_FILE} ${CMAKE_CURRENT_BINARY_DIR}/doxy.config @ONLY) #OUT-OF-PLACE LOCATION
|
|
||||||
+ set(DOXY_CONFIG "${CMAKE_CURRENT_BINARY_DIR}/doxy.config")
|
|
||||||
+ add_custom_target(doc ${DOXYGEN_EXECUTABLE} ${DOXY_CONFIG})
|
|
||||||
+
|
|
||||||
+ install(DIRECTORY "${PROJECT_BINARY_DIR}/doc/html/" DESTINATION "share/doc/html/lib${PROJECT_NAME}")
|
|
||||||
+
|
|
||||||
+ set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES doc)
|
|
||||||
+endmacro()
|
|
||||||
+
|
|
@ -1,43 +0,0 @@
|
|||||||
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 )
|
|
@ -1,39 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
@ -1,41 +1,17 @@
|
|||||||
|
|
||||||
Summary: Exif and Iptc metadata manipulation library
|
Summary: Exif and Iptc metadata manipulation library
|
||||||
Name: exiv2
|
Name: exiv2
|
||||||
Version: 0.26
|
Version: 0.27.2
|
||||||
Release: 10%{?dist}
|
Release: 5%{?dist}
|
||||||
|
|
||||||
License: GPLv2+
|
License: GPLv2+
|
||||||
URL: http://www.exiv2.org/
|
URL: http://www.exiv2.org/
|
||||||
Source0: https://github.com/Exiv2/%{name}/archive/exiv2-%{version}.tar.gz
|
Source0: https://github.com/Exiv2/%{name}/archive/exiv2-%{version}.tar.gz
|
||||||
|
|
||||||
Patch0: exiv2-simplify-compiler-info-in-cmake.patch
|
|
||||||
Patch1: exiv2-fix-documentation-build.patch
|
|
||||||
|
|
||||||
## upstream patches (lookaside cache)
|
## upstream patches (lookaside cache)
|
||||||
Patch6: 0006-1296-Fix-submitted.patch
|
Patch0: exiv2-CVE-2019-20421.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
|
## upstreamable patches
|
||||||
Patch100: exiv2-doxygen.patch
|
|
||||||
|
|
||||||
BuildRequires: cmake
|
BuildRequires: cmake
|
||||||
BuildRequires: expat-devel
|
BuildRequires: expat-devel
|
||||||
@ -92,19 +68,14 @@ BuildArch: noarch
|
|||||||
|
|
||||||
|
|
||||||
%build
|
%build
|
||||||
# exiv2: embedded copy of exempi should be compiled with BanAllEntityUsage
|
%{cmake} . \
|
||||||
# https://bugzilla.redhat.com/show_bug.cgi?id=888769
|
-DCMAKE_INSTALL_DOCDIR="%{_pkgdocdir}" \
|
||||||
export CPPFLAGS="-DBanAllEntityUsage=1"
|
-DEXIV2_BUILD_DOC:BOOL=ON \
|
||||||
|
-DEXIV2_ENABLE_NLS:BOOL=ON \
|
||||||
|
-DEXIV2_BUILD_SAMPLES:BOOL=OFF
|
||||||
|
|
||||||
%{cmake} \
|
%make_build
|
||||||
-DEXIV2_ENABLE_BUILD_PO:BOOL=ON \
|
%make_build doc
|
||||||
-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}
|
|
||||||
make doc -k ||:
|
|
||||||
|
|
||||||
%install
|
%install
|
||||||
make install/fast DESTDIR=%{buildroot}
|
make install/fast DESTDIR=%{buildroot}
|
||||||
@ -113,12 +84,12 @@ make install/fast DESTDIR=%{buildroot}
|
|||||||
|
|
||||||
## unpackaged files
|
## unpackaged files
|
||||||
rm -fv %{buildroot}%{_libdir}/libexiv2.la
|
rm -fv %{buildroot}%{_libdir}/libexiv2.la
|
||||||
rm -fv %{buildroot}%{_libdir}/libxmp.a
|
#rm -fv %{buildroot}%{_libdir}/pkgconfig/exiv2.lsm
|
||||||
rm -fv %{buildroot}%{_libdir}/pkgconfig//exiv2.lsm
|
|
||||||
|
|
||||||
%check
|
%check
|
||||||
export PKG_CONFIG_PATH=%{buildroot}%{_libdir}/pkgconfig
|
export PKG_CONFIG_PATH="%{buildroot}%{_libdir}/pkgconfig${PKG_CONFIG_PATH:+:}${PKG_CONFIG_PATH}"
|
||||||
test "$(pkg-config --modversion exiv2)" = "%{version}"
|
test "$(pkg-config --modversion exiv2)" = "0.27.2"
|
||||||
|
test "$(pkg-config --variable=libdir exiv2)" = "%{_libdir}"
|
||||||
test -x %{buildroot}%{_libdir}/libexiv2.so
|
test -x %{buildroot}%{_libdir}/libexiv2.so
|
||||||
|
|
||||||
|
|
||||||
@ -126,25 +97,49 @@ test -x %{buildroot}%{_libdir}/libexiv2.so
|
|||||||
%license COPYING
|
%license COPYING
|
||||||
%doc doc/ChangeLog
|
%doc doc/ChangeLog
|
||||||
# README is mostly installation instructions
|
# README is mostly installation instructions
|
||||||
#doc README
|
#doc README.md
|
||||||
%{_bindir}/exiv2
|
%{_bindir}/exiv2
|
||||||
%{_mandir}/man1/exiv2*.1*
|
%{_mandir}/man1/exiv2*.1*
|
||||||
|
|
||||||
%ldconfig_scriptlets libs
|
%ldconfig_scriptlets libs
|
||||||
|
|
||||||
%files libs
|
%files libs
|
||||||
%{_libdir}/libexiv2.so.26*
|
%{_libdir}/libexiv2.so.27*
|
||||||
|
%{_libdir}/libexiv2.so.0.27.2
|
||||||
|
|
||||||
%files devel
|
%files devel
|
||||||
%{_includedir}/exiv2/
|
%{_includedir}/exiv2/
|
||||||
%{_libdir}/libexiv2.so
|
%{_libdir}/libexiv2.so
|
||||||
%{_libdir}/pkgconfig/exiv2.pc
|
%{_libdir}/pkgconfig/exiv2.pc
|
||||||
|
%{_libdir}/cmake/exiv2/
|
||||||
|
%{_libdir}/libexiv2-xmp.a
|
||||||
|
|
||||||
%files doc
|
%files doc
|
||||||
%{_datadir}/doc/html/
|
%{_pkgdocdir}/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Wed Mar 04 2020 Jan Grulich <jgrulich@redhat.com> - 0.27.2-5
|
||||||
|
- Fix failing test
|
||||||
|
Resolves: bz#1800472
|
||||||
|
|
||||||
|
* Wed Mar 04 2020 Jan Grulich <jgrulich@redhat.com> - 0.27.2-4
|
||||||
|
- Drop test for the previous CVE as we test it manually and we don't have POC available
|
||||||
|
Resolves: bz#1800472
|
||||||
|
|
||||||
|
* Wed Feb 26 2020 Jan Grulich <jgrulich@redhat.com> - 0.27.2-3
|
||||||
|
- Fix infinite loop and hang in Jp2Image::readMetadata()
|
||||||
|
Resolves: bz#1800472
|
||||||
|
|
||||||
|
* Tue Oct 29 2019 Jan Grulich <jgrulich@redhat.com> - 0.27.2-2
|
||||||
|
Rebuild
|
||||||
|
Resolves: bz#1651917
|
||||||
|
|
||||||
|
* Fri Sep 20 2019 Jan Grulich <jgrulich@redhat.com> - 0.27.2-1
|
||||||
|
- Update to 0.27.2
|
||||||
|
Resolves: bz#1651917
|
||||||
|
|
||||||
* Tue Sep 11 2018 Jan Grulich <jgrulich@redhat.com> - 0.26-10
|
* Tue Sep 11 2018 Jan Grulich <jgrulich@redhat.com> - 0.26-10
|
||||||
- Security fix for CVE-2018-16336
|
- Security fix for CVE-2018-16336
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user