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 <laurent.pinchart@ideasonboard.com>
This commit is contained in:
Laurent Pinchart
2020-05-03 17:06:16 +03:00
parent 1beb3c91b4
commit cec7908429
2 changed files with 33 additions and 15 deletions

View File

@@ -1510,8 +1510,6 @@ int Tag::toInt (int ofs, TagType astype) const
return attrib->interpreter->toInt (this, ofs, astype); return attrib->interpreter->toInt (this, ofs, astype);
} }
int a;
if (astype == INVALID) { if (astype == INVALID) {
astype = type; astype = type;
} }
@@ -1537,10 +1535,15 @@ int Tag::toInt (int ofs, TagType astype) const
case LONG: case LONG:
return (int)sget4 (value + ofs, getOrder()); return (int)sget4 (value + ofs, getOrder());
case SRATIONAL: case SRATIONAL: {
case RATIONAL: int a = (int)sget4 (value + ofs + 4, getOrder());
a = (int)sget4 (value + ofs + 4, getOrder());
return a == 0 ? 0 : (int)sget4 (value + ofs, getOrder()) / a; 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: case FLOAT:
return (int)toDouble (ofs); return (int)toDouble (ofs);
@@ -1589,10 +1592,14 @@ double Tag::toDouble (int ofs) const
return (double) ((int)sget4 (value + ofs, getOrder())); return (double) ((int)sget4 (value + ofs, getOrder()));
case SRATIONAL: case SRATIONAL:
case RATIONAL:
ud = (int)sget4 (value + ofs, getOrder()); ud = (int)sget4 (value + ofs, getOrder());
dd = (int)sget4 (value + ofs + 4, 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: case FLOAT:
conv.i = sget4 (value + ofs, getOrder()); conv.i = sget4 (value + ofs, getOrder());
@@ -1735,10 +1742,13 @@ void Tag::toString (char* buffer, int ofs) const
break; break;
case SRATIONAL: case SRATIONAL:
case RATIONAL:
sprintf (b, "%d/%d", (int)sget4 (value + 8 * i + ofs, getOrder()), (int)sget4 (value + 8 * i + ofs + 4, getOrder())); sprintf (b, "%d/%d", (int)sget4 (value + 8 * i + ofs, getOrder()), (int)sget4 (value + 8 * i + ofs + 4, getOrder()));
break; 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: case FLOAT:
sprintf (b, "%g", toDouble (8 * i + ofs)); sprintf (b, "%g", toDouble (8 * i + ofs));
break; break;

View File

@@ -434,13 +434,18 @@ public:
case LONG: case LONG:
return (double) ((int)sget4 (t->getValue() + ofs, t->getOrder())); return (double) ((int)sget4 (t->getValue() + ofs, t->getOrder()));
case SRATIONAL: case SRATIONAL: {
case RATIONAL: {
const double dividend = (int)sget4 (t->getValue() + ofs, t->getOrder()); const double dividend = (int)sget4 (t->getValue() + ofs, t->getOrder());
const double divisor = (int)sget4 (t->getValue() + ofs + 4, t->getOrder()); const double divisor = (int)sget4 (t->getValue() + ofs + 4, t->getOrder());
return divisor == 0. ? 0. : dividend / divisor; 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: case FLOAT:
return double (sget4 (t->getValue() + ofs, t->getOrder())); return double (sget4 (t->getValue() + ofs, t->getOrder()));
@@ -454,8 +459,6 @@ public:
// Get the value as an int // Get the value as an int
virtual int toInt (const Tag* t, int ofs = 0, TagType astype = INVALID) virtual int toInt (const Tag* t, int ofs = 0, TagType astype = INVALID)
{ {
int a;
if (astype == INVALID || astype == AUTO) { if (astype == INVALID || astype == AUTO) {
astype = t->getType(); astype = t->getType();
} }
@@ -480,10 +483,15 @@ public:
case LONG: case LONG:
return (int)sget4 (t->getValue() + ofs, t->getOrder()); return (int)sget4 (t->getValue() + ofs, t->getOrder());
case SRATIONAL: case SRATIONAL: {
case RATIONAL: int a = (int)sget4 (t->getValue() + ofs + 4, t->getOrder());
a = (int)sget4 (t->getValue() + ofs + 4, t->getOrder());
return a == 0 ? 0 : (int)sget4 (t->getValue() + ofs, t->getOrder()) / a; 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: case FLOAT:
return (int)toDouble (t, ofs); return (int)toDouble (t, ofs);