1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "EXIF.h"
7 
8 #include "mozilla/EndianUtils.h"
9 #include "mozilla/StaticPrefs_image.h"
10 
11 namespace mozilla::image {
12 
13 // Section references in this file refer to the EXIF v2.3 standard, also known
14 // as CIPA DC-008-Translation-2010.
15 
16 // See Section 4.6.4, Table 4.
17 // Typesafe enums are intentionally not used here since we're comparing to raw
18 // integers produced by parsing.
19 enum class EXIFTag : uint16_t {
20   Orientation = 0x112,
21   XResolution = 0x11a,
22   YResolution = 0x11b,
23   PixelXDimension = 0xa002,
24   PixelYDimension = 0xa003,
25   ResolutionUnit = 0x128,
26   IFDPointer = 0x8769,
27 };
28 
29 // See Section 4.6.2.
30 enum EXIFType {
31   ByteType = 1,
32   ASCIIType = 2,
33   ShortType = 3,
34   LongType = 4,
35   RationalType = 5,
36   UndefinedType = 7,
37   SignedLongType = 9,
38   SignedRational = 10,
39 };
40 
41 static const char* EXIFHeader = "Exif\0\0";
42 static const uint32_t EXIFHeaderLength = 6;
43 static const uint32_t TIFFHeaderStart = EXIFHeaderLength;
44 
45 struct ParsedEXIFData {
46   Orientation orientation;
47   Maybe<float> resolutionX;
48   Maybe<float> resolutionY;
49   Maybe<uint32_t> pixelXDimension;
50   Maybe<uint32_t> pixelYDimension;
51   Maybe<ResolutionUnit> resolutionUnit;
52 };
53 
ToDppx(float aResolution,ResolutionUnit aUnit)54 static float ToDppx(float aResolution, ResolutionUnit aUnit) {
55   constexpr float kPointsPerInch = 72.0f;
56   constexpr float kPointsPerCm = 1.0f / 2.54f;
57   switch (aUnit) {
58     case ResolutionUnit::Dpi:
59       return aResolution / kPointsPerInch;
60     case ResolutionUnit::Dpcm:
61       return aResolution / kPointsPerCm;
62   }
63   MOZ_CRASH("Unknown resolution unit?");
64 }
65 
ResolutionFromParsedData(const ParsedEXIFData & aData,const gfx::IntSize & aRealImageSize)66 static Resolution ResolutionFromParsedData(const ParsedEXIFData& aData,
67                                            const gfx::IntSize& aRealImageSize) {
68   if (!aData.resolutionUnit || !aData.resolutionX || !aData.resolutionY) {
69     return {};
70   }
71 
72   Resolution resolution{ToDppx(*aData.resolutionX, *aData.resolutionUnit),
73                         ToDppx(*aData.resolutionY, *aData.resolutionUnit)};
74 
75   if (StaticPrefs::image_exif_density_correction_sanity_check_enabled()) {
76     if (!aData.pixelXDimension || !aData.pixelYDimension) {
77       return {};
78     }
79 
80     const gfx::IntSize exifSize(*aData.pixelXDimension, *aData.pixelYDimension);
81 
82     gfx::IntSize scaledSize = aRealImageSize;
83     resolution.ApplyTo(scaledSize.width, scaledSize.height);
84 
85     if (exifSize != scaledSize) {
86       return {};
87     }
88   }
89 
90   return resolution;
91 }
92 
93 /////////////////////////////////////////////////////////////
94 // Parse EXIF data, typically found in a JPEG's APP1 segment.
95 /////////////////////////////////////////////////////////////
ParseEXIF(const uint8_t * aData,const uint32_t aLength,const gfx::IntSize & aRealImageSize)96 EXIFData EXIFParser::ParseEXIF(const uint8_t* aData, const uint32_t aLength,
97                                const gfx::IntSize& aRealImageSize) {
98   if (!Initialize(aData, aLength)) {
99     return EXIFData();
100   }
101 
102   if (!ParseEXIFHeader()) {
103     return EXIFData();
104   }
105 
106   uint32_t offsetIFD;
107   if (!ParseTIFFHeader(offsetIFD)) {
108     return EXIFData();
109   }
110 
111   JumpTo(offsetIFD);
112 
113   ParsedEXIFData data;
114   ParseIFD(data);
115 
116   return EXIFData{data.orientation,
117                   ResolutionFromParsedData(data, aRealImageSize)};
118 }
119 
120 /////////////////////////////////////////////////////////
121 // Parse the EXIF header. (Section 4.7.2, Figure 30)
122 /////////////////////////////////////////////////////////
ParseEXIFHeader()123 bool EXIFParser::ParseEXIFHeader() {
124   return MatchString(EXIFHeader, EXIFHeaderLength);
125 }
126 
127 /////////////////////////////////////////////////////////
128 // Parse the TIFF header. (Section 4.5.2, Table 1)
129 /////////////////////////////////////////////////////////
ParseTIFFHeader(uint32_t & aIFD0OffsetOut)130 bool EXIFParser::ParseTIFFHeader(uint32_t& aIFD0OffsetOut) {
131   // Determine byte order.
132   if (MatchString("MM\0*", 4)) {
133     mByteOrder = ByteOrder::BigEndian;
134   } else if (MatchString("II*\0", 4)) {
135     mByteOrder = ByteOrder::LittleEndian;
136   } else {
137     return false;
138   }
139 
140   // Determine offset of the 0th IFD. (It shouldn't be greater than 64k, which
141   // is the maximum size of the entry APP1 segment.)
142   uint32_t ifd0Offset;
143   if (!ReadUInt32(ifd0Offset) || ifd0Offset > 64 * 1024) {
144     return false;
145   }
146 
147   // The IFD offset is relative to the beginning of the TIFF header, which
148   // begins after the EXIF header, so we need to increase the offset
149   // appropriately.
150   aIFD0OffsetOut = ifd0Offset + TIFFHeaderStart;
151   return true;
152 }
153 
154 // An arbitrary limit on the amount of pointers that we'll chase, to prevent bad
155 // inputs getting us stuck.
156 constexpr uint32_t kMaxEXIFDepth = 16;
157 
158 /////////////////////////////////////////////////////////
159 // Parse the entries in IFD0. (Section 4.6.2)
160 /////////////////////////////////////////////////////////
ParseIFD(ParsedEXIFData & aData,uint32_t aDepth)161 void EXIFParser::ParseIFD(ParsedEXIFData& aData, uint32_t aDepth) {
162   if (NS_WARN_IF(aDepth > kMaxEXIFDepth)) {
163     return;
164   }
165 
166   uint16_t entryCount;
167   if (!ReadUInt16(entryCount)) {
168     return;
169   }
170 
171   for (uint16_t entry = 0; entry < entryCount; ++entry) {
172     // Read the fields of the 12-byte entry.
173     uint16_t tag;
174     if (!ReadUInt16(tag)) {
175       return;
176     }
177 
178     uint16_t type;
179     if (!ReadUInt16(type)) {
180       return;
181     }
182 
183     uint32_t count;
184     if (!ReadUInt32(count)) {
185       return;
186     }
187 
188     switch (EXIFTag(tag)) {
189       case EXIFTag::Orientation:
190         // We should have an orientation value here; go ahead and parse it.
191         if (!ParseOrientation(type, count, aData.orientation)) {
192           return;
193         }
194         break;
195       case EXIFTag::ResolutionUnit:
196         if (!ParseResolutionUnit(type, count, aData.resolutionUnit)) {
197           return;
198         }
199         break;
200       case EXIFTag::XResolution:
201         if (!ParseResolution(type, count, aData.resolutionX)) {
202           return;
203         }
204         break;
205       case EXIFTag::YResolution:
206         if (!ParseResolution(type, count, aData.resolutionY)) {
207           return;
208         }
209         break;
210       case EXIFTag::PixelXDimension:
211         if (!ParseDimension(type, count, aData.pixelXDimension)) {
212           return;
213         }
214         break;
215       case EXIFTag::PixelYDimension:
216         if (!ParseDimension(type, count, aData.pixelYDimension)) {
217           return;
218         }
219         break;
220       case EXIFTag::IFDPointer: {
221         uint32_t offset;
222         if (!ReadUInt32(offset)) {
223           return;
224         }
225 
226         ScopedJump jump(*this, offset + TIFFHeaderStart);
227         ParseIFD(aData, aDepth + 1);
228         break;
229       }
230 
231       default:
232         Advance(4);
233         break;
234     }
235   }
236 }
237 
ReadRational(float & aOut)238 bool EXIFParser::ReadRational(float& aOut) {
239   // Values larger than 4 bytes (like rationals) are specified as an offset into
240   // the TIFF header.
241   uint32_t valueOffset;
242   if (!ReadUInt32(valueOffset)) {
243     return false;
244   }
245   ScopedJump jumpToHeader(*this, valueOffset + TIFFHeaderStart);
246   uint32_t numerator;
247   if (!ReadUInt32(numerator)) {
248     return false;
249   }
250   uint32_t denominator;
251   if (!ReadUInt32(denominator)) {
252     return false;
253   }
254   if (denominator == 0) {
255     return false;
256   }
257   aOut = float(numerator) / float(denominator);
258   return true;
259 }
260 
ParseResolution(uint16_t aType,uint32_t aCount,Maybe<float> & aOut)261 bool EXIFParser::ParseResolution(uint16_t aType, uint32_t aCount,
262                                  Maybe<float>& aOut) {
263   if (!StaticPrefs::image_exif_density_correction_enabled()) {
264     Advance(4);
265     return true;
266   }
267   if (aType != RationalType || aCount != 1) {
268     return false;
269   }
270   float value;
271   if (!ReadRational(value)) {
272     return false;
273   }
274   if (value == 0.0f) {
275     return false;
276   }
277   aOut = Some(value);
278   return true;
279 }
280 
ParseDimension(uint16_t aType,uint32_t aCount,Maybe<uint32_t> & aOut)281 bool EXIFParser::ParseDimension(uint16_t aType, uint32_t aCount,
282                                 Maybe<uint32_t>& aOut) {
283   if (!StaticPrefs::image_exif_density_correction_enabled()) {
284     Advance(4);
285     return true;
286   }
287 
288   if (aCount != 1) {
289     return false;
290   }
291 
292   switch (aType) {
293     case ShortType: {
294       uint16_t value;
295       if (!ReadUInt16(value)) {
296         return false;
297       }
298       aOut = Some(value);
299       Advance(2);
300       break;
301     }
302     case LongType: {
303       uint32_t value;
304       if (!ReadUInt32(value)) {
305         return false;
306       }
307       aOut = Some(value);
308       break;
309     }
310     default:
311       return false;
312   }
313   return true;
314 }
315 
ParseResolutionUnit(uint16_t aType,uint32_t aCount,Maybe<ResolutionUnit> & aOut)316 bool EXIFParser::ParseResolutionUnit(uint16_t aType, uint32_t aCount,
317                                      Maybe<ResolutionUnit>& aOut) {
318   if (!StaticPrefs::image_exif_density_correction_enabled()) {
319     Advance(4);
320     return true;
321   }
322   if (aType != ShortType || aCount != 1) {
323     return false;
324   }
325   uint16_t value;
326   if (!ReadUInt16(value)) {
327     return false;
328   }
329   switch (value) {
330     case 2:
331       aOut = Some(ResolutionUnit::Dpi);
332       break;
333     case 3:
334       aOut = Some(ResolutionUnit::Dpcm);
335       break;
336     default:
337       return false;
338   }
339 
340   // This is a 32-bit field, but the unit value only occupies the first 16 bits.
341   // We need to advance another 16 bits to consume the entire field.
342   Advance(2);
343   return true;
344 }
345 
ParseOrientation(uint16_t aType,uint32_t aCount,Orientation & aOut)346 bool EXIFParser::ParseOrientation(uint16_t aType, uint32_t aCount,
347                                   Orientation& aOut) {
348   // Sanity check the type and count.
349   if (aType != ShortType || aCount != 1) {
350     return false;
351   }
352 
353   uint16_t value;
354   if (!ReadUInt16(value)) {
355     return false;
356   }
357 
358   switch (value) {
359     case 1:
360       aOut = Orientation(Angle::D0, Flip::Unflipped);
361       break;
362     case 2:
363       aOut = Orientation(Angle::D0, Flip::Horizontal);
364       break;
365     case 3:
366       aOut = Orientation(Angle::D180, Flip::Unflipped);
367       break;
368     case 4:
369       aOut = Orientation(Angle::D180, Flip::Horizontal);
370       break;
371     case 5:
372       aOut = Orientation(Angle::D90, Flip::Horizontal);
373       break;
374     case 6:
375       aOut = Orientation(Angle::D90, Flip::Unflipped);
376       break;
377     case 7:
378       aOut = Orientation(Angle::D270, Flip::Horizontal);
379       break;
380     case 8:
381       aOut = Orientation(Angle::D270, Flip::Unflipped);
382       break;
383     default:
384       return false;
385   }
386 
387   // This is a 32-bit field, but the orientation value only occupies the first
388   // 16 bits. We need to advance another 16 bits to consume the entire field.
389   Advance(2);
390   return true;
391 }
392 
Initialize(const uint8_t * aData,const uint32_t aLength)393 bool EXIFParser::Initialize(const uint8_t* aData, const uint32_t aLength) {
394   if (aData == nullptr) {
395     return false;
396   }
397 
398   // An APP1 segment larger than 64k violates the JPEG standard.
399   if (aLength > 64 * 1024) {
400     return false;
401   }
402 
403   mStart = mCurrent = aData;
404   mLength = mRemainingLength = aLength;
405   mByteOrder = ByteOrder::Unknown;
406   return true;
407 }
408 
Advance(const uint32_t aDistance)409 void EXIFParser::Advance(const uint32_t aDistance) {
410   if (mRemainingLength >= aDistance) {
411     mCurrent += aDistance;
412     mRemainingLength -= aDistance;
413   } else {
414     mCurrent = mStart;
415     mRemainingLength = 0;
416   }
417 }
418 
JumpTo(const uint32_t aOffset)419 void EXIFParser::JumpTo(const uint32_t aOffset) {
420   if (mLength >= aOffset) {
421     mCurrent = mStart + aOffset;
422     mRemainingLength = mLength - aOffset;
423   } else {
424     mCurrent = mStart;
425     mRemainingLength = 0;
426   }
427 }
428 
MatchString(const char * aString,const uint32_t aLength)429 bool EXIFParser::MatchString(const char* aString, const uint32_t aLength) {
430   if (mRemainingLength < aLength) {
431     return false;
432   }
433 
434   for (uint32_t i = 0; i < aLength; ++i) {
435     if (mCurrent[i] != aString[i]) {
436       return false;
437     }
438   }
439 
440   Advance(aLength);
441   return true;
442 }
443 
MatchUInt16(const uint16_t aValue)444 bool EXIFParser::MatchUInt16(const uint16_t aValue) {
445   if (mRemainingLength < 2) {
446     return false;
447   }
448 
449   bool matched;
450   switch (mByteOrder) {
451     case ByteOrder::LittleEndian:
452       matched = LittleEndian::readUint16(mCurrent) == aValue;
453       break;
454     case ByteOrder::BigEndian:
455       matched = BigEndian::readUint16(mCurrent) == aValue;
456       break;
457     default:
458       MOZ_ASSERT_UNREACHABLE("Should know the byte order by now");
459       matched = false;
460   }
461 
462   if (matched) {
463     Advance(2);
464   }
465 
466   return matched;
467 }
468 
ReadUInt16(uint16_t & aValue)469 bool EXIFParser::ReadUInt16(uint16_t& aValue) {
470   if (mRemainingLength < 2) {
471     return false;
472   }
473 
474   bool matched = true;
475   switch (mByteOrder) {
476     case ByteOrder::LittleEndian:
477       aValue = LittleEndian::readUint16(mCurrent);
478       break;
479     case ByteOrder::BigEndian:
480       aValue = BigEndian::readUint16(mCurrent);
481       break;
482     default:
483       MOZ_ASSERT_UNREACHABLE("Should know the byte order by now");
484       matched = false;
485   }
486 
487   if (matched) {
488     Advance(2);
489   }
490 
491   return matched;
492 }
493 
ReadUInt32(uint32_t & aValue)494 bool EXIFParser::ReadUInt32(uint32_t& aValue) {
495   if (mRemainingLength < 4) {
496     return false;
497   }
498 
499   bool matched = true;
500   switch (mByteOrder) {
501     case ByteOrder::LittleEndian:
502       aValue = LittleEndian::readUint32(mCurrent);
503       break;
504     case ByteOrder::BigEndian:
505       aValue = BigEndian::readUint32(mCurrent);
506       break;
507     default:
508       MOZ_ASSERT_UNREACHABLE("Should know the byte order by now");
509       matched = false;
510   }
511 
512   if (matched) {
513     Advance(4);
514   }
515 
516   return matched;
517 }
518 
519 }  // namespace mozilla::image
520