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