Coverage Report

Created: 2018-09-25 14:53

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