Bumping manifests a=b2g-bump
[gecko.git] / image / decoders / EXIF.cpp
blob0a73c3fe6f74d085b390cf297dab20b707e2a7ed
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/. */
6 #include "EXIF.h"
8 #include "mozilla/Endian.h"
10 namespace mozilla {
11 namespace image {
13 // Section references in this file refer to the EXIF v2.3 standard, also known
14 // as CIPA DC-008-Translation-2010.
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
21 OrientationTag = 0x112,
24 // See Section 4.6.2.
25 enum EXIFType
27 ByteType = 1,
28 ASCIIType = 2,
29 ShortType = 3,
30 LongType = 4,
31 RationalType = 5,
32 UndefinedType = 7,
33 SignedLongType = 9,
34 SignedRational = 10,
37 static const char* EXIFHeader = "Exif\0\0";
38 static const uint32_t EXIFHeaderLength = 6;
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)
46 if (!Initialize(aData, aLength))
47 return EXIFData();
49 if (!ParseEXIFHeader())
50 return EXIFData();
52 uint32_t offsetIFD;
53 if (!ParseTIFFHeader(offsetIFD))
54 return EXIFData();
56 JumpTo(offsetIFD);
58 Orientation orientation;
59 if (!ParseIFD0(orientation))
60 return EXIFData();
62 // We only care about orientation at this point, so we don't bother with the
63 // other IFDs. If we got this far we're done.
64 return EXIFData(orientation);
67 /////////////////////////////////////////////////////////
68 // Parse the EXIF header. (Section 4.7.2, Figure 30)
69 /////////////////////////////////////////////////////////
70 bool
71 EXIFParser::ParseEXIFHeader()
73 return MatchString(EXIFHeader, EXIFHeaderLength);
76 /////////////////////////////////////////////////////////
77 // Parse the TIFF header. (Section 4.5.2, Table 1)
78 /////////////////////////////////////////////////////////
79 bool
80 EXIFParser::ParseTIFFHeader(uint32_t& aIFD0OffsetOut)
82 // Determine byte order.
83 if (MatchString("MM\0*", 4))
84 mByteOrder = ByteOrder::BigEndian;
85 else if (MatchString("II*\0", 4))
86 mByteOrder = ByteOrder::LittleEndian;
87 else
88 return false;
90 // Determine offset of the 0th IFD. (It shouldn't be greater than 64k, which
91 // is the maximum size of the entry APP1 segment.)
92 uint32_t ifd0Offset;
93 if (!ReadUInt32(ifd0Offset) || ifd0Offset > 64 * 1024)
94 return false;
96 // The IFD offset is relative to the beginning of the TIFF header, which
97 // begins after the EXIF header, so we need to increase the offset
98 // appropriately.
99 aIFD0OffsetOut = ifd0Offset + EXIFHeaderLength;
100 return true;
103 /////////////////////////////////////////////////////////
104 // Parse the entries in IFD0. (Section 4.6.2)
105 /////////////////////////////////////////////////////////
106 bool
107 EXIFParser::ParseIFD0(Orientation& aOrientationOut)
109 uint16_t entryCount;
110 if (!ReadUInt16(entryCount))
111 return false;
113 for (uint16_t entry = 0 ; entry < entryCount ; ++entry) {
114 // Read the fields of the entry.
115 uint16_t tag;
116 if (!ReadUInt16(tag))
117 return false;
119 // Right now, we only care about orientation, so we immediately skip to the
120 // next entry if we find anything else.
121 if (tag != OrientationTag) {
122 Advance(10);
123 continue;
126 uint16_t type;
127 if (!ReadUInt16(type))
128 return false;
130 uint32_t count;
131 if (!ReadUInt32(count))
132 return false;
134 // We should have an orientation value here; go ahead and parse it.
135 if (!ParseOrientation(type, count, aOrientationOut))
136 return false;
138 // Since the orientation is all we care about, we're done.
139 return true;
142 // We didn't find an orientation field in the IFD. That's OK; we assume the
143 // default orientation in that case.
144 aOrientationOut = Orientation();
145 return true;
148 bool
149 EXIFParser::ParseOrientation(uint16_t aType, uint32_t aCount, Orientation& aOut)
151 // Sanity check the type and count.
152 if (aType != ShortType || aCount != 1)
153 return false;
155 uint16_t value;
156 if (!ReadUInt16(value))
157 return false;
159 switch (value) {
160 case 1: aOut = Orientation(Angle::D0, Flip::Unflipped); break;
161 case 2: aOut = Orientation(Angle::D0, Flip::Horizontal); break;
162 case 3: aOut = Orientation(Angle::D180, Flip::Unflipped); break;
163 case 4: aOut = Orientation(Angle::D180, Flip::Horizontal); break;
164 case 5: aOut = Orientation(Angle::D90, Flip::Horizontal); break;
165 case 6: aOut = Orientation(Angle::D90, Flip::Unflipped); break;
166 case 7: aOut = Orientation(Angle::D270, Flip::Horizontal); break;
167 case 8: aOut = Orientation(Angle::D270, Flip::Unflipped); break;
168 default: return false;
171 // This is a 32-bit field, but the orientation value only occupies the first
172 // 16 bits. We need to advance another 16 bits to consume the entire field.
173 Advance(2);
174 return true;
177 bool
178 EXIFParser::Initialize(const uint8_t* aData, const uint32_t aLength)
180 if (aData == nullptr)
181 return false;
183 // An APP1 segment larger than 64k violates the JPEG standard.
184 if (aLength > 64 * 1024)
185 return false;
187 mStart = mCurrent = aData;
188 mLength = mRemainingLength = aLength;
189 mByteOrder = ByteOrder::Unknown;
190 return true;
193 void
194 EXIFParser::Advance(const uint32_t aDistance)
196 if (mRemainingLength >= aDistance) {
197 mCurrent += aDistance;
198 mRemainingLength -= aDistance;
199 } else {
200 mCurrent = mStart;
201 mRemainingLength = 0;
205 void
206 EXIFParser::JumpTo(const uint32_t aOffset)
208 if (mLength >= aOffset) {
209 mCurrent = mStart + aOffset;
210 mRemainingLength = mLength - aOffset;
211 } else {
212 mCurrent = mStart;
213 mRemainingLength = 0;
217 bool
218 EXIFParser::MatchString(const char* aString, const uint32_t aLength)
220 if (mRemainingLength < aLength)
221 return false;
223 for (uint32_t i = 0 ; i < aLength ; ++i) {
224 if (mCurrent[i] != aString[i])
225 return false;
228 Advance(aLength);
229 return true;
232 bool
233 EXIFParser::MatchUInt16(const uint16_t aValue)
235 if (mRemainingLength < 2)
236 return false;
238 bool matched;
239 switch (mByteOrder) {
240 case ByteOrder::LittleEndian:
241 matched = LittleEndian::readUint16(mCurrent) == aValue;
242 break;
243 case ByteOrder::BigEndian:
244 matched = BigEndian::readUint16(mCurrent) == aValue;
245 break;
246 default:
247 NS_NOTREACHED("Should know the byte order by now");
248 matched = false;
251 if (matched)
252 Advance(2);
254 return matched;
257 bool
258 EXIFParser::ReadUInt16(uint16_t& aValue)
260 if (mRemainingLength < 2)
261 return false;
263 bool matched = true;
264 switch (mByteOrder) {
265 case ByteOrder::LittleEndian:
266 aValue = LittleEndian::readUint16(mCurrent);
267 break;
268 case ByteOrder::BigEndian:
269 aValue = BigEndian::readUint16(mCurrent);
270 break;
271 default:
272 NS_NOTREACHED("Should know the byte order by now");
273 matched = false;
276 if (matched)
277 Advance(2);
279 return matched;
282 bool
283 EXIFParser::ReadUInt32(uint32_t& aValue)
285 if (mRemainingLength < 4)
286 return false;
288 bool matched = true;
289 switch (mByteOrder) {
290 case ByteOrder::LittleEndian:
291 aValue = LittleEndian::readUint32(mCurrent);
292 break;
293 case ByteOrder::BigEndian:
294 aValue = BigEndian::readUint32(mCurrent);
295 break;
296 default:
297 NS_NOTREACHED("Should know the byte order by now");
298 matched = false;
301 if (matched)
302 Advance(4);
304 return matched;
307 } // namespace image
308 } // namespace mozilla