image/decoders/EXIF.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "EXIF.h"
michael@0 7
michael@0 8 #include "mozilla/Endian.h"
michael@0 9
michael@0 10 namespace mozilla {
michael@0 11 namespace image {
michael@0 12
michael@0 13 // Section references in this file refer to the EXIF v2.3 standard, also known
michael@0 14 // as CIPA DC-008-Translation-2010.
michael@0 15
michael@0 16 // See Section 4.6.4, Table 4.
michael@0 17 // Typesafe enums are intentionally not used here since we're comparing to raw
michael@0 18 // integers produced by parsing.
michael@0 19 enum EXIFTag
michael@0 20 {
michael@0 21 OrientationTag = 0x112,
michael@0 22 };
michael@0 23
michael@0 24 // See Section 4.6.2.
michael@0 25 enum EXIFType
michael@0 26 {
michael@0 27 ByteType = 1,
michael@0 28 ASCIIType = 2,
michael@0 29 ShortType = 3,
michael@0 30 LongType = 4,
michael@0 31 RationalType = 5,
michael@0 32 UndefinedType = 7,
michael@0 33 SignedLongType = 9,
michael@0 34 SignedRational = 10,
michael@0 35 };
michael@0 36
michael@0 37 static const char* EXIFHeader = "Exif\0\0";
michael@0 38 static const uint32_t EXIFHeaderLength = 6;
michael@0 39
michael@0 40 /////////////////////////////////////////////////////////////
michael@0 41 // Parse EXIF data, typically found in a JPEG's APP1 segment.
michael@0 42 /////////////////////////////////////////////////////////////
michael@0 43 EXIFData
michael@0 44 EXIFParser::ParseEXIF(const uint8_t* aData, const uint32_t aLength)
michael@0 45 {
michael@0 46 if (!Initialize(aData, aLength))
michael@0 47 return EXIFData();
michael@0 48
michael@0 49 if (!ParseEXIFHeader())
michael@0 50 return EXIFData();
michael@0 51
michael@0 52 uint32_t offsetIFD;
michael@0 53 if (!ParseTIFFHeader(offsetIFD))
michael@0 54 return EXIFData();
michael@0 55
michael@0 56 JumpTo(offsetIFD);
michael@0 57
michael@0 58 Orientation orientation;
michael@0 59 if (!ParseIFD0(orientation))
michael@0 60 return EXIFData();
michael@0 61
michael@0 62 // We only care about orientation at this point, so we don't bother with the
michael@0 63 // other IFDs. If we got this far we're done.
michael@0 64 return EXIFData(orientation);
michael@0 65 }
michael@0 66
michael@0 67 /////////////////////////////////////////////////////////
michael@0 68 // Parse the EXIF header. (Section 4.7.2, Figure 30)
michael@0 69 /////////////////////////////////////////////////////////
michael@0 70 bool
michael@0 71 EXIFParser::ParseEXIFHeader()
michael@0 72 {
michael@0 73 return MatchString(EXIFHeader, EXIFHeaderLength);
michael@0 74 }
michael@0 75
michael@0 76 /////////////////////////////////////////////////////////
michael@0 77 // Parse the TIFF header. (Section 4.5.2, Table 1)
michael@0 78 /////////////////////////////////////////////////////////
michael@0 79 bool
michael@0 80 EXIFParser::ParseTIFFHeader(uint32_t& aIFD0OffsetOut)
michael@0 81 {
michael@0 82 // Determine byte order.
michael@0 83 if (MatchString("MM\0*", 4))
michael@0 84 mByteOrder = ByteOrder::BigEndian;
michael@0 85 else if (MatchString("II*\0", 4))
michael@0 86 mByteOrder = ByteOrder::LittleEndian;
michael@0 87 else
michael@0 88 return false;
michael@0 89
michael@0 90 // Determine offset of the 0th IFD. (It shouldn't be greater than 64k, which
michael@0 91 // is the maximum size of the entry APP1 segment.)
michael@0 92 uint32_t ifd0Offset;
michael@0 93 if (!ReadUInt32(ifd0Offset) || ifd0Offset > 64 * 1024)
michael@0 94 return false;
michael@0 95
michael@0 96 // The IFD offset is relative to the beginning of the TIFF header, which
michael@0 97 // begins after the EXIF header, so we need to increase the offset
michael@0 98 // appropriately.
michael@0 99 aIFD0OffsetOut = ifd0Offset + EXIFHeaderLength;
michael@0 100 return true;
michael@0 101 }
michael@0 102
michael@0 103 /////////////////////////////////////////////////////////
michael@0 104 // Parse the entries in IFD0. (Section 4.6.2)
michael@0 105 /////////////////////////////////////////////////////////
michael@0 106 bool
michael@0 107 EXIFParser::ParseIFD0(Orientation& aOrientationOut)
michael@0 108 {
michael@0 109 uint16_t entryCount;
michael@0 110 if (!ReadUInt16(entryCount))
michael@0 111 return false;
michael@0 112
michael@0 113 for (uint16_t entry = 0 ; entry < entryCount ; ++entry) {
michael@0 114 // Read the fields of the entry.
michael@0 115 uint16_t tag;
michael@0 116 if (!ReadUInt16(tag))
michael@0 117 return false;
michael@0 118
michael@0 119 // Right now, we only care about orientation, so we immediately skip to the
michael@0 120 // next entry if we find anything else.
michael@0 121 if (tag != OrientationTag) {
michael@0 122 Advance(10);
michael@0 123 continue;
michael@0 124 }
michael@0 125
michael@0 126 uint16_t type;
michael@0 127 if (!ReadUInt16(type))
michael@0 128 return false;
michael@0 129
michael@0 130 uint32_t count;
michael@0 131 if (!ReadUInt32(count))
michael@0 132 return false;
michael@0 133
michael@0 134 // We should have an orientation value here; go ahead and parse it.
michael@0 135 Orientation orientation;
michael@0 136 if (!ParseOrientation(type, count, aOrientationOut))
michael@0 137 return false;
michael@0 138
michael@0 139 // Since the orientation is all we care about, we're done.
michael@0 140 return true;
michael@0 141 }
michael@0 142
michael@0 143 // We didn't find an orientation field in the IFD. That's OK; we assume the
michael@0 144 // default orientation in that case.
michael@0 145 aOrientationOut = Orientation();
michael@0 146 return true;
michael@0 147 }
michael@0 148
michael@0 149 bool
michael@0 150 EXIFParser::ParseOrientation(uint16_t aType, uint32_t aCount, Orientation& aOut)
michael@0 151 {
michael@0 152 // Sanity check the type and count.
michael@0 153 if (aType != ShortType || aCount != 1)
michael@0 154 return false;
michael@0 155
michael@0 156 uint16_t value;
michael@0 157 if (!ReadUInt16(value))
michael@0 158 return false;
michael@0 159
michael@0 160 switch (value) {
michael@0 161 case 1: aOut = Orientation(Angle::D0, Flip::Unflipped); break;
michael@0 162 case 2: aOut = Orientation(Angle::D0, Flip::Horizontal); break;
michael@0 163 case 3: aOut = Orientation(Angle::D180, Flip::Unflipped); break;
michael@0 164 case 4: aOut = Orientation(Angle::D180, Flip::Horizontal); break;
michael@0 165 case 5: aOut = Orientation(Angle::D90, Flip::Horizontal); break;
michael@0 166 case 6: aOut = Orientation(Angle::D90, Flip::Unflipped); break;
michael@0 167 case 7: aOut = Orientation(Angle::D270, Flip::Horizontal); break;
michael@0 168 case 8: aOut = Orientation(Angle::D270, Flip::Unflipped); break;
michael@0 169 default: return false;
michael@0 170 }
michael@0 171
michael@0 172 // This is a 32-bit field, but the orientation value only occupies the first
michael@0 173 // 16 bits. We need to advance another 16 bits to consume the entire field.
michael@0 174 Advance(2);
michael@0 175 return true;
michael@0 176 }
michael@0 177
michael@0 178 bool
michael@0 179 EXIFParser::Initialize(const uint8_t* aData, const uint32_t aLength)
michael@0 180 {
michael@0 181 if (aData == nullptr)
michael@0 182 return false;
michael@0 183
michael@0 184 // An APP1 segment larger than 64k violates the JPEG standard.
michael@0 185 if (aLength > 64 * 1024)
michael@0 186 return false;
michael@0 187
michael@0 188 mStart = mCurrent = aData;
michael@0 189 mLength = mRemainingLength = aLength;
michael@0 190 mByteOrder = ByteOrder::Unknown;
michael@0 191 return true;
michael@0 192 }
michael@0 193
michael@0 194 void
michael@0 195 EXIFParser::Advance(const uint32_t aDistance)
michael@0 196 {
michael@0 197 if (mRemainingLength >= aDistance) {
michael@0 198 mCurrent += aDistance;
michael@0 199 mRemainingLength -= aDistance;
michael@0 200 } else {
michael@0 201 mCurrent = mStart;
michael@0 202 mRemainingLength = 0;
michael@0 203 }
michael@0 204 }
michael@0 205
michael@0 206 void
michael@0 207 EXIFParser::JumpTo(const uint32_t aOffset)
michael@0 208 {
michael@0 209 if (mLength >= aOffset) {
michael@0 210 mCurrent = mStart + aOffset;
michael@0 211 mRemainingLength = mLength - aOffset;
michael@0 212 } else {
michael@0 213 mCurrent = mStart;
michael@0 214 mRemainingLength = 0;
michael@0 215 }
michael@0 216 }
michael@0 217
michael@0 218 bool
michael@0 219 EXIFParser::MatchString(const char* aString, const uint32_t aLength)
michael@0 220 {
michael@0 221 if (mRemainingLength < aLength)
michael@0 222 return false;
michael@0 223
michael@0 224 for (uint32_t i = 0 ; i < aLength ; ++i) {
michael@0 225 if (mCurrent[i] != aString[i])
michael@0 226 return false;
michael@0 227 }
michael@0 228
michael@0 229 Advance(aLength);
michael@0 230 return true;
michael@0 231 }
michael@0 232
michael@0 233 bool
michael@0 234 EXIFParser::MatchUInt16(const uint16_t aValue)
michael@0 235 {
michael@0 236 if (mRemainingLength < 2)
michael@0 237 return false;
michael@0 238
michael@0 239 bool matched;
michael@0 240 switch (mByteOrder) {
michael@0 241 case ByteOrder::LittleEndian:
michael@0 242 matched = LittleEndian::readUint16(mCurrent) == aValue;
michael@0 243 break;
michael@0 244 case ByteOrder::BigEndian:
michael@0 245 matched = BigEndian::readUint16(mCurrent) == aValue;
michael@0 246 break;
michael@0 247 default:
michael@0 248 NS_NOTREACHED("Should know the byte order by now");
michael@0 249 matched = false;
michael@0 250 }
michael@0 251
michael@0 252 if (matched)
michael@0 253 Advance(2);
michael@0 254
michael@0 255 return matched;
michael@0 256 }
michael@0 257
michael@0 258 bool
michael@0 259 EXIFParser::ReadUInt16(uint16_t& aValue)
michael@0 260 {
michael@0 261 if (mRemainingLength < 2)
michael@0 262 return false;
michael@0 263
michael@0 264 bool matched = true;
michael@0 265 switch (mByteOrder) {
michael@0 266 case ByteOrder::LittleEndian:
michael@0 267 aValue = LittleEndian::readUint16(mCurrent);
michael@0 268 break;
michael@0 269 case ByteOrder::BigEndian:
michael@0 270 aValue = BigEndian::readUint16(mCurrent);
michael@0 271 break;
michael@0 272 default:
michael@0 273 NS_NOTREACHED("Should know the byte order by now");
michael@0 274 matched = false;
michael@0 275 }
michael@0 276
michael@0 277 if (matched)
michael@0 278 Advance(2);
michael@0 279
michael@0 280 return matched;
michael@0 281 }
michael@0 282
michael@0 283 bool
michael@0 284 EXIFParser::ReadUInt32(uint32_t& aValue)
michael@0 285 {
michael@0 286 if (mRemainingLength < 4)
michael@0 287 return false;
michael@0 288
michael@0 289 bool matched = true;
michael@0 290 switch (mByteOrder) {
michael@0 291 case ByteOrder::LittleEndian:
michael@0 292 aValue = LittleEndian::readUint32(mCurrent);
michael@0 293 break;
michael@0 294 case ByteOrder::BigEndian:
michael@0 295 aValue = BigEndian::readUint32(mCurrent);
michael@0 296 break;
michael@0 297 default:
michael@0 298 NS_NOTREACHED("Should know the byte order by now");
michael@0 299 matched = false;
michael@0 300 }
michael@0 301
michael@0 302 if (matched)
michael@0 303 Advance(4);
michael@0 304
michael@0 305 return matched;
michael@0 306 }
michael@0 307
michael@0 308 } // namespace image
michael@0 309 } // namespace mozilla

mercurial