1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.camera.exif;
18 
19 import com.android.camera.debug.Log;
20 
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.nio.ByteOrder;
24 import java.nio.charset.Charset;
25 import java.util.Map.Entry;
26 import java.util.TreeMap;
27 
28 /**
29  * This class provides a low-level EXIF parsing API. Given a JPEG format
30  * InputStream, the caller can request which IFD's to read via
31  * {@link #parse(InputStream, int)} with given options.
32  * <p>
33  * Below is an example of getting EXIF data from IFD 0 and EXIF IFD using the
34  * parser.
35  *
36  * <pre>
37  * void parse() {
38  *     ExifParser parser = ExifParser.parse(mImageInputStream,
39  *             ExifParser.OPTION_IFD_0 | ExifParser.OPTIONS_IFD_EXIF);
40  *     int event = parser.next();
41  *     while (event != ExifParser.EVENT_END) {
42  *         switch (event) {
43  *             case ExifParser.EVENT_START_OF_IFD:
44  *                 break;
45  *             case ExifParser.EVENT_NEW_TAG:
46  *                 ExifTag tag = parser.getTag();
47  *                 if (!tag.hasValue()) {
48  *                     parser.registerForTagValue(tag);
49  *                 } else {
50  *                     processTag(tag);
51  *                 }
52  *                 break;
53  *             case ExifParser.EVENT_VALUE_OF_REGISTERED_TAG:
54  *                 tag = parser.getTag();
55  *                 if (tag.getDataType() != ExifTag.TYPE_UNDEFINED) {
56  *                     processTag(tag);
57  *                 }
58  *                 break;
59  *         }
60  *         event = parser.next();
61  *     }
62  * }
63  *
64  * void processTag(ExifTag tag) {
65  *     // process the tag as you like.
66  * }
67  * </pre>
68  */
69 class ExifParser {
70     private static final boolean LOGV = false;
71     private static final Log.Tag TAG = new Log.Tag("ExifParser");
72     /**
73      * When the parser reaches a new IFD area. Call {@link #getCurrentIfd()} to
74      * know which IFD we are in.
75      */
76     public static final int EVENT_START_OF_IFD = 0;
77     /**
78      * When the parser reaches a new tag. Call {@link #getTag()}to get the
79      * corresponding tag.
80      */
81     public static final int EVENT_NEW_TAG = 1;
82     /**
83      * When the parser reaches the value area of tag that is registered by
84      * {@link #registerForTagValue(ExifTag)} previously. Call {@link #getTag()}
85      * to get the corresponding tag.
86      */
87     public static final int EVENT_VALUE_OF_REGISTERED_TAG = 2;
88 
89     /**
90      * When the parser reaches the compressed image area.
91      */
92     public static final int EVENT_COMPRESSED_IMAGE = 3;
93     /**
94      * When the parser reaches the uncompressed image strip. Call
95      * {@link #getStripIndex()} to get the index of the strip.
96      *
97      * @see #getStripIndex()
98      * @see #getStripCount()
99      */
100     public static final int EVENT_UNCOMPRESSED_STRIP = 4;
101     /**
102      * When there is nothing more to parse.
103      */
104     public static final int EVENT_END = 5;
105 
106     /**
107      * Option bit to request to parse IFD0.
108      */
109     public static final int OPTION_IFD_0 = 1 << 0;
110     /**
111      * Option bit to request to parse IFD1.
112      */
113     public static final int OPTION_IFD_1 = 1 << 1;
114     /**
115      * Option bit to request to parse Exif-IFD.
116      */
117     public static final int OPTION_IFD_EXIF = 1 << 2;
118     /**
119      * Option bit to request to parse GPS-IFD.
120      */
121     public static final int OPTION_IFD_GPS = 1 << 3;
122     /**
123      * Option bit to request to parse Interoperability-IFD.
124      */
125     public static final int OPTION_IFD_INTEROPERABILITY = 1 << 4;
126     /**
127      * Option bit to request to parse thumbnail.
128      */
129     public static final int OPTION_THUMBNAIL = 1 << 5;
130 
131     protected static final int EXIF_HEADER = 0x45786966; // EXIF header "Exif"
132     protected static final short EXIF_HEADER_TAIL = (short) 0x0000; // EXIF header in APP1
133 
134     // TIFF header
135     protected static final short LITTLE_ENDIAN_TAG = (short) 0x4949; // "II"
136     protected static final short BIG_ENDIAN_TAG = (short) 0x4d4d; // "MM"
137     protected static final short TIFF_HEADER_TAIL = 0x002A;
138 
139     protected static final int TAG_SIZE = 12;
140     protected static final int OFFSET_SIZE = 2;
141 
142     private static final Charset US_ASCII = Charset.forName("US-ASCII");
143 
144     protected static final int DEFAULT_IFD0_OFFSET = 8;
145 
146     private final CountedDataInputStream mTiffStream;
147     private final int mOptions;
148     private int mIfdStartOffset = 0;
149     private int mNumOfTagInIfd = 0;
150     private int mIfdType;
151     private ExifTag mTag;
152     private ImageEvent mImageEvent;
153     private int mStripCount;
154     private ExifTag mStripSizeTag;
155     private ExifTag mJpegSizeTag;
156     private boolean mNeedToParseOffsetsInCurrentIfd;
157     private boolean mContainExifData = false;
158     private int mApp1End;
159     private int mOffsetToApp1EndFromSOF = 0;
160     private byte[] mDataAboveIfd0;
161     private int mIfd0Position;
162     private int mTiffStartPosition;
163     private final ExifInterface mInterface;
164 
165     private static final short TAG_EXIF_IFD = ExifInterface
166             .getTrueTagKey(ExifInterface.TAG_EXIF_IFD);
167     private static final short TAG_GPS_IFD = ExifInterface.getTrueTagKey(ExifInterface.TAG_GPS_IFD);
168     private static final short TAG_INTEROPERABILITY_IFD = ExifInterface
169             .getTrueTagKey(ExifInterface.TAG_INTEROPERABILITY_IFD);
170     private static final short TAG_JPEG_INTERCHANGE_FORMAT = ExifInterface
171             .getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT);
172     private static final short TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = ExifInterface
173             .getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
174     private static final short TAG_STRIP_OFFSETS = ExifInterface
175             .getTrueTagKey(ExifInterface.TAG_STRIP_OFFSETS);
176     private static final short TAG_STRIP_BYTE_COUNTS = ExifInterface
177             .getTrueTagKey(ExifInterface.TAG_STRIP_BYTE_COUNTS);
178 
179     private final TreeMap<Integer, Object> mCorrespondingEvent = new TreeMap<Integer, Object>();
180 
isIfdRequested(int ifdType)181     private boolean isIfdRequested(int ifdType) {
182         switch (ifdType) {
183             case IfdId.TYPE_IFD_0:
184                 return (mOptions & OPTION_IFD_0) != 0;
185             case IfdId.TYPE_IFD_1:
186                 return (mOptions & OPTION_IFD_1) != 0;
187             case IfdId.TYPE_IFD_EXIF:
188                 return (mOptions & OPTION_IFD_EXIF) != 0;
189             case IfdId.TYPE_IFD_GPS:
190                 return (mOptions & OPTION_IFD_GPS) != 0;
191             case IfdId.TYPE_IFD_INTEROPERABILITY:
192                 return (mOptions & OPTION_IFD_INTEROPERABILITY) != 0;
193         }
194         return false;
195     }
196 
isThumbnailRequested()197     private boolean isThumbnailRequested() {
198         return (mOptions & OPTION_THUMBNAIL) != 0;
199     }
200 
ExifParser(InputStream inputStream, int options, ExifInterface iRef)201     private ExifParser(InputStream inputStream, int options, ExifInterface iRef)
202             throws IOException, ExifInvalidFormatException {
203         if (inputStream == null) {
204             throw new IOException("Null argument inputStream to ExifParser");
205         }
206         if (LOGV) {
207             Log.v(TAG, "Reading exif...");
208         }
209         mInterface = iRef;
210         mContainExifData = seekTiffData(inputStream);
211         mTiffStream = new CountedDataInputStream(inputStream);
212         mOptions = options;
213         if (!mContainExifData) {
214             return;
215         }
216 
217         parseTiffHeader();
218         long offset = mTiffStream.readUnsignedInt();
219         if (offset > Integer.MAX_VALUE) {
220             throw new ExifInvalidFormatException("Invalid offset " + offset);
221         }
222         mIfd0Position = (int) offset;
223         mIfdType = IfdId.TYPE_IFD_0;
224         if (isIfdRequested(IfdId.TYPE_IFD_0) || needToParseOffsetsInCurrentIfd()) {
225             registerIfd(IfdId.TYPE_IFD_0, offset);
226             if (offset != DEFAULT_IFD0_OFFSET) {
227                 mDataAboveIfd0 = new byte[(int) offset - DEFAULT_IFD0_OFFSET];
228                 read(mDataAboveIfd0);
229             }
230         }
231     }
232 
233     /**
234      * Parses the the given InputStream with the given options
235      *
236      * @exception IOException
237      * @exception ExifInvalidFormatException
238      */
parse(InputStream inputStream, int options, ExifInterface iRef)239     protected static ExifParser parse(InputStream inputStream, int options, ExifInterface iRef)
240             throws IOException, ExifInvalidFormatException {
241         return new ExifParser(inputStream, options, iRef);
242     }
243 
244     /**
245      * Parses the the given InputStream with default options; that is, every IFD
246      * and thumbnaill will be parsed.
247      *
248      * @exception IOException
249      * @exception ExifInvalidFormatException
250      * @see #parse(InputStream, int)
251      */
parse(InputStream inputStream, ExifInterface iRef)252     protected static ExifParser parse(InputStream inputStream, ExifInterface iRef)
253             throws IOException, ExifInvalidFormatException {
254         return new ExifParser(inputStream, OPTION_IFD_0 | OPTION_IFD_1
255                 | OPTION_IFD_EXIF | OPTION_IFD_GPS | OPTION_IFD_INTEROPERABILITY
256                 | OPTION_THUMBNAIL, iRef);
257     }
258 
259     /**
260      * Moves the parser forward and returns the next parsing event
261      *
262      * @exception IOException
263      * @exception ExifInvalidFormatException
264      * @see #EVENT_START_OF_IFD
265      * @see #EVENT_NEW_TAG
266      * @see #EVENT_VALUE_OF_REGISTERED_TAG
267      * @see #EVENT_COMPRESSED_IMAGE
268      * @see #EVENT_UNCOMPRESSED_STRIP
269      * @see #EVENT_END
270      */
next()271     protected int next() throws IOException, ExifInvalidFormatException {
272         if (!mContainExifData) {
273             return EVENT_END;
274         }
275         int offset = mTiffStream.getReadByteCount();
276         int endOfTags = mIfdStartOffset + OFFSET_SIZE + TAG_SIZE * mNumOfTagInIfd;
277         if (offset < endOfTags) {
278             mTag = readTag();
279             if (mTag == null) {
280                 return next();
281             }
282             if (mNeedToParseOffsetsInCurrentIfd) {
283                 checkOffsetOrImageTag(mTag);
284             }
285             return EVENT_NEW_TAG;
286         } else if (offset == endOfTags) {
287             // There is a link to ifd1 at the end of ifd0
288             if (mIfdType == IfdId.TYPE_IFD_0) {
289                 long ifdOffset = readUnsignedLong();
290                 if (isIfdRequested(IfdId.TYPE_IFD_1) || isThumbnailRequested()) {
291                     if (ifdOffset != 0) {
292                         registerIfd(IfdId.TYPE_IFD_1, ifdOffset);
293                     }
294                 }
295             } else {
296                 int offsetSize = 4;
297                 // Some camera models use invalid length of the offset
298                 if (mCorrespondingEvent.size() > 0) {
299                     offsetSize = mCorrespondingEvent.firstEntry().getKey() -
300                             mTiffStream.getReadByteCount();
301                 }
302                 if (offsetSize < 4) {
303                     Log.w(TAG, "Invalid size of link to next IFD: " + offsetSize);
304                 } else {
305                     long ifdOffset = readUnsignedLong();
306                     if (ifdOffset != 0) {
307                         Log.w(TAG, "Invalid link to next IFD: " + ifdOffset);
308                     }
309                 }
310             }
311         }
312         while (mCorrespondingEvent.size() != 0) {
313             Entry<Integer, Object> entry = mCorrespondingEvent.pollFirstEntry();
314             Object event = entry.getValue();
315             try {
316                 skipTo(entry.getKey());
317             } catch (IOException e) {
318                 Log.w(TAG, "Failed to skip to data at: " + entry.getKey() +
319                         " for " + event.getClass().getName() + ", the file may be broken.");
320                 continue;
321             }
322             if (event instanceof IfdEvent) {
323                 mIfdType = ((IfdEvent) event).ifd;
324                 mNumOfTagInIfd = mTiffStream.readUnsignedShort();
325                 mIfdStartOffset = entry.getKey();
326 
327                 if (mNumOfTagInIfd * TAG_SIZE + mIfdStartOffset + OFFSET_SIZE > mApp1End) {
328                     Log.w(TAG, "Invalid size of IFD " + mIfdType);
329                     return EVENT_END;
330                 }
331 
332                 mNeedToParseOffsetsInCurrentIfd = needToParseOffsetsInCurrentIfd();
333                 if (((IfdEvent) event).isRequested) {
334                     return EVENT_START_OF_IFD;
335                 } else {
336                     skipRemainingTagsInCurrentIfd();
337                 }
338             } else if (event instanceof ImageEvent) {
339                 mImageEvent = (ImageEvent) event;
340                 return mImageEvent.type;
341             } else {
342                 ExifTagEvent tagEvent = (ExifTagEvent) event;
343                 mTag = tagEvent.tag;
344                 if (mTag.getDataType() != ExifTag.TYPE_UNDEFINED) {
345                     readFullTagValue(mTag);
346                     checkOffsetOrImageTag(mTag);
347                 }
348                 if (tagEvent.isRequested) {
349                     return EVENT_VALUE_OF_REGISTERED_TAG;
350                 }
351             }
352         }
353         return EVENT_END;
354     }
355 
356     /**
357      * Skips the tags area of current IFD, if the parser is not in the tag area,
358      * nothing will happen.
359      *
360      * @throws IOException
361      * @throws ExifInvalidFormatException
362      */
skipRemainingTagsInCurrentIfd()363     protected void skipRemainingTagsInCurrentIfd() throws IOException, ExifInvalidFormatException {
364         int endOfTags = mIfdStartOffset + OFFSET_SIZE + TAG_SIZE * mNumOfTagInIfd;
365         int offset = mTiffStream.getReadByteCount();
366         if (offset > endOfTags) {
367             return;
368         }
369         if (mNeedToParseOffsetsInCurrentIfd) {
370             while (offset < endOfTags) {
371                 mTag = readTag();
372                 offset += TAG_SIZE;
373                 if (mTag == null) {
374                     continue;
375                 }
376                 checkOffsetOrImageTag(mTag);
377             }
378         } else {
379             skipTo(endOfTags);
380         }
381         long ifdOffset = readUnsignedLong();
382         // For ifd0, there is a link to ifd1 in the end of all tags
383         if (mIfdType == IfdId.TYPE_IFD_0
384                 && (isIfdRequested(IfdId.TYPE_IFD_1) || isThumbnailRequested())) {
385             if (ifdOffset > 0) {
386                 registerIfd(IfdId.TYPE_IFD_1, ifdOffset);
387             }
388         }
389     }
390 
needToParseOffsetsInCurrentIfd()391     private boolean needToParseOffsetsInCurrentIfd() {
392         switch (mIfdType) {
393             case IfdId.TYPE_IFD_0:
394                 return isIfdRequested(IfdId.TYPE_IFD_EXIF) || isIfdRequested(IfdId.TYPE_IFD_GPS)
395                         || isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY)
396                         || isIfdRequested(IfdId.TYPE_IFD_1);
397             case IfdId.TYPE_IFD_1:
398                 return isThumbnailRequested();
399             case IfdId.TYPE_IFD_EXIF:
400                 // The offset to interoperability IFD is located in Exif IFD
401                 return isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY);
402             default:
403                 return false;
404         }
405     }
406 
407     /**
408      * If {@link #next()} return {@link #EVENT_NEW_TAG} or
409      * {@link #EVENT_VALUE_OF_REGISTERED_TAG}, call this function to get the
410      * corresponding tag.
411      * <p>
412      * For {@link #EVENT_NEW_TAG}, the tag may not contain the value if the size
413      * of the value is greater than 4 bytes. One should call
414      * {@link ExifTag#hasValue()} to check if the tag contains value. If there
415      * is no value,call {@link #registerForTagValue(ExifTag)} to have the parser
416      * emit {@link #EVENT_VALUE_OF_REGISTERED_TAG} when it reaches the area
417      * pointed by the offset.
418      * <p>
419      * When {@link #EVENT_VALUE_OF_REGISTERED_TAG} is emitted, the value of the
420      * tag will have already been read except for tags of undefined type. For
421      * tags of undefined type, call one of the read methods to get the value.
422      *
423      * @see #registerForTagValue(ExifTag)
424      * @see #read(byte[])
425      * @see #read(byte[], int, int)
426      * @see #readLong()
427      * @see #readRational()
428      * @see #readString(int)
429      * @see #readString(int, Charset)
430      */
getTag()431     protected ExifTag getTag() {
432         return mTag;
433     }
434 
435     /**
436      * Gets number of tags in the current IFD area.
437      */
getTagCountInCurrentIfd()438     protected int getTagCountInCurrentIfd() {
439         return mNumOfTagInIfd;
440     }
441 
442     /**
443      * Gets the ID of current IFD.
444      *
445      * @see IfdId#TYPE_IFD_0
446      * @see IfdId#TYPE_IFD_1
447      * @see IfdId#TYPE_IFD_GPS
448      * @see IfdId#TYPE_IFD_INTEROPERABILITY
449      * @see IfdId#TYPE_IFD_EXIF
450      */
getCurrentIfd()451     protected int getCurrentIfd() {
452         return mIfdType;
453     }
454 
455     /**
456      * When receiving {@link #EVENT_UNCOMPRESSED_STRIP}, call this function to
457      * get the index of this strip.
458      *
459      * @see #getStripCount()
460      */
getStripIndex()461     protected int getStripIndex() {
462         return mImageEvent.stripIndex;
463     }
464 
465     /**
466      * When receiving {@link #EVENT_UNCOMPRESSED_STRIP}, call this function to
467      * get the number of strip data.
468      *
469      * @see #getStripIndex()
470      */
getStripCount()471     protected int getStripCount() {
472         return mStripCount;
473     }
474 
475     /**
476      * When receiving {@link #EVENT_UNCOMPRESSED_STRIP}, call this function to
477      * get the strip size.
478      */
getStripSize()479     protected int getStripSize() {
480         if (mStripSizeTag == null)
481             return 0;
482         return (int) mStripSizeTag.getValueAt(0);
483     }
484 
485     /**
486      * When receiving {@link #EVENT_COMPRESSED_IMAGE}, call this function to get
487      * the image data size.
488      */
getCompressedImageSize()489     protected int getCompressedImageSize() {
490         if (mJpegSizeTag == null) {
491             return 0;
492         }
493         return (int) mJpegSizeTag.getValueAt(0);
494     }
495 
skipTo(int offset)496     private void skipTo(int offset) throws IOException {
497         mTiffStream.skipTo(offset);
498         while (!mCorrespondingEvent.isEmpty() && mCorrespondingEvent.firstKey() < offset) {
499             mCorrespondingEvent.pollFirstEntry();
500         }
501     }
502 
503     /**
504      * When getting {@link #EVENT_NEW_TAG} in the tag area of IFD, the tag may
505      * not contain the value if the size of the value is greater than 4 bytes.
506      * When the value is not available here, call this method so that the parser
507      * will emit {@link #EVENT_VALUE_OF_REGISTERED_TAG} when it reaches the area
508      * where the value is located.
509      *
510      * @see #EVENT_VALUE_OF_REGISTERED_TAG
511      */
registerForTagValue(ExifTag tag)512     protected void registerForTagValue(ExifTag tag) {
513         if (tag.getOffset() >= mTiffStream.getReadByteCount()) {
514             mCorrespondingEvent.put(tag.getOffset(), new ExifTagEvent(tag, true));
515         }
516     }
517 
registerIfd(int ifdType, long offset)518     private void registerIfd(int ifdType, long offset) {
519         // Cast unsigned int to int since the offset is always smaller
520         // than the size of APP1 (65536)
521         mCorrespondingEvent.put((int) offset, new IfdEvent(ifdType, isIfdRequested(ifdType)));
522     }
523 
registerCompressedImage(long offset)524     private void registerCompressedImage(long offset) {
525         mCorrespondingEvent.put((int) offset, new ImageEvent(EVENT_COMPRESSED_IMAGE));
526     }
527 
registerUncompressedStrip(int stripIndex, long offset)528     private void registerUncompressedStrip(int stripIndex, long offset) {
529         mCorrespondingEvent.put((int) offset, new ImageEvent(EVENT_UNCOMPRESSED_STRIP
530                 , stripIndex));
531     }
532 
readTag()533     private ExifTag readTag() throws IOException, ExifInvalidFormatException {
534         short tagId = mTiffStream.readShort();
535         short dataFormat = mTiffStream.readShort();
536         long numOfComp = mTiffStream.readUnsignedInt();
537         if (numOfComp > Integer.MAX_VALUE) {
538             throw new ExifInvalidFormatException(
539                     "Number of component is larger then Integer.MAX_VALUE");
540         }
541         // Some invalid image file contains invalid data type. Ignore those tags
542         if (!ExifTag.isValidType(dataFormat)) {
543             Log.w(TAG, String.format("Tag %04x: Invalid data type %d", tagId, dataFormat));
544             mTiffStream.skip(4);
545             return null;
546         }
547         // TODO: handle numOfComp overflow
548         ExifTag tag = new ExifTag(tagId, dataFormat, (int) numOfComp, mIfdType,
549                 ((int) numOfComp) != ExifTag.SIZE_UNDEFINED);
550         int dataSize = tag.getDataSize();
551         if (dataSize > 4) {
552             long offset = mTiffStream.readUnsignedInt();
553             if (offset > Integer.MAX_VALUE) {
554                 throw new ExifInvalidFormatException(
555                         "offset is larger then Integer.MAX_VALUE");
556             }
557             // Some invalid images put some undefined data before IFD0.
558             // Read the data here.
559             if ((offset < mIfd0Position) && (dataFormat == ExifTag.TYPE_UNDEFINED)) {
560                 byte[] buf = new byte[(int) numOfComp];
561                 System.arraycopy(mDataAboveIfd0, (int) offset - DEFAULT_IFD0_OFFSET,
562                         buf, 0, (int) numOfComp);
563                 tag.setValue(buf);
564             } else {
565                 tag.setOffset((int) offset);
566             }
567         } else {
568             boolean defCount = tag.hasDefinedCount();
569             // Set defined count to 0 so we can add \0 to non-terminated strings
570             tag.setHasDefinedCount(false);
571             // Read value
572             readFullTagValue(tag);
573             tag.setHasDefinedCount(defCount);
574             mTiffStream.skip(4 - dataSize);
575             // Set the offset to the position of value.
576             tag.setOffset(mTiffStream.getReadByteCount() - 4);
577         }
578         return tag;
579     }
580 
581     /**
582      * Check the tag, if the tag is one of the offset tag that points to the IFD
583      * or image the caller is interested in, register the IFD or image.
584      */
checkOffsetOrImageTag(ExifTag tag)585     private void checkOffsetOrImageTag(ExifTag tag) {
586         // Some invalid formattd image contains tag with 0 size.
587         if (tag.getComponentCount() == 0) {
588             return;
589         }
590         short tid = tag.getTagId();
591         int ifd = tag.getIfd();
592         if (tid == TAG_EXIF_IFD && checkAllowed(ifd, ExifInterface.TAG_EXIF_IFD)) {
593             if (isIfdRequested(IfdId.TYPE_IFD_EXIF)
594                     || isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY)) {
595                 registerIfd(IfdId.TYPE_IFD_EXIF, tag.getValueAt(0));
596             }
597         } else if (tid == TAG_GPS_IFD && checkAllowed(ifd, ExifInterface.TAG_GPS_IFD)) {
598             if (isIfdRequested(IfdId.TYPE_IFD_GPS)) {
599                 registerIfd(IfdId.TYPE_IFD_GPS, tag.getValueAt(0));
600             }
601         } else if (tid == TAG_INTEROPERABILITY_IFD
602                 && checkAllowed(ifd, ExifInterface.TAG_INTEROPERABILITY_IFD)) {
603             if (isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY)) {
604                 registerIfd(IfdId.TYPE_IFD_INTEROPERABILITY, tag.getValueAt(0));
605             }
606         } else if (tid == TAG_JPEG_INTERCHANGE_FORMAT
607                 && checkAllowed(ifd, ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT)) {
608             if (isThumbnailRequested()) {
609                 registerCompressedImage(tag.getValueAt(0));
610             }
611         } else if (tid == TAG_JPEG_INTERCHANGE_FORMAT_LENGTH
612                 && checkAllowed(ifd, ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH)) {
613             if (isThumbnailRequested()) {
614                 mJpegSizeTag = tag;
615             }
616         } else if (tid == TAG_STRIP_OFFSETS && checkAllowed(ifd, ExifInterface.TAG_STRIP_OFFSETS)) {
617             if (isThumbnailRequested()) {
618                 if (tag.hasValue()) {
619                     for (int i = 0; i < tag.getComponentCount(); i++) {
620                         if (tag.getDataType() == ExifTag.TYPE_UNSIGNED_SHORT) {
621                             registerUncompressedStrip(i, tag.getValueAt(i));
622                         } else {
623                             registerUncompressedStrip(i, tag.getValueAt(i));
624                         }
625                     }
626                 } else {
627                     mCorrespondingEvent.put(tag.getOffset(), new ExifTagEvent(tag, false));
628                 }
629             }
630         } else if (tid == TAG_STRIP_BYTE_COUNTS
631                 && checkAllowed(ifd, ExifInterface.TAG_STRIP_BYTE_COUNTS)
632                 &&isThumbnailRequested() && tag.hasValue()) {
633             mStripSizeTag = tag;
634         }
635     }
636 
checkAllowed(int ifd, int tagId)637     private boolean checkAllowed(int ifd, int tagId) {
638         int info = mInterface.getTagInfo().get(tagId);
639         if (info == ExifInterface.DEFINITION_NULL) {
640             return false;
641         }
642         return ExifInterface.isIfdAllowed(info, ifd);
643     }
644 
readFullTagValue(ExifTag tag)645     protected void readFullTagValue(ExifTag tag) throws IOException {
646         // Some invalid images contains tags with wrong size, check it here
647         short type = tag.getDataType();
648         if (type == ExifTag.TYPE_ASCII || type == ExifTag.TYPE_UNDEFINED ||
649                 type == ExifTag.TYPE_UNSIGNED_BYTE) {
650             int size = tag.getComponentCount();
651             if (mCorrespondingEvent.size() > 0) {
652                 if (mCorrespondingEvent.firstEntry().getKey() < mTiffStream.getReadByteCount()
653                         + size) {
654                     Object event = mCorrespondingEvent.firstEntry().getValue();
655                     if (event instanceof ImageEvent) {
656                         // Tag value overlaps thumbnail, ignore thumbnail.
657                         Log.w(TAG, "Thumbnail overlaps value for tag: \n" + tag.toString());
658                         Entry<Integer, Object> entry = mCorrespondingEvent.pollFirstEntry();
659                         Log.w(TAG, "Invalid thumbnail offset: " + entry.getKey());
660                     } else {
661                         // Tag value overlaps another tag, shorten count
662                         if (event instanceof IfdEvent) {
663                             Log.w(TAG, "Ifd " + ((IfdEvent) event).ifd
664                                     + " overlaps value for tag: \n" + tag.toString());
665                         } else if (event instanceof ExifTagEvent) {
666                             Log.w(TAG, "Tag value for tag: \n"
667                                     + ((ExifTagEvent) event).tag.toString()
668                                     + " overlaps value for tag: \n" + tag.toString());
669                         }
670                         size = mCorrespondingEvent.firstEntry().getKey()
671                                 - mTiffStream.getReadByteCount();
672                         Log.w(TAG, "Invalid size of tag: \n" + tag.toString()
673                                 + " setting count to: " + size);
674                         tag.forceSetComponentCount(size);
675                     }
676                 }
677             }
678         }
679         switch (tag.getDataType()) {
680             case ExifTag.TYPE_UNSIGNED_BYTE:
681             case ExifTag.TYPE_UNDEFINED: {
682                 byte buf[] = new byte[tag.getComponentCount()];
683                 read(buf);
684                 tag.setValue(buf);
685             }
686                 break;
687             case ExifTag.TYPE_ASCII:
688                 tag.setValue(readString(tag.getComponentCount()));
689                 break;
690             case ExifTag.TYPE_UNSIGNED_LONG: {
691                 long value[] = new long[tag.getComponentCount()];
692                 for (int i = 0, n = value.length; i < n; i++) {
693                     value[i] = readUnsignedLong();
694                 }
695                 tag.setValue(value);
696             }
697                 break;
698             case ExifTag.TYPE_UNSIGNED_RATIONAL: {
699                 Rational value[] = new Rational[tag.getComponentCount()];
700                 for (int i = 0, n = value.length; i < n; i++) {
701                     value[i] = readUnsignedRational();
702                 }
703                 tag.setValue(value);
704             }
705                 break;
706             case ExifTag.TYPE_UNSIGNED_SHORT: {
707                 int value[] = new int[tag.getComponentCount()];
708                 for (int i = 0, n = value.length; i < n; i++) {
709                     value[i] = readUnsignedShort();
710                 }
711                 tag.setValue(value);
712             }
713                 break;
714             case ExifTag.TYPE_LONG: {
715                 int value[] = new int[tag.getComponentCount()];
716                 for (int i = 0, n = value.length; i < n; i++) {
717                     value[i] = readLong();
718                 }
719                 tag.setValue(value);
720             }
721                 break;
722             case ExifTag.TYPE_RATIONAL: {
723                 Rational value[] = new Rational[tag.getComponentCount()];
724                 for (int i = 0, n = value.length; i < n; i++) {
725                     value[i] = readRational();
726                 }
727                 tag.setValue(value);
728             }
729                 break;
730         }
731         if (LOGV) {
732             Log.v(TAG, "\n" + tag.toString());
733         }
734     }
735 
parseTiffHeader()736     private void parseTiffHeader() throws IOException,
737             ExifInvalidFormatException {
738         short byteOrder = mTiffStream.readShort();
739         if (LITTLE_ENDIAN_TAG == byteOrder) {
740             mTiffStream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
741         } else if (BIG_ENDIAN_TAG == byteOrder) {
742             mTiffStream.setByteOrder(ByteOrder.BIG_ENDIAN);
743         } else {
744             throw new ExifInvalidFormatException("Invalid TIFF header");
745         }
746 
747         if (mTiffStream.readShort() != TIFF_HEADER_TAIL) {
748             throw new ExifInvalidFormatException("Invalid TIFF header");
749         }
750     }
751 
seekTiffData(InputStream inputStream)752     private boolean seekTiffData(InputStream inputStream) throws IOException,
753             ExifInvalidFormatException {
754         CountedDataInputStream dataStream = new CountedDataInputStream(inputStream);
755         if (dataStream.readShort() != JpegHeader.SOI) {
756             throw new ExifInvalidFormatException("Invalid JPEG format");
757         }
758 
759         short marker = dataStream.readShort();
760         while (marker != JpegHeader.EOI
761                 && !JpegHeader.isSofMarker(marker)) {
762             int length = dataStream.readUnsignedShort();
763             // Some invalid formatted image contains multiple APP1,
764             // try to find the one with Exif data.
765             if (marker == JpegHeader.APP1) {
766                 int header = 0;
767                 short headerTail = 0;
768                 if (length >= 8) {
769                     header = dataStream.readInt();
770                     headerTail = dataStream.readShort();
771                     length -= 6;
772                     if (header == EXIF_HEADER && headerTail == EXIF_HEADER_TAIL) {
773                         mTiffStartPosition = dataStream.getReadByteCount();
774                         mApp1End = length;
775                         mOffsetToApp1EndFromSOF = mTiffStartPosition + mApp1End;
776                         return true;
777                     }
778                 }
779             }
780             if (length < 2 || (length - 2) != dataStream.skip(length - 2)) {
781                 Log.w(TAG, "Invalid JPEG format.");
782                 return false;
783             }
784             marker = dataStream.readShort();
785         }
786         return false;
787     }
788 
getOffsetToExifEndFromSOF()789     protected int getOffsetToExifEndFromSOF() {
790         return mOffsetToApp1EndFromSOF;
791     }
792 
getTiffStartPosition()793     protected int getTiffStartPosition() {
794         return mTiffStartPosition;
795     }
796 
797     /**
798      * Reads bytes from the InputStream.
799      */
read(byte[] buffer, int offset, int length)800     protected int read(byte[] buffer, int offset, int length) throws IOException {
801         return mTiffStream.read(buffer, offset, length);
802     }
803 
804     /**
805      * Equivalent to read(buffer, 0, buffer.length).
806      */
read(byte[] buffer)807     protected int read(byte[] buffer) throws IOException {
808         return mTiffStream.read(buffer);
809     }
810 
811     /**
812      * Reads a String from the InputStream with US-ASCII charset. The parser
813      * will read n bytes and convert it to ascii string. This is used for
814      * reading values of type {@link ExifTag#TYPE_ASCII}.
815      */
readString(int n)816     protected String readString(int n) throws IOException {
817         return readString(n, US_ASCII);
818     }
819 
820     /**
821      * Reads a String from the InputStream with the given charset. The parser
822      * will read n bytes and convert it to string. This is used for reading
823      * values of type {@link ExifTag#TYPE_ASCII}.
824      */
readString(int n, Charset charset)825     protected String readString(int n, Charset charset) throws IOException {
826         if (n > 0) {
827             return mTiffStream.readString(n, charset);
828         } else {
829             return "";
830         }
831     }
832 
833     /**
834      * Reads value of type {@link ExifTag#TYPE_UNSIGNED_SHORT} from the
835      * InputStream.
836      */
readUnsignedShort()837     protected int readUnsignedShort() throws IOException {
838         return mTiffStream.readShort() & 0xffff;
839     }
840 
841     /**
842      * Reads value of type {@link ExifTag#TYPE_UNSIGNED_LONG} from the
843      * InputStream.
844      */
readUnsignedLong()845     protected long readUnsignedLong() throws IOException {
846         return readLong() & 0xffffffffL;
847     }
848 
849     /**
850      * Reads value of type {@link ExifTag#TYPE_UNSIGNED_RATIONAL} from the
851      * InputStream.
852      */
readUnsignedRational()853     protected Rational readUnsignedRational() throws IOException {
854         long nomi = readUnsignedLong();
855         long denomi = readUnsignedLong();
856         return new Rational(nomi, denomi);
857     }
858 
859     /**
860      * Reads value of type {@link ExifTag#TYPE_LONG} from the InputStream.
861      */
readLong()862     protected int readLong() throws IOException {
863         return mTiffStream.readInt();
864     }
865 
866     /**
867      * Reads value of type {@link ExifTag#TYPE_RATIONAL} from the InputStream.
868      */
readRational()869     protected Rational readRational() throws IOException {
870         int nomi = readLong();
871         int denomi = readLong();
872         return new Rational(nomi, denomi);
873     }
874 
875     private static class ImageEvent {
876         int stripIndex;
877         int type;
878 
ImageEvent(int type)879         ImageEvent(int type) {
880             this.stripIndex = 0;
881             this.type = type;
882         }
883 
ImageEvent(int type, int stripIndex)884         ImageEvent(int type, int stripIndex) {
885             this.type = type;
886             this.stripIndex = stripIndex;
887         }
888     }
889 
890     private static class IfdEvent {
891         int ifd;
892         boolean isRequested;
893 
IfdEvent(int ifd, boolean isInterestedIfd)894         IfdEvent(int ifd, boolean isInterestedIfd) {
895             this.ifd = ifd;
896             this.isRequested = isInterestedIfd;
897         }
898     }
899 
900     private static class ExifTagEvent {
901         ExifTag tag;
902         boolean isRequested;
903 
ExifTagEvent(ExifTag tag, boolean isRequireByUser)904         ExifTagEvent(ExifTag tag, boolean isRequireByUser) {
905             this.tag = tag;
906             this.isRequested = isRequireByUser;
907         }
908     }
909 
910     /**
911      * Gets the byte order of the current InputStream.
912      */
getByteOrder()913     protected ByteOrder getByteOrder() {
914         return mTiffStream.getByteOrder();
915     }
916 }
917