From cec79084296570fb5b4a076d3f9a3c1fbad3ed04 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 3 May 2020 17:06:16 +0300 Subject: [PATCH] rtexif: Fix conversion from RATIONAL to int, double or string RATIONAL tags are defined as a ratio of two LONG, themselves defined as 32-bit unsigned integers. The value is misinterpreted when converting to an int, double or string, as the numerator and the denominator are interpreted as signed values. The problem has been noticed with the ExposureTime tag generated by libtiff, which sets the denominator to 0xffffffff for exposure times lower than 1. Fix it. Signed-off-by: Laurent Pinchart --- rtexif/rtexif.cc | 26 ++++++++++++++++++-------- rtexif/rtexif.h | 22 +++++++++++++++------- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/rtexif/rtexif.cc b/rtexif/rtexif.cc index 06604ade5..95b46c2b9 100644 --- a/rtexif/rtexif.cc +++ b/rtexif/rtexif.cc @@ -1510,8 +1510,6 @@ int Tag::toInt (int ofs, TagType astype) const return attrib->interpreter->toInt (this, ofs, astype); } - int a; - if (astype == INVALID) { astype = type; } @@ -1537,10 +1535,15 @@ int Tag::toInt (int ofs, TagType astype) const case LONG: return (int)sget4 (value + ofs, getOrder()); - case SRATIONAL: - case RATIONAL: - a = (int)sget4 (value + ofs + 4, getOrder()); + case SRATIONAL: { + int a = (int)sget4 (value + ofs + 4, getOrder()); return a == 0 ? 0 : (int)sget4 (value + ofs, getOrder()) / a; + } + + case RATIONAL: { + uint32_t a = (uint32_t)sget4 (value + ofs + 4, getOrder()); + return a == 0 ? 0 : (uint32_t)sget4 (value + ofs, getOrder()) / a; + } case FLOAT: return (int)toDouble (ofs); @@ -1589,10 +1592,14 @@ double Tag::toDouble (int ofs) const return (double) ((int)sget4 (value + ofs, getOrder())); case SRATIONAL: - case RATIONAL: ud = (int)sget4 (value + ofs, getOrder()); dd = (int)sget4 (value + ofs + 4, getOrder()); - return dd == 0. ? 0. : (double)ud / (double)dd; + return dd == 0. ? 0. : ud / dd; + + case RATIONAL: + ud = (uint32_t)sget4 (value + ofs, getOrder()); + dd = (uint32_t)sget4 (value + ofs + 4, getOrder()); + return dd == 0. ? 0. : ud / dd; case FLOAT: conv.i = sget4 (value + ofs, getOrder()); @@ -1735,10 +1742,13 @@ void Tag::toString (char* buffer, int ofs) const break; case SRATIONAL: - case RATIONAL: sprintf (b, "%d/%d", (int)sget4 (value + 8 * i + ofs, getOrder()), (int)sget4 (value + 8 * i + ofs + 4, getOrder())); break; + case RATIONAL: + sprintf (b, "%u/%u", (uint32_t)sget4 (value + 8 * i + ofs, getOrder()), (uint32_t)sget4 (value + 8 * i + ofs + 4, getOrder())); + break; + case FLOAT: sprintf (b, "%g", toDouble (8 * i + ofs)); break; diff --git a/rtexif/rtexif.h b/rtexif/rtexif.h index 1a956a4a5..5084f70de 100644 --- a/rtexif/rtexif.h +++ b/rtexif/rtexif.h @@ -434,13 +434,18 @@ public: case LONG: return (double) ((int)sget4 (t->getValue() + ofs, t->getOrder())); - case SRATIONAL: - case RATIONAL: { + case SRATIONAL: { const double dividend = (int)sget4 (t->getValue() + ofs, t->getOrder()); const double divisor = (int)sget4 (t->getValue() + ofs + 4, t->getOrder()); return divisor == 0. ? 0. : dividend / divisor; } + case RATIONAL: { + const double dividend = (uint32_t)sget4 (t->getValue() + ofs, t->getOrder()); + const double divisor = (uint32_t)sget4 (t->getValue() + ofs + 4, t->getOrder()); + return divisor == 0. ? 0. : dividend / divisor; + } + case FLOAT: return double (sget4 (t->getValue() + ofs, t->getOrder())); @@ -454,8 +459,6 @@ public: // Get the value as an int virtual int toInt (const Tag* t, int ofs = 0, TagType astype = INVALID) { - int a; - if (astype == INVALID || astype == AUTO) { astype = t->getType(); } @@ -480,10 +483,15 @@ public: case LONG: return (int)sget4 (t->getValue() + ofs, t->getOrder()); - case SRATIONAL: - case RATIONAL: - a = (int)sget4 (t->getValue() + ofs + 4, t->getOrder()); + case SRATIONAL: { + int a = (int)sget4 (t->getValue() + ofs + 4, t->getOrder()); return a == 0 ? 0 : (int)sget4 (t->getValue() + ofs, t->getOrder()) / a; + } + + case RATIONAL: { + uint32_t a = (uint32_t)sget4 (t->getValue() + ofs + 4, t->getOrder()); + return a == 0 ? 0 : (uint32_t)sget4 (t->getValue() + ofs, t->getOrder()) / a; + } case FLOAT: return (int)toDouble (t, ofs);