173e933f1f57002d2e593aa7b471811d8837f8767Earl Ou/*
273e933f1f57002d2e593aa7b471811d8837f8767Earl Ou * Copyright (C) 2012 The Android Open Source Project
373e933f1f57002d2e593aa7b471811d8837f8767Earl Ou *
473e933f1f57002d2e593aa7b471811d8837f8767Earl Ou * Licensed under the Apache License, Version 2.0 (the "License");
573e933f1f57002d2e593aa7b471811d8837f8767Earl Ou * you may not use this file except in compliance with the License.
673e933f1f57002d2e593aa7b471811d8837f8767Earl Ou * You may obtain a copy of the License at
773e933f1f57002d2e593aa7b471811d8837f8767Earl Ou *
873e933f1f57002d2e593aa7b471811d8837f8767Earl Ou *      http://www.apache.org/licenses/LICENSE-2.0
973e933f1f57002d2e593aa7b471811d8837f8767Earl Ou *
1073e933f1f57002d2e593aa7b471811d8837f8767Earl Ou * Unless required by applicable law or agreed to in writing, software
1173e933f1f57002d2e593aa7b471811d8837f8767Earl Ou * distributed under the License is distributed on an "AS IS" BASIS,
1273e933f1f57002d2e593aa7b471811d8837f8767Earl Ou * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1373e933f1f57002d2e593aa7b471811d8837f8767Earl Ou * See the License for the specific language governing permissions and
1473e933f1f57002d2e593aa7b471811d8837f8767Earl Ou * limitations under the License.
1573e933f1f57002d2e593aa7b471811d8837f8767Earl Ou */
1673e933f1f57002d2e593aa7b471811d8837f8767Earl Ou
1773e933f1f57002d2e593aa7b471811d8837f8767Earl Oupackage com.android.gallery3d.exif;
1873e933f1f57002d2e593aa7b471811d8837f8767Earl Ou
19c83dab412a3babdc6012c95fe1f335cdf3102d7eEarl Ouimport android.util.Log;
20c83dab412a3babdc6012c95fe1f335cdf3102d7eEarl Ou
2173e933f1f57002d2e593aa7b471811d8837f8767Earl Ouimport java.io.IOException;
2273e933f1f57002d2e593aa7b471811d8837f8767Earl Ouimport java.io.InputStream;
2373e933f1f57002d2e593aa7b471811d8837f8767Earl Ouimport java.nio.ByteOrder;
244ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ouimport java.nio.charset.Charset;
254ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ouimport java.util.Map.Entry;
264ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ouimport java.util.TreeMap;
2773e933f1f57002d2e593aa7b471811d8837f8767Earl Ou
284ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou/**
296e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk * This class provides a low-level EXIF parsing API. Given a JPEG format
306e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk * InputStream, the caller can request which IFD's to read via
316e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk * {@link #parse(InputStream, int)} with given options.
324ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou * <p>
336e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk * Below is an example of getting EXIF data from IFD 0 and EXIF IFD using the
346e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk * parser.
356e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk *
364ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou * <pre>
374ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou * void parse() {
384ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou *     ExifParser parser = ExifParser.parse(mImageInputStream,
394ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou *             ExifParser.OPTION_IFD_0 | ExifParser.OPTIONS_IFD_EXIF);
404ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou *     int event = parser.next();
414ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou *     while (event != ExifParser.EVENT_END) {
424ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou *         switch (event) {
434ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou *             case ExifParser.EVENT_START_OF_IFD:
444ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou *                 break;
454ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou *             case ExifParser.EVENT_NEW_TAG:
464ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou *                 ExifTag tag = parser.getTag();
474ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou *                 if (!tag.hasValue()) {
484ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou *                     parser.registerForTagValue(tag);
494ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou *                 } else {
504ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou *                     processTag(tag);
514ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou *                 }
524ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou *                 break;
534ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou *             case ExifParser.EVENT_VALUE_OF_REGISTERED_TAG:
544ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou *                 tag = parser.getTag();
554ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou *                 if (tag.getDataType() != ExifTag.TYPE_UNDEFINED) {
564ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou *                     processTag(tag);
574ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou *                 }
584ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou *                 break;
594ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou *         }
604ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou *         event = parser.next();
614ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou *     }
624ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou * }
634ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou *
644ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou * void processTag(ExifTag tag) {
654ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou *     // process the tag as you like.
664ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou * }
674ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou * </pre>
684ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou */
696e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunkclass ExifParser {
706e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    private static final boolean LOGV = false;
71c83dab412a3babdc6012c95fe1f335cdf3102d7eEarl Ou    private static final String TAG = "ExifParser";
724ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    /**
736e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * When the parser reaches a new IFD area. Call {@link #getCurrentIfd()} to
746e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * know which IFD we are in.
754ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     */
764ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    public static final int EVENT_START_OF_IFD = 0;
774ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    /**
784ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * When the parser reaches a new tag. Call {@link #getTag()}to get the
794ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * corresponding tag.
804ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     */
814ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    public static final int EVENT_NEW_TAG = 1;
824ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    /**
834ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * When the parser reaches the value area of tag that is registered by
846e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * {@link #registerForTagValue(ExifTag)} previously. Call {@link #getTag()}
856e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * to get the corresponding tag.
864ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     */
874ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    public static final int EVENT_VALUE_OF_REGISTERED_TAG = 2;
8873e933f1f57002d2e593aa7b471811d8837f8767Earl Ou
894ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    /**
904ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * When the parser reaches the compressed image area.
914ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     */
924ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    public static final int EVENT_COMPRESSED_IMAGE = 3;
934ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    /**
946e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * When the parser reaches the uncompressed image strip. Call
956e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * {@link #getStripIndex()} to get the index of the strip.
966e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     *
974ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @see #getStripIndex()
984ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @see #getStripCount()
994ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     */
1004ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    public static final int EVENT_UNCOMPRESSED_STRIP = 4;
1014ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    /**
1024ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * When there is nothing more to parse.
1034ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     */
1044ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    public static final int EVENT_END = 5;
1054ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
1064ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    /**
1074ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * Option bit to request to parse IFD0.
1084ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     */
1094ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    public static final int OPTION_IFD_0 = 1 << 0;
1104ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    /**
1114ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * Option bit to request to parse IFD1.
1124ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     */
1134ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    public static final int OPTION_IFD_1 = 1 << 1;
1144ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    /**
1154ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * Option bit to request to parse Exif-IFD.
1164ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     */
1174ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    public static final int OPTION_IFD_EXIF = 1 << 2;
1184ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    /**
1194ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * Option bit to request to parse GPS-IFD.
1204ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     */
1214ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    public static final int OPTION_IFD_GPS = 1 << 3;
1224ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    /**
1234ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * Option bit to request to parse Interoperability-IFD.
1244ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     */
1254ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    public static final int OPTION_IFD_INTEROPERABILITY = 1 << 4;
1264ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    /**
1274ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * Option bit to request to parse thumbnail.
1284ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     */
1294ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    public static final int OPTION_THUMBNAIL = 1 << 5;
13073e933f1f57002d2e593aa7b471811d8837f8767Earl Ou
1316e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected static final int EXIF_HEADER = 0x45786966; // EXIF header "Exif"
1326e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected static final short EXIF_HEADER_TAIL = (short) 0x0000; // EXIF header in APP1
13373e933f1f57002d2e593aa7b471811d8837f8767Earl Ou
13473e933f1f57002d2e593aa7b471811d8837f8767Earl Ou    // TIFF header
1356e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected static final short LITTLE_ENDIAN_TAG = (short) 0x4949; // "II"
1366e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected static final short BIG_ENDIAN_TAG = (short) 0x4d4d; // "MM"
1376e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected static final short TIFF_HEADER_TAIL = 0x002A;
13873e933f1f57002d2e593aa7b471811d8837f8767Earl Ou
1396e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected static final int TAG_SIZE = 12;
1406e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected static final int OFFSET_SIZE = 2;
1414ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
1423357622665ec1757b120c16584fc7b67114c69ffEarl Ou    private static final Charset US_ASCII = Charset.forName("US-ASCII");
1433357622665ec1757b120c16584fc7b67114c69ffEarl Ou
1446e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected static final int DEFAULT_IFD0_OFFSET = 8;
14586ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou
146bdbf57f29db2c98dd2e0d05cd062c063fe90cd54Earl Ou    private final CountedDataInputStream mTiffStream;
1474ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    private final int mOptions;
1484ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    private int mIfdStartOffset = 0;
1494ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    private int mNumOfTagInIfd = 0;
1504ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    private int mIfdType;
1514ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    private ExifTag mTag;
1524ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    private ImageEvent mImageEvent;
1534ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    private int mStripCount;
1544ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    private ExifTag mStripSizeTag;
1554ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    private ExifTag mJpegSizeTag;
1564ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    private boolean mNeedToParseOffsetsInCurrentIfd;
1574cec566b34655e76b90f8ca089f151e6f42ede0cEarl Ou    private boolean mContainExifData = false;
15886ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou    private int mApp1End;
1596e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    private int mOffsetToApp1EndFromSOF = 0;
16086ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou    private byte[] mDataAboveIfd0;
16186ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou    private int mIfd0Position;
162b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou    private int mTiffStartPosition;
1636e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    private final ExifInterface mInterface;
1646e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk
1656e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    private static final short TAG_EXIF_IFD = ExifInterface
1666e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            .getTrueTagKey(ExifInterface.TAG_EXIF_IFD);
1676e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    private static final short TAG_GPS_IFD = ExifInterface.getTrueTagKey(ExifInterface.TAG_GPS_IFD);
1686e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    private static final short TAG_INTEROPERABILITY_IFD = ExifInterface
1696e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            .getTrueTagKey(ExifInterface.TAG_INTEROPERABILITY_IFD);
1706e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    private static final short TAG_JPEG_INTERCHANGE_FORMAT = ExifInterface
1716e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            .getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT);
1726e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    private static final short TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = ExifInterface
1736e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            .getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
1746e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    private static final short TAG_STRIP_OFFSETS = ExifInterface
1756e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            .getTrueTagKey(ExifInterface.TAG_STRIP_OFFSETS);
1766e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    private static final short TAG_STRIP_BYTE_COUNTS = ExifInterface
1776e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            .getTrueTagKey(ExifInterface.TAG_STRIP_BYTE_COUNTS);
1784ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
1794ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    private final TreeMap<Integer, Object> mCorrespondingEvent = new TreeMap<Integer, Object>();
1804ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
1814ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    private boolean isIfdRequested(int ifdType) {
1824ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        switch (ifdType) {
1834ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            case IfdId.TYPE_IFD_0:
1844ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                return (mOptions & OPTION_IFD_0) != 0;
1854ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            case IfdId.TYPE_IFD_1:
1864ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                return (mOptions & OPTION_IFD_1) != 0;
1874ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            case IfdId.TYPE_IFD_EXIF:
1884ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                return (mOptions & OPTION_IFD_EXIF) != 0;
1894ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            case IfdId.TYPE_IFD_GPS:
1904ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                return (mOptions & OPTION_IFD_GPS) != 0;
1914ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            case IfdId.TYPE_IFD_INTEROPERABILITY:
1924ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                return (mOptions & OPTION_IFD_INTEROPERABILITY) != 0;
1934ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        }
1944ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        return false;
1954ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
1964ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
1974ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    private boolean isThumbnailRequested() {
1984ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        return (mOptions & OPTION_THUMBNAIL) != 0;
1994ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
2004ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
2016e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    private ExifParser(InputStream inputStream, int options, ExifInterface iRef)
2024ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            throws IOException, ExifInvalidFormatException {
203aeb7d79d2a35f534276bc6bf8128349f9768ae6bRuben Brunk        if (inputStream == null) {
204aeb7d79d2a35f534276bc6bf8128349f9768ae6bRuben Brunk            throw new IOException("Null argument inputStream to ExifParser");
205aeb7d79d2a35f534276bc6bf8128349f9768ae6bRuben Brunk        }
2066e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        if (LOGV) {
2076e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            Log.v(TAG, "Reading exif...");
2086e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        }
2096e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        mInterface = iRef;
2104cec566b34655e76b90f8ca089f151e6f42ede0cEarl Ou        mContainExifData = seekTiffData(inputStream);
211bdbf57f29db2c98dd2e0d05cd062c063fe90cd54Earl Ou        mTiffStream = new CountedDataInputStream(inputStream);
2124ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        mOptions = options;
2136e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        if (!mContainExifData) {
2146e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            return;
2156e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        }
21686ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou
21786ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou        parseTiffHeader();
21886ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou        long offset = mTiffStream.readUnsignedInt();
21986ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou        if (offset > Integer.MAX_VALUE) {
22086ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou            throw new ExifInvalidFormatException("Invalid offset " + offset);
22186ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou        }
22286ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou        mIfd0Position = (int) offset;
223b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou        mIfdType = IfdId.TYPE_IFD_0;
224b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou        if (isIfdRequested(IfdId.TYPE_IFD_0) || needToParseOffsetsInCurrentIfd()) {
225b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou            registerIfd(IfdId.TYPE_IFD_0, offset);
226b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou            if (offset != DEFAULT_IFD0_OFFSET) {
227b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou                mDataAboveIfd0 = new byte[(int) offset - DEFAULT_IFD0_OFFSET];
228b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou                read(mDataAboveIfd0);
229b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou            }
2304ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        }
2314ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
2324ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
2334ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    /**
2344ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * Parses the the given InputStream with the given options
2356e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     *
2364ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @exception IOException
2374ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @exception ExifInvalidFormatException
2384ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     */
2396e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected static ExifParser parse(InputStream inputStream, int options, ExifInterface iRef)
240b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou            throws IOException, ExifInvalidFormatException {
2416e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        return new ExifParser(inputStream, options, iRef);
2424ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
2434ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
2444ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    /**
2456e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * Parses the the given InputStream with default options; that is, every IFD
2466e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * and thumbnaill will be parsed.
2476e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     *
2484ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @exception IOException
2494ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @exception ExifInvalidFormatException
2504ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @see #parse(InputStream, int)
2514ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     */
2526e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected static ExifParser parse(InputStream inputStream, ExifInterface iRef)
2534ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            throws IOException, ExifInvalidFormatException {
2544ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        return new ExifParser(inputStream, OPTION_IFD_0 | OPTION_IFD_1
2554ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                | OPTION_IFD_EXIF | OPTION_IFD_GPS | OPTION_IFD_INTEROPERABILITY
2566e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                | OPTION_THUMBNAIL, iRef);
2574ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
2584ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
2594ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    /**
2604ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * Moves the parser forward and returns the next parsing event
2614ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     *
2624ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @exception IOException
2634ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @exception ExifInvalidFormatException
2644ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @see #EVENT_START_OF_IFD
2654ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @see #EVENT_NEW_TAG
2664ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @see #EVENT_VALUE_OF_REGISTERED_TAG
2674ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @see #EVENT_COMPRESSED_IMAGE
2684ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @see #EVENT_UNCOMPRESSED_STRIP
2694ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @see #EVENT_END
2704ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     */
2716e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected int next() throws IOException, ExifInvalidFormatException {
2724cec566b34655e76b90f8ca089f151e6f42ede0cEarl Ou        if (!mContainExifData) {
2734cec566b34655e76b90f8ca089f151e6f42ede0cEarl Ou            return EVENT_END;
2744cec566b34655e76b90f8ca089f151e6f42ede0cEarl Ou        }
2754ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        int offset = mTiffStream.getReadByteCount();
2764ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        int endOfTags = mIfdStartOffset + OFFSET_SIZE + TAG_SIZE * mNumOfTagInIfd;
2774ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        if (offset < endOfTags) {
2784ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            mTag = readTag();
279e761c182a1a0321df95f2c11aa97e4cd1377a880Earl Ou            if (mTag == null) {
280e761c182a1a0321df95f2c11aa97e4cd1377a880Earl Ou                return next();
281e761c182a1a0321df95f2c11aa97e4cd1377a880Earl Ou            }
2824ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            if (mNeedToParseOffsetsInCurrentIfd) {
2834ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                checkOffsetOrImageTag(mTag);
2844ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            }
2854ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            return EVENT_NEW_TAG;
2864ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        } else if (offset == endOfTags) {
2874ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            // There is a link to ifd1 at the end of ifd0
2884ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            if (mIfdType == IfdId.TYPE_IFD_0) {
289c83dab412a3babdc6012c95fe1f335cdf3102d7eEarl Ou                long ifdOffset = readUnsignedLong();
2904ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                if (isIfdRequested(IfdId.TYPE_IFD_1) || isThumbnailRequested()) {
2914ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                    if (ifdOffset != 0) {
2924ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                        registerIfd(IfdId.TYPE_IFD_1, ifdOffset);
2934ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                    }
2944ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                }
2954ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            } else {
296c83dab412a3babdc6012c95fe1f335cdf3102d7eEarl Ou                int offsetSize = 4;
297c83dab412a3babdc6012c95fe1f335cdf3102d7eEarl Ou                // Some camera models use invalid length of the offset
298c83dab412a3babdc6012c95fe1f335cdf3102d7eEarl Ou                if (mCorrespondingEvent.size() > 0) {
299c83dab412a3babdc6012c95fe1f335cdf3102d7eEarl Ou                    offsetSize = mCorrespondingEvent.firstEntry().getKey() -
300c83dab412a3babdc6012c95fe1f335cdf3102d7eEarl Ou                            mTiffStream.getReadByteCount();
301c83dab412a3babdc6012c95fe1f335cdf3102d7eEarl Ou                }
302c83dab412a3babdc6012c95fe1f335cdf3102d7eEarl Ou                if (offsetSize < 4) {
303c83dab412a3babdc6012c95fe1f335cdf3102d7eEarl Ou                    Log.w(TAG, "Invalid size of link to next IFD: " + offsetSize);
304c83dab412a3babdc6012c95fe1f335cdf3102d7eEarl Ou                } else {
305c83dab412a3babdc6012c95fe1f335cdf3102d7eEarl Ou                    long ifdOffset = readUnsignedLong();
306c83dab412a3babdc6012c95fe1f335cdf3102d7eEarl Ou                    if (ifdOffset != 0) {
307c83dab412a3babdc6012c95fe1f335cdf3102d7eEarl Ou                        Log.w(TAG, "Invalid link to next IFD: " + ifdOffset);
308c83dab412a3babdc6012c95fe1f335cdf3102d7eEarl Ou                    }
3094ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                }
3104ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            }
3114ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        }
3126e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        while (mCorrespondingEvent.size() != 0) {
3134ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            Entry<Integer, Object> entry = mCorrespondingEvent.pollFirstEntry();
3144ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            Object event = entry.getValue();
31586ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou            try {
31686ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou                skipTo(entry.getKey());
31786ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou            } catch (IOException e) {
31886ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou                Log.w(TAG, "Failed to skip to data at: " + entry.getKey() +
31986ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou                        " for " + event.getClass().getName() + ", the file may be broken.");
32086ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou                continue;
32186ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou            }
3224ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            if (event instanceof IfdEvent) {
3234ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                mIfdType = ((IfdEvent) event).ifd;
3244ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                mNumOfTagInIfd = mTiffStream.readUnsignedShort();
3254ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                mIfdStartOffset = entry.getKey();
32686ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou
32786ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou                if (mNumOfTagInIfd * TAG_SIZE + mIfdStartOffset + OFFSET_SIZE > mApp1End) {
32886ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou                    Log.w(TAG, "Invalid size of IFD " + mIfdType);
32986ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou                    return EVENT_END;
33086ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou                }
33186ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou
3324ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                mNeedToParseOffsetsInCurrentIfd = needToParseOffsetsInCurrentIfd();
3334ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                if (((IfdEvent) event).isRequested) {
3344ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                    return EVENT_START_OF_IFD;
3354ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                } else {
3364ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                    skipRemainingTagsInCurrentIfd();
3374ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                }
3384ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            } else if (event instanceof ImageEvent) {
3394ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                mImageEvent = (ImageEvent) event;
3404ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                return mImageEvent.type;
3414ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            } else {
3424ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                ExifTagEvent tagEvent = (ExifTagEvent) event;
3434ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                mTag = tagEvent.tag;
3444ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                if (mTag.getDataType() != ExifTag.TYPE_UNDEFINED) {
3454ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                    readFullTagValue(mTag);
3464ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                    checkOffsetOrImageTag(mTag);
3474ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                }
3484ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                if (tagEvent.isRequested) {
3494ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                    return EVENT_VALUE_OF_REGISTERED_TAG;
3504ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                }
3514ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            }
3524ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        }
3534ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        return EVENT_END;
3544ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
3554ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
3564ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    /**
3576e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * Skips the tags area of current IFD, if the parser is not in the tag area,
3586e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * nothing will happen.
3594ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     *
3604ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @throws IOException
3614ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @throws ExifInvalidFormatException
3624ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     */
3636e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected void skipRemainingTagsInCurrentIfd() throws IOException, ExifInvalidFormatException {
3644ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        int endOfTags = mIfdStartOffset + OFFSET_SIZE + TAG_SIZE * mNumOfTagInIfd;
3654ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        int offset = mTiffStream.getReadByteCount();
3666e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        if (offset > endOfTags) {
3676e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            return;
3686e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        }
3694ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        if (mNeedToParseOffsetsInCurrentIfd) {
3704ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            while (offset < endOfTags) {
3714ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                mTag = readTag();
3724ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                offset += TAG_SIZE;
3736e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                if (mTag == null) {
3746e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                    continue;
3756e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                }
376e761c182a1a0321df95f2c11aa97e4cd1377a880Earl Ou                checkOffsetOrImageTag(mTag);
3774ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            }
3784ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        } else {
3794ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            skipTo(endOfTags);
3804ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        }
38189591324c5d1097e59217177ad3ea74598867584Earl Ou        long ifdOffset = readUnsignedLong();
3824ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        // For ifd0, there is a link to ifd1 in the end of all tags
3834ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        if (mIfdType == IfdId.TYPE_IFD_0
3844ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                && (isIfdRequested(IfdId.TYPE_IFD_1) || isThumbnailRequested())) {
3854ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            if (ifdOffset > 0) {
3864ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                registerIfd(IfdId.TYPE_IFD_1, ifdOffset);
3874ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            }
3884ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        }
3894ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
3904ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
3914ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    private boolean needToParseOffsetsInCurrentIfd() {
3924ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        switch (mIfdType) {
3934ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            case IfdId.TYPE_IFD_0:
3944ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                return isIfdRequested(IfdId.TYPE_IFD_EXIF) || isIfdRequested(IfdId.TYPE_IFD_GPS)
395b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou                        || isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY)
396b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou                        || isIfdRequested(IfdId.TYPE_IFD_1);
3974ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            case IfdId.TYPE_IFD_1:
3984ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                return isThumbnailRequested();
3994ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            case IfdId.TYPE_IFD_EXIF:
4004ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                // The offset to interoperability IFD is located in Exif IFD
4014ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                return isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY);
4024ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            default:
4034ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                return false;
4044ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        }
4054ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
4064ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
4074ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    /**
4086e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * If {@link #next()} return {@link #EVENT_NEW_TAG} or
4096e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * {@link #EVENT_VALUE_OF_REGISTERED_TAG}, call this function to get the
4106e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * corresponding tag.
4114ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * <p>
4126e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * For {@link #EVENT_NEW_TAG}, the tag may not contain the value if the size
4136e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * of the value is greater than 4 bytes. One should call
4146e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * {@link ExifTag#hasValue()} to check if the tag contains value. If there
4156e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * is no value,call {@link #registerForTagValue(ExifTag)} to have the parser
4166e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * emit {@link #EVENT_VALUE_OF_REGISTERED_TAG} when it reaches the area
4176e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * pointed by the offset.
4184ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * <p>
4196e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * When {@link #EVENT_VALUE_OF_REGISTERED_TAG} is emitted, the value of the
4206e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * tag will have already been read except for tags of undefined type. For
4216e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * tags of undefined type, call one of the read methods to get the value.
4224ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     *
4234ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @see #registerForTagValue(ExifTag)
4244ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @see #read(byte[])
4254ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @see #read(byte[], int, int)
42689591324c5d1097e59217177ad3ea74598867584Earl Ou     * @see #readLong()
4274ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @see #readRational()
4284ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @see #readString(int)
4294ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @see #readString(int, Charset)
4304ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     */
4316e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected ExifTag getTag() {
4324ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        return mTag;
4334ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
4344ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
4354ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    /**
4364ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * Gets number of tags in the current IFD area.
4374ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     */
4386e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected int getTagCountInCurrentIfd() {
4394ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        return mNumOfTagInIfd;
4404ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
4414ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
4424ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    /**
4434ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * Gets the ID of current IFD.
4444ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     *
4454ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @see IfdId#TYPE_IFD_0
4464ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @see IfdId#TYPE_IFD_1
4474ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @see IfdId#TYPE_IFD_GPS
4484ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @see IfdId#TYPE_IFD_INTEROPERABILITY
4494ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @see IfdId#TYPE_IFD_EXIF
4504ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     */
4516e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected int getCurrentIfd() {
4524ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        return mIfdType;
4534ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
4544ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
4554ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    /**
4566e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * When receiving {@link #EVENT_UNCOMPRESSED_STRIP}, call this function to
4576e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * get the index of this strip.
4586e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     *
4594ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @see #getStripCount()
4604ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     */
4616e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected int getStripIndex() {
4624ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        return mImageEvent.stripIndex;
4634ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
4644ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
4654ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    /**
4666e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * When receiving {@link #EVENT_UNCOMPRESSED_STRIP}, call this function to
4676e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * get the number of strip data.
4686e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     *
4694ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @see #getStripIndex()
4704ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     */
4716e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected int getStripCount() {
4724ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        return mStripCount;
4734ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
4744ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
4754ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    /**
4766e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * When receiving {@link #EVENT_UNCOMPRESSED_STRIP}, call this function to
4776e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * get the strip size.
4784ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     */
4796e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected int getStripSize() {
4806e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        if (mStripSizeTag == null)
4816e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            return 0;
4828592397237a3f052ac39dd7f259898a7e04fae50Earl Ou        return (int) mStripSizeTag.getValueAt(0);
4834ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
4844ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
4854ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    /**
4866e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * When receiving {@link #EVENT_COMPRESSED_IMAGE}, call this function to get
4876e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * the image data size.
4884ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     */
4896e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected int getCompressedImageSize() {
4906e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        if (mJpegSizeTag == null) {
4916e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            return 0;
4926e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        }
4938592397237a3f052ac39dd7f259898a7e04fae50Earl Ou        return (int) mJpegSizeTag.getValueAt(0);
4944ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
4954ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
4964ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    private void skipTo(int offset) throws IOException {
4974ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        mTiffStream.skipTo(offset);
4984ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        while (!mCorrespondingEvent.isEmpty() && mCorrespondingEvent.firstKey() < offset) {
4994ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            mCorrespondingEvent.pollFirstEntry();
50073e933f1f57002d2e593aa7b471811d8837f8767Earl Ou        }
50173e933f1f57002d2e593aa7b471811d8837f8767Earl Ou    }
50273e933f1f57002d2e593aa7b471811d8837f8767Earl Ou
5034ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    /**
5046e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * When getting {@link #EVENT_NEW_TAG} in the tag area of IFD, the tag may
5056e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * not contain the value if the size of the value is greater than 4 bytes.
5066e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * When the value is not available here, call this method so that the parser
5076e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * will emit {@link #EVENT_VALUE_OF_REGISTERED_TAG} when it reaches the area
5086e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * where the value is located.
5096e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     *
5104ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     * @see #EVENT_VALUE_OF_REGISTERED_TAG
5114ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     */
5126e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected void registerForTagValue(ExifTag tag) {
5136e91433bb48ad64cb48ccba7513bfac388c1eaf4Ruben Brunk        if (tag.getOffset() >= mTiffStream.getReadByteCount()) {
5146e91433bb48ad64cb48ccba7513bfac388c1eaf4Ruben Brunk            mCorrespondingEvent.put(tag.getOffset(), new ExifTagEvent(tag, true));
5156e91433bb48ad64cb48ccba7513bfac388c1eaf4Ruben Brunk        }
5164ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
5174ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
5184ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    private void registerIfd(int ifdType, long offset) {
51989591324c5d1097e59217177ad3ea74598867584Earl Ou        // Cast unsigned int to int since the offset is always smaller
52089591324c5d1097e59217177ad3ea74598867584Earl Ou        // than the size of APP1 (65536)
5214ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        mCorrespondingEvent.put((int) offset, new IfdEvent(ifdType, isIfdRequested(ifdType)));
5224ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
5234ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
5244ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    private void registerCompressedImage(long offset) {
5254ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        mCorrespondingEvent.put((int) offset, new ImageEvent(EVENT_COMPRESSED_IMAGE));
5264ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
5274ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
5284ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    private void registerUncompressedStrip(int stripIndex, long offset) {
5294ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        mCorrespondingEvent.put((int) offset, new ImageEvent(EVENT_UNCOMPRESSED_STRIP
5304ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                , stripIndex));
5314ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
5324ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
5334ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    private ExifTag readTag() throws IOException, ExifInvalidFormatException {
5344ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        short tagId = mTiffStream.readShort();
5354ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        short dataFormat = mTiffStream.readShort();
5364ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        long numOfComp = mTiffStream.readUnsignedInt();
5374ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        if (numOfComp > Integer.MAX_VALUE) {
5384ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            throw new ExifInvalidFormatException(
5394ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                    "Number of component is larger then Integer.MAX_VALUE");
5404ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        }
541e761c182a1a0321df95f2c11aa97e4cd1377a880Earl Ou        // Some invalid image file contains invalid data type. Ignore those tags
542e761c182a1a0321df95f2c11aa97e4cd1377a880Earl Ou        if (!ExifTag.isValidType(dataFormat)) {
543e761c182a1a0321df95f2c11aa97e4cd1377a880Earl Ou            Log.w(TAG, String.format("Tag %04x: Invalid data type %d", tagId, dataFormat));
544e761c182a1a0321df95f2c11aa97e4cd1377a880Earl Ou            mTiffStream.skip(4);
545e761c182a1a0321df95f2c11aa97e4cd1377a880Earl Ou            return null;
546e761c182a1a0321df95f2c11aa97e4cd1377a880Earl Ou        }
5476e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        // TODO: handle numOfComp overflow
5486e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        ExifTag tag = new ExifTag(tagId, dataFormat, (int) numOfComp, mIfdType,
5496e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                ((int) numOfComp) != ExifTag.SIZE_UNDEFINED);
5505df339d5ef4550ceb12070f5e17335df2c4fff62Earl Ou        int dataSize = tag.getDataSize();
5515df339d5ef4550ceb12070f5e17335df2c4fff62Earl Ou        if (dataSize > 4) {
5524ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            long offset = mTiffStream.readUnsignedInt();
5534ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            if (offset > Integer.MAX_VALUE) {
5544ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                throw new ExifInvalidFormatException(
5554ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                        "offset is larger then Integer.MAX_VALUE");
5564ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            }
55786ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou            // Some invalid images put some undefined data before IFD0.
55886ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou            // Read the data here.
55986ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou            if ((offset < mIfd0Position) && (dataFormat == ExifTag.TYPE_UNDEFINED)) {
56086ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou                byte[] buf = new byte[(int) numOfComp];
56186ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou                System.arraycopy(mDataAboveIfd0, (int) offset - DEFAULT_IFD0_OFFSET,
56286ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou                        buf, 0, (int) numOfComp);
56386ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou                tag.setValue(buf);
56486ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou            } else {
56586ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou                tag.setOffset((int) offset);
56686ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou            }
5674ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        } else {
5686e91433bb48ad64cb48ccba7513bfac388c1eaf4Ruben Brunk            boolean defCount = tag.hasDefinedCount();
5696e91433bb48ad64cb48ccba7513bfac388c1eaf4Ruben Brunk            // Set defined count to 0 so we can add \0 to non-terminated strings
5706e91433bb48ad64cb48ccba7513bfac388c1eaf4Ruben Brunk            tag.setHasDefinedCount(false);
5716e91433bb48ad64cb48ccba7513bfac388c1eaf4Ruben Brunk            // Read value
5724ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            readFullTagValue(tag);
5736e91433bb48ad64cb48ccba7513bfac388c1eaf4Ruben Brunk            tag.setHasDefinedCount(defCount);
5745df339d5ef4550ceb12070f5e17335df2c4fff62Earl Ou            mTiffStream.skip(4 - dataSize);
575b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou            // Set the offset to the position of value.
576b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou            tag.setOffset(mTiffStream.getReadByteCount() - 4);
5774ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        }
5784ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        return tag;
5794ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
5804ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
5814ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    /**
5826e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * Check the tag, if the tag is one of the offset tag that points to the IFD
5836e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * or image the caller is interested in, register the IFD or image.
5844ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou     */
5854ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    private void checkOffsetOrImageTag(ExifTag tag) {
58686ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou        // Some invalid formattd image contains tag with 0 size.
58786ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou        if (tag.getComponentCount() == 0) {
58886ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou            return;
58986ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou        }
5906e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        short tid = tag.getTagId();
5916e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        int ifd = tag.getIfd();
5926e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        if (tid == TAG_EXIF_IFD && checkAllowed(ifd, ExifInterface.TAG_EXIF_IFD)) {
5936e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            if (isIfdRequested(IfdId.TYPE_IFD_EXIF)
5946e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                    || isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY)) {
5956e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                registerIfd(IfdId.TYPE_IFD_EXIF, tag.getValueAt(0));
5966e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            }
5976e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        } else if (tid == TAG_GPS_IFD && checkAllowed(ifd, ExifInterface.TAG_GPS_IFD)) {
5986e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            if (isIfdRequested(IfdId.TYPE_IFD_GPS)) {
5996e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                registerIfd(IfdId.TYPE_IFD_GPS, tag.getValueAt(0));
6006e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            }
6016e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        } else if (tid == TAG_INTEROPERABILITY_IFD
6026e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                && checkAllowed(ifd, ExifInterface.TAG_INTEROPERABILITY_IFD)) {
6036e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            if (isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY)) {
6046e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                registerIfd(IfdId.TYPE_IFD_INTEROPERABILITY, tag.getValueAt(0));
6056e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            }
6066e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        } else if (tid == TAG_JPEG_INTERCHANGE_FORMAT
6076e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                && checkAllowed(ifd, ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT)) {
6086e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            if (isThumbnailRequested()) {
6096e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                registerCompressedImage(tag.getValueAt(0));
6106e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            }
6116e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        } else if (tid == TAG_JPEG_INTERCHANGE_FORMAT_LENGTH
6126e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                && checkAllowed(ifd, ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH)) {
6136e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            if (isThumbnailRequested()) {
6146e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                mJpegSizeTag = tag;
6156e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            }
6166e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        } else if (tid == TAG_STRIP_OFFSETS && checkAllowed(ifd, ExifInterface.TAG_STRIP_OFFSETS)) {
6176e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            if (isThumbnailRequested()) {
6186e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                if (tag.hasValue()) {
6196e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                    for (int i = 0; i < tag.getComponentCount(); i++) {
6206e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                        if (tag.getDataType() == ExifTag.TYPE_UNSIGNED_SHORT) {
6216e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                            registerUncompressedStrip(i, tag.getValueAt(i));
6226e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                        } else {
6236e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                            registerUncompressedStrip(i, tag.getValueAt(i));
6244ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                        }
6254ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                    }
6266e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                } else {
6276e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                    mCorrespondingEvent.put(tag.getOffset(), new ExifTagEvent(tag, false));
6284ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                }
6296e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            }
6306e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        } else if (tid == TAG_STRIP_BYTE_COUNTS
6316e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                && checkAllowed(ifd, ExifInterface.TAG_STRIP_BYTE_COUNTS)
6326e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                &&isThumbnailRequested() && tag.hasValue()) {
6336e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            mStripSizeTag = tag;
6346e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        }
6356e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    }
6366e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk
6376e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    private boolean checkAllowed(int ifd, int tagId) {
6386e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        int info = mInterface.getTagInfo().get(tagId);
6396e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        if (info == ExifInterface.DEFINITION_NULL) {
6406e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            return false;
6414ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        }
6426e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        return ExifInterface.isIfdAllowed(info, ifd);
6434ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
6444ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
6456e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected void readFullTagValue(ExifTag tag) throws IOException {
64686ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou        // Some invalid images contains tags with wrong size, check it here
64786ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou        short type = tag.getDataType();
64886ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou        if (type == ExifTag.TYPE_ASCII || type == ExifTag.TYPE_UNDEFINED ||
64986ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou                type == ExifTag.TYPE_UNSIGNED_BYTE) {
65086ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou            int size = tag.getComponentCount();
65186ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou            if (mCorrespondingEvent.size() > 0) {
6526e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                if (mCorrespondingEvent.firstEntry().getKey() < mTiffStream.getReadByteCount()
6536e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                        + size) {
6546e91433bb48ad64cb48ccba7513bfac388c1eaf4Ruben Brunk                    Object event = mCorrespondingEvent.firstEntry().getValue();
6556e91433bb48ad64cb48ccba7513bfac388c1eaf4Ruben Brunk                    if (event instanceof ImageEvent) {
6566e91433bb48ad64cb48ccba7513bfac388c1eaf4Ruben Brunk                        // Tag value overlaps thumbnail, ignore thumbnail.
6576e91433bb48ad64cb48ccba7513bfac388c1eaf4Ruben Brunk                        Log.w(TAG, "Thumbnail overlaps value for tag: \n" + tag.toString());
6586e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                        Entry<Integer, Object> entry = mCorrespondingEvent.pollFirstEntry();
6596e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                        Log.w(TAG, "Invalid thumbnail offset: " + entry.getKey());
6606e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                    } else {
6616e91433bb48ad64cb48ccba7513bfac388c1eaf4Ruben Brunk                        // Tag value overlaps another tag, shorten count
6626e91433bb48ad64cb48ccba7513bfac388c1eaf4Ruben Brunk                        if (event instanceof IfdEvent) {
6636e91433bb48ad64cb48ccba7513bfac388c1eaf4Ruben Brunk                            Log.w(TAG, "Ifd " + ((IfdEvent) event).ifd
6646e91433bb48ad64cb48ccba7513bfac388c1eaf4Ruben Brunk                                    + " overlaps value for tag: \n" + tag.toString());
6656e91433bb48ad64cb48ccba7513bfac388c1eaf4Ruben Brunk                        } else if (event instanceof ExifTagEvent) {
6666e91433bb48ad64cb48ccba7513bfac388c1eaf4Ruben Brunk                            Log.w(TAG, "Tag value for tag: \n"
6676e91433bb48ad64cb48ccba7513bfac388c1eaf4Ruben Brunk                                    + ((ExifTagEvent) event).tag.toString()
6686e91433bb48ad64cb48ccba7513bfac388c1eaf4Ruben Brunk                                    + " overlaps value for tag: \n" + tag.toString());
6696e91433bb48ad64cb48ccba7513bfac388c1eaf4Ruben Brunk                        }
6706e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                        size = mCorrespondingEvent.firstEntry().getKey()
6716e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                                - mTiffStream.getReadByteCount();
6726e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                        Log.w(TAG, "Invalid size of tag: \n" + tag.toString()
6736e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                                + " setting count to: " + size);
6746e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                        tag.forceSetComponentCount(size);
6756e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                    }
67686ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou                }
67786ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou            }
67886ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou        }
6796e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        switch (tag.getDataType()) {
6804ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            case ExifTag.TYPE_UNSIGNED_BYTE:
6816e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            case ExifTag.TYPE_UNDEFINED: {
6826e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                byte buf[] = new byte[tag.getComponentCount()];
6836e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                read(buf);
6846e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                tag.setValue(buf);
6856e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            }
6864ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                break;
6874ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            case ExifTag.TYPE_ASCII:
6884ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                tag.setValue(readString(tag.getComponentCount()));
6894ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                break;
6906e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            case ExifTag.TYPE_UNSIGNED_LONG: {
6916e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                long value[] = new long[tag.getComponentCount()];
6926e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                for (int i = 0, n = value.length; i < n; i++) {
6936e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                    value[i] = readUnsignedLong();
6944ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                }
6956e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                tag.setValue(value);
6966e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            }
6974ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou                break;
6986e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            case ExifTag.TYPE_UNSIGNED_RATIONAL: {
6996e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                Rational value[] = new Rational[tag.getComponentCount()];
7006e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                for (int i = 0, n = value.length; i < n; i++) {
7016e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                    value[i] = readUnsignedRational();
702b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou                }
7036e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                tag.setValue(value);
7046e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            }
705b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou                break;
7066e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            case ExifTag.TYPE_UNSIGNED_SHORT: {
7076e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                int value[] = new int[tag.getComponentCount()];
7086e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                for (int i = 0, n = value.length; i < n; i++) {
7096e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                    value[i] = readUnsignedShort();
710b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou                }
7116e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                tag.setValue(value);
7126e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            }
713b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou                break;
7146e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            case ExifTag.TYPE_LONG: {
7156e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                int value[] = new int[tag.getComponentCount()];
7166e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                for (int i = 0, n = value.length; i < n; i++) {
7176e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                    value[i] = readLong();
718b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou                }
7196e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                tag.setValue(value);
7206e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            }
721b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou                break;
7226e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            case ExifTag.TYPE_RATIONAL: {
7236e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                Rational value[] = new Rational[tag.getComponentCount()];
7246e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                for (int i = 0, n = value.length; i < n; i++) {
7256e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                    value[i] = readRational();
726b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou                }
7276e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                tag.setValue(value);
7286e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            }
729b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou                break;
7304ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        }
7316e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        if (LOGV) {
7326e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk            Log.v(TAG, "\n" + tag.toString());
7336e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        }
7344ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
7354ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
7364ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    private void parseTiffHeader() throws IOException,
73773e933f1f57002d2e593aa7b471811d8837f8767Earl Ou            ExifInvalidFormatException {
7384ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        short byteOrder = mTiffStream.readShort();
73973e933f1f57002d2e593aa7b471811d8837f8767Earl Ou        if (LITTLE_ENDIAN_TAG == byteOrder) {
7404ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            mTiffStream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
74173e933f1f57002d2e593aa7b471811d8837f8767Earl Ou        } else if (BIG_ENDIAN_TAG == byteOrder) {
7424ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            mTiffStream.setByteOrder(ByteOrder.BIG_ENDIAN);
74373e933f1f57002d2e593aa7b471811d8837f8767Earl Ou        } else {
74473e933f1f57002d2e593aa7b471811d8837f8767Earl Ou            throw new ExifInvalidFormatException("Invalid TIFF header");
74573e933f1f57002d2e593aa7b471811d8837f8767Earl Ou        }
74673e933f1f57002d2e593aa7b471811d8837f8767Earl Ou
7474ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        if (mTiffStream.readShort() != TIFF_HEADER_TAIL) {
74873e933f1f57002d2e593aa7b471811d8837f8767Earl Ou            throw new ExifInvalidFormatException("Invalid TIFF header");
74973e933f1f57002d2e593aa7b471811d8837f8767Earl Ou        }
75073e933f1f57002d2e593aa7b471811d8837f8767Earl Ou    }
75173e933f1f57002d2e593aa7b471811d8837f8767Earl Ou
7524cec566b34655e76b90f8ca089f151e6f42ede0cEarl Ou    private boolean seekTiffData(InputStream inputStream) throws IOException,
75373e933f1f57002d2e593aa7b471811d8837f8767Earl Ou            ExifInvalidFormatException {
754b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou        CountedDataInputStream dataStream = new CountedDataInputStream(inputStream);
7554cec566b34655e76b90f8ca089f151e6f42ede0cEarl Ou        if (dataStream.readShort() != JpegHeader.SOI) {
75673e933f1f57002d2e593aa7b471811d8837f8767Earl Ou            throw new ExifInvalidFormatException("Invalid JPEG format");
75773e933f1f57002d2e593aa7b471811d8837f8767Earl Ou        }
75873e933f1f57002d2e593aa7b471811d8837f8767Earl Ou
7594cec566b34655e76b90f8ca089f151e6f42ede0cEarl Ou        short marker = dataStream.readShort();
7606e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        while (marker != JpegHeader.EOI
7614cec566b34655e76b90f8ca089f151e6f42ede0cEarl Ou                && !JpegHeader.isSofMarker(marker)) {
76223ea2b53d9625471774dd219c36701b656c64616Earl Ou            int length = dataStream.readUnsignedShort();
763abb1b01a32a400433ab60358d92ebea78a64b669Earl Ou            // Some invalid formatted image contains multiple APP1,
764abb1b01a32a400433ab60358d92ebea78a64b669Earl Ou            // try to find the one with Exif data.
765abb1b01a32a400433ab60358d92ebea78a64b669Earl Ou            if (marker == JpegHeader.APP1) {
766abb1b01a32a400433ab60358d92ebea78a64b669Earl Ou                int header = 0;
767abb1b01a32a400433ab60358d92ebea78a64b669Earl Ou                short headerTail = 0;
768abb1b01a32a400433ab60358d92ebea78a64b669Earl Ou                if (length >= 8) {
769abb1b01a32a400433ab60358d92ebea78a64b669Earl Ou                    header = dataStream.readInt();
770abb1b01a32a400433ab60358d92ebea78a64b669Earl Ou                    headerTail = dataStream.readShort();
771abb1b01a32a400433ab60358d92ebea78a64b669Earl Ou                    length -= 6;
772abb1b01a32a400433ab60358d92ebea78a64b669Earl Ou                    if (header == EXIF_HEADER && headerTail == EXIF_HEADER_TAIL) {
773b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou                        mTiffStartPosition = dataStream.getReadByteCount();
77486ad9b7a1fa1e31cbb07d972d581386bc2b13a59Earl Ou                        mApp1End = length;
7756e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk                        mOffsetToApp1EndFromSOF = mTiffStartPosition + mApp1End;
776abb1b01a32a400433ab60358d92ebea78a64b669Earl Ou                        return true;
777abb1b01a32a400433ab60358d92ebea78a64b669Earl Ou                    }
778abb1b01a32a400433ab60358d92ebea78a64b669Earl Ou                }
779abb1b01a32a400433ab60358d92ebea78a64b669Earl Ou            }
780abb1b01a32a400433ab60358d92ebea78a64b669Earl Ou            if (length < 2 || (length - 2) != dataStream.skip(length - 2)) {
781abb1b01a32a400433ab60358d92ebea78a64b669Earl Ou                Log.w(TAG, "Invalid JPEG format.");
782abb1b01a32a400433ab60358d92ebea78a64b669Earl Ou                return false;
78323ea2b53d9625471774dd219c36701b656c64616Earl Ou            }
7844cec566b34655e76b90f8ca089f151e6f42ede0cEarl Ou            marker = dataStream.readShort();
78523ea2b53d9625471774dd219c36701b656c64616Earl Ou        }
786abb1b01a32a400433ab60358d92ebea78a64b669Earl Ou        return false;
7874ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
7884ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
7896e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected int getOffsetToExifEndFromSOF() {
7906e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk        return mOffsetToApp1EndFromSOF;
7916e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    }
7926e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk
7936e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected int getTiffStartPosition() {
794b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou        return mTiffStartPosition;
795b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou    }
796b430b34197d3016d1659ed104abbd3cb5d6d881dEarl Ou
79789591324c5d1097e59217177ad3ea74598867584Earl Ou    /**
79889591324c5d1097e59217177ad3ea74598867584Earl Ou     * Reads bytes from the InputStream.
79989591324c5d1097e59217177ad3ea74598867584Earl Ou     */
8006e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected int read(byte[] buffer, int offset, int length) throws IOException {
8014ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        return mTiffStream.read(buffer, offset, length);
8024ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
8034ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
80489591324c5d1097e59217177ad3ea74598867584Earl Ou    /**
80589591324c5d1097e59217177ad3ea74598867584Earl Ou     * Equivalent to read(buffer, 0, buffer.length).
80689591324c5d1097e59217177ad3ea74598867584Earl Ou     */
8076e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected int read(byte[] buffer) throws IOException {
8084ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        return mTiffStream.read(buffer);
8094ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
8104ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
81189591324c5d1097e59217177ad3ea74598867584Earl Ou    /**
8126e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * Reads a String from the InputStream with US-ASCII charset. The parser
8136e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * will read n bytes and convert it to ascii string. This is used for
8146e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * reading values of type {@link ExifTag#TYPE_ASCII}.
81589591324c5d1097e59217177ad3ea74598867584Earl Ou     */
8166e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected String readString(int n) throws IOException {
8173357622665ec1757b120c16584fc7b67114c69ffEarl Ou        return readString(n, US_ASCII);
8184ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
8194ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
82089591324c5d1097e59217177ad3ea74598867584Earl Ou    /**
8216e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * Reads a String from the InputStream with the given charset. The parser
8226e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * will read n bytes and convert it to string. This is used for reading
8236e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * values of type {@link ExifTag#TYPE_ASCII}.
82489591324c5d1097e59217177ad3ea74598867584Earl Ou     */
8256e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected String readString(int n, Charset charset) throws IOException {
8263357622665ec1757b120c16584fc7b67114c69ffEarl Ou        if (n > 0) {
8273357622665ec1757b120c16584fc7b67114c69ffEarl Ou            return mTiffStream.readString(n, charset);
8283357622665ec1757b120c16584fc7b67114c69ffEarl Ou        } else {
8293357622665ec1757b120c16584fc7b67114c69ffEarl Ou            return "";
8303357622665ec1757b120c16584fc7b67114c69ffEarl Ou        }
8314ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
8324ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
83389591324c5d1097e59217177ad3ea74598867584Earl Ou    /**
8346e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * Reads value of type {@link ExifTag#TYPE_UNSIGNED_SHORT} from the
8356e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * InputStream.
83689591324c5d1097e59217177ad3ea74598867584Earl Ou     */
8376e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected int readUnsignedShort() throws IOException {
83889591324c5d1097e59217177ad3ea74598867584Earl Ou        return mTiffStream.readShort() & 0xffff;
8394ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
8404ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
84189591324c5d1097e59217177ad3ea74598867584Earl Ou    /**
8426e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * Reads value of type {@link ExifTag#TYPE_UNSIGNED_LONG} from the
8436e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * InputStream.
84489591324c5d1097e59217177ad3ea74598867584Earl Ou     */
8456e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected long readUnsignedLong() throws IOException {
84689591324c5d1097e59217177ad3ea74598867584Earl Ou        return readLong() & 0xffffffffL;
8474ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
8484ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
84989591324c5d1097e59217177ad3ea74598867584Earl Ou    /**
8506e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * Reads value of type {@link ExifTag#TYPE_UNSIGNED_RATIONAL} from the
8516e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk     * InputStream.
85289591324c5d1097e59217177ad3ea74598867584Earl Ou     */
8536e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected Rational readUnsignedRational() throws IOException {
85489591324c5d1097e59217177ad3ea74598867584Earl Ou        long nomi = readUnsignedLong();
85589591324c5d1097e59217177ad3ea74598867584Earl Ou        long denomi = readUnsignedLong();
8564ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        return new Rational(nomi, denomi);
8574ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
8584ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
85989591324c5d1097e59217177ad3ea74598867584Earl Ou    /**
86089591324c5d1097e59217177ad3ea74598867584Earl Ou     * Reads value of type {@link ExifTag#TYPE_LONG} from the InputStream.
86189591324c5d1097e59217177ad3ea74598867584Earl Ou     */
8626e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected int readLong() throws IOException {
8634ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        return mTiffStream.readInt();
8644ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
8654ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
86689591324c5d1097e59217177ad3ea74598867584Earl Ou    /**
86789591324c5d1097e59217177ad3ea74598867584Earl Ou     * Reads value of type {@link ExifTag#TYPE_RATIONAL} from the InputStream.
86889591324c5d1097e59217177ad3ea74598867584Earl Ou     */
8696e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected Rational readRational() throws IOException {
87089591324c5d1097e59217177ad3ea74598867584Earl Ou        int nomi = readLong();
87189591324c5d1097e59217177ad3ea74598867584Earl Ou        int denomi = readLong();
8724ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        return new Rational(nomi, denomi);
8734ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
8744ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
8754ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    private static class ImageEvent {
8764ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        int stripIndex;
8774ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        int type;
8786e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk
8794ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        ImageEvent(int type) {
8804ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            this.stripIndex = 0;
8814ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            this.type = type;
88273e933f1f57002d2e593aa7b471811d8837f8767Earl Ou        }
8836e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk
8844ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        ImageEvent(int type, int stripIndex) {
8854ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            this.type = type;
8864ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            this.stripIndex = stripIndex;
8874ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        }
8884ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
88973e933f1f57002d2e593aa7b471811d8837f8767Earl Ou
8904ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    private static class IfdEvent {
8914ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        int ifd;
8924ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        boolean isRequested;
8936e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk
8944ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        IfdEvent(int ifd, boolean isInterestedIfd) {
8954ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            this.ifd = ifd;
8964ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            this.isRequested = isInterestedIfd;
8974ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        }
8984ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    }
8994ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou
9004ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou    private static class ExifTagEvent {
9014ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        ExifTag tag;
9024ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        boolean isRequested;
9036e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk
9044ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        ExifTagEvent(ExifTag tag, boolean isRequireByUser) {
9054ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            this.tag = tag;
9064ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou            this.isRequested = isRequireByUser;
9074ae9b211fee74f801f003bc9ad716e214de1a4f0Earl Ou        }
90873e933f1f57002d2e593aa7b471811d8837f8767Earl Ou    }
9097973bc292dcacaa5e68eecaff533d19b5cffc1e8Earl Ou
9107973bc292dcacaa5e68eecaff533d19b5cffc1e8Earl Ou    /**
9117973bc292dcacaa5e68eecaff533d19b5cffc1e8Earl Ou     * Gets the byte order of the current InputStream.
9127973bc292dcacaa5e68eecaff533d19b5cffc1e8Earl Ou     */
9136e6a524390d8ddebce5de0dcc8ae258e652ec80aRuben Brunk    protected ByteOrder getByteOrder() {
9147973bc292dcacaa5e68eecaff533d19b5cffc1e8Earl Ou        return mTiffStream.getByteOrder();
9157973bc292dcacaa5e68eecaff533d19b5cffc1e8Earl Ou    }
9163357622665ec1757b120c16584fc7b67114c69ffEarl Ou}
917