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