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:
@@ -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;
|
||||||
|
@@ -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);
|
||||||
|
Reference in New Issue
Block a user