|
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/Endian.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 { |
|
46 if (!Initialize(aData, aLength)) |
|
47 return EXIFData(); |
|
48 |
|
49 if (!ParseEXIFHeader()) |
|
50 return EXIFData(); |
|
51 |
|
52 uint32_t offsetIFD; |
|
53 if (!ParseTIFFHeader(offsetIFD)) |
|
54 return EXIFData(); |
|
55 |
|
56 JumpTo(offsetIFD); |
|
57 |
|
58 Orientation orientation; |
|
59 if (!ParseIFD0(orientation)) |
|
60 return EXIFData(); |
|
61 |
|
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); |
|
65 } |
|
66 |
|
67 ///////////////////////////////////////////////////////// |
|
68 // Parse the EXIF header. (Section 4.7.2, Figure 30) |
|
69 ///////////////////////////////////////////////////////// |
|
70 bool |
|
71 EXIFParser::ParseEXIFHeader() |
|
72 { |
|
73 return MatchString(EXIFHeader, EXIFHeaderLength); |
|
74 } |
|
75 |
|
76 ///////////////////////////////////////////////////////// |
|
77 // Parse the TIFF header. (Section 4.5.2, Table 1) |
|
78 ///////////////////////////////////////////////////////// |
|
79 bool |
|
80 EXIFParser::ParseTIFFHeader(uint32_t& aIFD0OffsetOut) |
|
81 { |
|
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; |
|
89 |
|
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; |
|
95 |
|
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; |
|
101 } |
|
102 |
|
103 ///////////////////////////////////////////////////////// |
|
104 // Parse the entries in IFD0. (Section 4.6.2) |
|
105 ///////////////////////////////////////////////////////// |
|
106 bool |
|
107 EXIFParser::ParseIFD0(Orientation& aOrientationOut) |
|
108 { |
|
109 uint16_t entryCount; |
|
110 if (!ReadUInt16(entryCount)) |
|
111 return false; |
|
112 |
|
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; |
|
118 |
|
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; |
|
124 } |
|
125 |
|
126 uint16_t type; |
|
127 if (!ReadUInt16(type)) |
|
128 return false; |
|
129 |
|
130 uint32_t count; |
|
131 if (!ReadUInt32(count)) |
|
132 return false; |
|
133 |
|
134 // We should have an orientation value here; go ahead and parse it. |
|
135 Orientation orientation; |
|
136 if (!ParseOrientation(type, count, aOrientationOut)) |
|
137 return false; |
|
138 |
|
139 // Since the orientation is all we care about, we're done. |
|
140 return true; |
|
141 } |
|
142 |
|
143 // We didn't find an orientation field in the IFD. That's OK; we assume the |
|
144 // default orientation in that case. |
|
145 aOrientationOut = Orientation(); |
|
146 return true; |
|
147 } |
|
148 |
|
149 bool |
|
150 EXIFParser::ParseOrientation(uint16_t aType, uint32_t aCount, Orientation& aOut) |
|
151 { |
|
152 // Sanity check the type and count. |
|
153 if (aType != ShortType || aCount != 1) |
|
154 return false; |
|
155 |
|
156 uint16_t value; |
|
157 if (!ReadUInt16(value)) |
|
158 return false; |
|
159 |
|
160 switch (value) { |
|
161 case 1: aOut = Orientation(Angle::D0, Flip::Unflipped); break; |
|
162 case 2: aOut = Orientation(Angle::D0, Flip::Horizontal); break; |
|
163 case 3: aOut = Orientation(Angle::D180, Flip::Unflipped); break; |
|
164 case 4: aOut = Orientation(Angle::D180, Flip::Horizontal); break; |
|
165 case 5: aOut = Orientation(Angle::D90, Flip::Horizontal); break; |
|
166 case 6: aOut = Orientation(Angle::D90, Flip::Unflipped); break; |
|
167 case 7: aOut = Orientation(Angle::D270, Flip::Horizontal); break; |
|
168 case 8: aOut = Orientation(Angle::D270, Flip::Unflipped); break; |
|
169 default: return false; |
|
170 } |
|
171 |
|
172 // This is a 32-bit field, but the orientation value only occupies the first |
|
173 // 16 bits. We need to advance another 16 bits to consume the entire field. |
|
174 Advance(2); |
|
175 return true; |
|
176 } |
|
177 |
|
178 bool |
|
179 EXIFParser::Initialize(const uint8_t* aData, const uint32_t aLength) |
|
180 { |
|
181 if (aData == nullptr) |
|
182 return false; |
|
183 |
|
184 // An APP1 segment larger than 64k violates the JPEG standard. |
|
185 if (aLength > 64 * 1024) |
|
186 return false; |
|
187 |
|
188 mStart = mCurrent = aData; |
|
189 mLength = mRemainingLength = aLength; |
|
190 mByteOrder = ByteOrder::Unknown; |
|
191 return true; |
|
192 } |
|
193 |
|
194 void |
|
195 EXIFParser::Advance(const uint32_t aDistance) |
|
196 { |
|
197 if (mRemainingLength >= aDistance) { |
|
198 mCurrent += aDistance; |
|
199 mRemainingLength -= aDistance; |
|
200 } else { |
|
201 mCurrent = mStart; |
|
202 mRemainingLength = 0; |
|
203 } |
|
204 } |
|
205 |
|
206 void |
|
207 EXIFParser::JumpTo(const uint32_t aOffset) |
|
208 { |
|
209 if (mLength >= aOffset) { |
|
210 mCurrent = mStart + aOffset; |
|
211 mRemainingLength = mLength - aOffset; |
|
212 } else { |
|
213 mCurrent = mStart; |
|
214 mRemainingLength = 0; |
|
215 } |
|
216 } |
|
217 |
|
218 bool |
|
219 EXIFParser::MatchString(const char* aString, const uint32_t aLength) |
|
220 { |
|
221 if (mRemainingLength < aLength) |
|
222 return false; |
|
223 |
|
224 for (uint32_t i = 0 ; i < aLength ; ++i) { |
|
225 if (mCurrent[i] != aString[i]) |
|
226 return false; |
|
227 } |
|
228 |
|
229 Advance(aLength); |
|
230 return true; |
|
231 } |
|
232 |
|
233 bool |
|
234 EXIFParser::MatchUInt16(const uint16_t aValue) |
|
235 { |
|
236 if (mRemainingLength < 2) |
|
237 return false; |
|
238 |
|
239 bool matched; |
|
240 switch (mByteOrder) { |
|
241 case ByteOrder::LittleEndian: |
|
242 matched = LittleEndian::readUint16(mCurrent) == aValue; |
|
243 break; |
|
244 case ByteOrder::BigEndian: |
|
245 matched = BigEndian::readUint16(mCurrent) == aValue; |
|
246 break; |
|
247 default: |
|
248 NS_NOTREACHED("Should know the byte order by now"); |
|
249 matched = false; |
|
250 } |
|
251 |
|
252 if (matched) |
|
253 Advance(2); |
|
254 |
|
255 return matched; |
|
256 } |
|
257 |
|
258 bool |
|
259 EXIFParser::ReadUInt16(uint16_t& aValue) |
|
260 { |
|
261 if (mRemainingLength < 2) |
|
262 return false; |
|
263 |
|
264 bool matched = true; |
|
265 switch (mByteOrder) { |
|
266 case ByteOrder::LittleEndian: |
|
267 aValue = LittleEndian::readUint16(mCurrent); |
|
268 break; |
|
269 case ByteOrder::BigEndian: |
|
270 aValue = BigEndian::readUint16(mCurrent); |
|
271 break; |
|
272 default: |
|
273 NS_NOTREACHED("Should know the byte order by now"); |
|
274 matched = false; |
|
275 } |
|
276 |
|
277 if (matched) |
|
278 Advance(2); |
|
279 |
|
280 return matched; |
|
281 } |
|
282 |
|
283 bool |
|
284 EXIFParser::ReadUInt32(uint32_t& aValue) |
|
285 { |
|
286 if (mRemainingLength < 4) |
|
287 return false; |
|
288 |
|
289 bool matched = true; |
|
290 switch (mByteOrder) { |
|
291 case ByteOrder::LittleEndian: |
|
292 aValue = LittleEndian::readUint32(mCurrent); |
|
293 break; |
|
294 case ByteOrder::BigEndian: |
|
295 aValue = BigEndian::readUint32(mCurrent); |
|
296 break; |
|
297 default: |
|
298 NS_NOTREACHED("Should know the byte order by now"); |
|
299 matched = false; |
|
300 } |
|
301 |
|
302 if (matched) |
|
303 Advance(4); |
|
304 |
|
305 return matched; |
|
306 } |
|
307 |
|
308 } // namespace image |
|
309 } // namespace mozilla |