12523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan/*
22523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan * Copyright (C) 2012 The Android Open Source Project
32523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *
42523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan * Licensed under the Apache License, Version 2.0 (the "License");
52523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan * you may not use this file except in compliance with the License.
62523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan * You may obtain a copy of the License at
72523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *
82523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *      http://www.apache.org/licenses/LICENSE-2.0
92523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *
102523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan * Unless required by applicable law or agreed to in writing, software
112523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan * distributed under the License is distributed on an "AS IS" BASIS,
122523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan * See the License for the specific language governing permissions and
142523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan * limitations under the License.
152523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan */
162523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
17a16e7b50f3148f581439509279f242092e254309ztenghuipackage com.android.camera.exif;
182523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
192bca210e5fc8a77685775ffb403096167b017dceAngus Kongimport com.android.camera.debug.Log;
207e92ec75da5e2eb06e659e2226f64749b80ea3d9Earl Ou
212523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyanimport java.io.IOException;
222523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyanimport java.io.InputStream;
232523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyanimport java.nio.ByteOrder;
242523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyanimport java.nio.charset.Charset;
252523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyanimport java.util.Map.Entry;
262523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyanimport java.util.TreeMap;
272523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
282523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan/**
29c274ded801f745d6318186958107622e7a4fef33Ruben Brunk * This class provides a low-level EXIF parsing API. Given a JPEG format
30c274ded801f745d6318186958107622e7a4fef33Ruben Brunk * InputStream, the caller can request which IFD's to read via
31c274ded801f745d6318186958107622e7a4fef33Ruben Brunk * {@link #parse(InputStream, int)} with given options.
322523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan * <p>
33c274ded801f745d6318186958107622e7a4fef33Ruben Brunk * Below is an example of getting EXIF data from IFD 0 and EXIF IFD using the
34c274ded801f745d6318186958107622e7a4fef33Ruben Brunk * parser.
35c274ded801f745d6318186958107622e7a4fef33Ruben Brunk *
362523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan * <pre>
372523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan * void parse() {
382523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *     ExifParser parser = ExifParser.parse(mImageInputStream,
392523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *             ExifParser.OPTION_IFD_0 | ExifParser.OPTIONS_IFD_EXIF);
402523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *     int event = parser.next();
412523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *     while (event != ExifParser.EVENT_END) {
422523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *         switch (event) {
432523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *             case ExifParser.EVENT_START_OF_IFD:
442523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *                 break;
452523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *             case ExifParser.EVENT_NEW_TAG:
462523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *                 ExifTag tag = parser.getTag();
472523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *                 if (!tag.hasValue()) {
482523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *                     parser.registerForTagValue(tag);
492523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *                 } else {
502523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *                     processTag(tag);
512523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *                 }
522523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *                 break;
532523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *             case ExifParser.EVENT_VALUE_OF_REGISTERED_TAG:
542523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *                 tag = parser.getTag();
552523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *                 if (tag.getDataType() != ExifTag.TYPE_UNDEFINED) {
562523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *                     processTag(tag);
572523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *                 }
582523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *                 break;
592523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *         }
602523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *         event = parser.next();
612523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *     }
622523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan * }
632523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *
642523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan * void processTag(ExifTag tag) {
652523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan *     // process the tag as you like.
662523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan * }
672523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan * </pre>
682523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan */
69c274ded801f745d6318186958107622e7a4fef33Ruben Brunkclass ExifParser {
70c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    private static final boolean LOGV = false;
712bca210e5fc8a77685775ffb403096167b017dceAngus Kong    private static final Log.Tag TAG = new Log.Tag("ExifParser");
722523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
73c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * When the parser reaches a new IFD area. Call {@link #getCurrentIfd()} to
74c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * know which IFD we are in.
752523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
762523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    public static final int EVENT_START_OF_IFD = 0;
772523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
782523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * When the parser reaches a new tag. Call {@link #getTag()}to get the
792523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * corresponding tag.
802523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
812523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    public static final int EVENT_NEW_TAG = 1;
822523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
832523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * When the parser reaches the value area of tag that is registered by
84c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * {@link #registerForTagValue(ExifTag)} previously. Call {@link #getTag()}
85c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * to get the corresponding tag.
862523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
872523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    public static final int EVENT_VALUE_OF_REGISTERED_TAG = 2;
882523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
892523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
902523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * When the parser reaches the compressed image area.
912523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
922523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    public static final int EVENT_COMPRESSED_IMAGE = 3;
932523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
94c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * When the parser reaches the uncompressed image strip. Call
95c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * {@link #getStripIndex()} to get the index of the strip.
96c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     *
972523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @see #getStripIndex()
982523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @see #getStripCount()
992523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
1002523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    public static final int EVENT_UNCOMPRESSED_STRIP = 4;
1012523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
1022523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * When there is nothing more to parse.
1032523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
1042523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    public static final int EVENT_END = 5;
1052523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
1062523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
1072523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * Option bit to request to parse IFD0.
1082523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
1092523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    public static final int OPTION_IFD_0 = 1 << 0;
1102523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
1112523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * Option bit to request to parse IFD1.
1122523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
1132523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    public static final int OPTION_IFD_1 = 1 << 1;
1142523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
1152523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * Option bit to request to parse Exif-IFD.
1162523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
1172523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    public static final int OPTION_IFD_EXIF = 1 << 2;
1182523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
1192523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * Option bit to request to parse GPS-IFD.
1202523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
1212523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    public static final int OPTION_IFD_GPS = 1 << 3;
1222523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
1232523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * Option bit to request to parse Interoperability-IFD.
1242523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
1252523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    public static final int OPTION_IFD_INTEROPERABILITY = 1 << 4;
1262523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
1272523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * Option bit to request to parse thumbnail.
1282523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
1292523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    public static final int OPTION_THUMBNAIL = 1 << 5;
1302523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
131c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected static final int EXIF_HEADER = 0x45786966; // EXIF header "Exif"
132c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected static final short EXIF_HEADER_TAIL = (short) 0x0000; // EXIF header in APP1
1332523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
1342523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    // TIFF header
135c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected static final short LITTLE_ENDIAN_TAG = (short) 0x4949; // "II"
136c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected static final short BIG_ENDIAN_TAG = (short) 0x4d4d; // "MM"
137c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected static final short TIFF_HEADER_TAIL = 0x002A;
1382523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
139c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected static final int TAG_SIZE = 12;
140c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected static final int OFFSET_SIZE = 2;
1412523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
142ff0f96c07827c39df5a0b408a028e7198dc8294bEarl Ou    private static final Charset US_ASCII = Charset.forName("US-ASCII");
143ff0f96c07827c39df5a0b408a028e7198dc8294bEarl Ou
144c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected static final int DEFAULT_IFD0_OFFSET = 8;
1450490334cba2583a3690b8c58377394689f778ec9Earl Ou
1462523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private final CountedDataInputStream mTiffStream;
1472523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private final int mOptions;
1482523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private int mIfdStartOffset = 0;
1492523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private int mNumOfTagInIfd = 0;
1502523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private int mIfdType;
1512523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private ExifTag mTag;
1522523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private ImageEvent mImageEvent;
1532523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private int mStripCount;
1542523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private ExifTag mStripSizeTag;
1552523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private ExifTag mJpegSizeTag;
1562523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private boolean mNeedToParseOffsetsInCurrentIfd;
1572523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private boolean mContainExifData = false;
1580490334cba2583a3690b8c58377394689f778ec9Earl Ou    private int mApp1End;
159c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    private int mOffsetToApp1EndFromSOF = 0;
1600490334cba2583a3690b8c58377394689f778ec9Earl Ou    private byte[] mDataAboveIfd0;
1610490334cba2583a3690b8c58377394689f778ec9Earl Ou    private int mIfd0Position;
162c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou    private int mTiffStartPosition;
163c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    private final ExifInterface mInterface;
164c274ded801f745d6318186958107622e7a4fef33Ruben Brunk
165c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    private static final short TAG_EXIF_IFD = ExifInterface
166c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            .getTrueTagKey(ExifInterface.TAG_EXIF_IFD);
167c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    private static final short TAG_GPS_IFD = ExifInterface.getTrueTagKey(ExifInterface.TAG_GPS_IFD);
168c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    private static final short TAG_INTEROPERABILITY_IFD = ExifInterface
169c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            .getTrueTagKey(ExifInterface.TAG_INTEROPERABILITY_IFD);
170c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    private static final short TAG_JPEG_INTERCHANGE_FORMAT = ExifInterface
171c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            .getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT);
172c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    private static final short TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = ExifInterface
173c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            .getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
174c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    private static final short TAG_STRIP_OFFSETS = ExifInterface
175c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            .getTrueTagKey(ExifInterface.TAG_STRIP_OFFSETS);
176c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    private static final short TAG_STRIP_BYTE_COUNTS = ExifInterface
177c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            .getTrueTagKey(ExifInterface.TAG_STRIP_BYTE_COUNTS);
1782523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
1792523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private final TreeMap<Integer, Object> mCorrespondingEvent = new TreeMap<Integer, Object>();
1802523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
1812523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private boolean isIfdRequested(int ifdType) {
1822523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        switch (ifdType) {
1832523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            case IfdId.TYPE_IFD_0:
1842523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                return (mOptions & OPTION_IFD_0) != 0;
1852523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            case IfdId.TYPE_IFD_1:
1862523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                return (mOptions & OPTION_IFD_1) != 0;
1872523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            case IfdId.TYPE_IFD_EXIF:
1882523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                return (mOptions & OPTION_IFD_EXIF) != 0;
1892523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            case IfdId.TYPE_IFD_GPS:
1902523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                return (mOptions & OPTION_IFD_GPS) != 0;
1912523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            case IfdId.TYPE_IFD_INTEROPERABILITY:
1922523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                return (mOptions & OPTION_IFD_INTEROPERABILITY) != 0;
1932523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        }
1942523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        return false;
1952523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
1962523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
1972523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private boolean isThumbnailRequested() {
1982523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        return (mOptions & OPTION_THUMBNAIL) != 0;
1992523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
2002523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
201c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    private ExifParser(InputStream inputStream, int options, ExifInterface iRef)
2022523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            throws IOException, ExifInvalidFormatException {
203ec965b6ca57d3422e50bc1a476e0ff046f768ef5Ruben Brunk        if (inputStream == null) {
204ec965b6ca57d3422e50bc1a476e0ff046f768ef5Ruben Brunk            throw new IOException("Null argument inputStream to ExifParser");
205ec965b6ca57d3422e50bc1a476e0ff046f768ef5Ruben Brunk        }
206c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        if (LOGV) {
207c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            Log.v(TAG, "Reading exif...");
208c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        }
209c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        mInterface = iRef;
2102523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        mContainExifData = seekTiffData(inputStream);
2112523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        mTiffStream = new CountedDataInputStream(inputStream);
2122523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        mOptions = options;
213c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        if (!mContainExifData) {
214c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            return;
215c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        }
2160490334cba2583a3690b8c58377394689f778ec9Earl Ou
2170490334cba2583a3690b8c58377394689f778ec9Earl Ou        parseTiffHeader();
2180490334cba2583a3690b8c58377394689f778ec9Earl Ou        long offset = mTiffStream.readUnsignedInt();
2190490334cba2583a3690b8c58377394689f778ec9Earl Ou        if (offset > Integer.MAX_VALUE) {
2200490334cba2583a3690b8c58377394689f778ec9Earl Ou            throw new ExifInvalidFormatException("Invalid offset " + offset);
2210490334cba2583a3690b8c58377394689f778ec9Earl Ou        }
2220490334cba2583a3690b8c58377394689f778ec9Earl Ou        mIfd0Position = (int) offset;
223c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou        mIfdType = IfdId.TYPE_IFD_0;
224c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou        if (isIfdRequested(IfdId.TYPE_IFD_0) || needToParseOffsetsInCurrentIfd()) {
225c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou            registerIfd(IfdId.TYPE_IFD_0, offset);
226c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou            if (offset != DEFAULT_IFD0_OFFSET) {
227c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou                mDataAboveIfd0 = new byte[(int) offset - DEFAULT_IFD0_OFFSET];
228c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou                read(mDataAboveIfd0);
229c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou            }
2302523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        }
2312523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
2322523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
2332523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
2342523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * Parses the the given InputStream with the given options
235c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     *
2362523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @exception IOException
2372523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @exception ExifInvalidFormatException
2382523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
239c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected static ExifParser parse(InputStream inputStream, int options, ExifInterface iRef)
240c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou            throws IOException, ExifInvalidFormatException {
241c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        return new ExifParser(inputStream, options, iRef);
2422523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
2432523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
2442523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
245c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * Parses the the given InputStream with default options; that is, every IFD
246c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * and thumbnaill will be parsed.
247c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     *
2482523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @exception IOException
2492523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @exception ExifInvalidFormatException
2502523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @see #parse(InputStream, int)
2512523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
252c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected static ExifParser parse(InputStream inputStream, ExifInterface iRef)
2532523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            throws IOException, ExifInvalidFormatException {
2542523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        return new ExifParser(inputStream, OPTION_IFD_0 | OPTION_IFD_1
2552523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                | OPTION_IFD_EXIF | OPTION_IFD_GPS | OPTION_IFD_INTEROPERABILITY
256c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                | OPTION_THUMBNAIL, iRef);
2572523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
2582523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
2592523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
2602523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * Moves the parser forward and returns the next parsing event
2612523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     *
2622523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @exception IOException
2632523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @exception ExifInvalidFormatException
2642523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @see #EVENT_START_OF_IFD
2652523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @see #EVENT_NEW_TAG
2662523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @see #EVENT_VALUE_OF_REGISTERED_TAG
2672523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @see #EVENT_COMPRESSED_IMAGE
2682523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @see #EVENT_UNCOMPRESSED_STRIP
2692523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @see #EVENT_END
2702523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
271c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected int next() throws IOException, ExifInvalidFormatException {
2722523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        if (!mContainExifData) {
2732523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            return EVENT_END;
2742523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        }
2752523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        int offset = mTiffStream.getReadByteCount();
2762523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        int endOfTags = mIfdStartOffset + OFFSET_SIZE + TAG_SIZE * mNumOfTagInIfd;
2772523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        if (offset < endOfTags) {
2782523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            mTag = readTag();
279c57d5a6b1e5e85c40d751b33dd868e29ccf4504eEarl Ou            if (mTag == null) {
280c57d5a6b1e5e85c40d751b33dd868e29ccf4504eEarl Ou                return next();
281c57d5a6b1e5e85c40d751b33dd868e29ccf4504eEarl Ou            }
2822523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            if (mNeedToParseOffsetsInCurrentIfd) {
2832523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                checkOffsetOrImageTag(mTag);
2842523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            }
2852523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            return EVENT_NEW_TAG;
2862523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        } else if (offset == endOfTags) {
2872523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            // There is a link to ifd1 at the end of ifd0
2882523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            if (mIfdType == IfdId.TYPE_IFD_0) {
2897e92ec75da5e2eb06e659e2226f64749b80ea3d9Earl Ou                long ifdOffset = readUnsignedLong();
2902523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                if (isIfdRequested(IfdId.TYPE_IFD_1) || isThumbnailRequested()) {
2912523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                    if (ifdOffset != 0) {
2922523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                        registerIfd(IfdId.TYPE_IFD_1, ifdOffset);
2932523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                    }
2942523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                }
2952523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            } else {
2967e92ec75da5e2eb06e659e2226f64749b80ea3d9Earl Ou                int offsetSize = 4;
2977e92ec75da5e2eb06e659e2226f64749b80ea3d9Earl Ou                // Some camera models use invalid length of the offset
2987e92ec75da5e2eb06e659e2226f64749b80ea3d9Earl Ou                if (mCorrespondingEvent.size() > 0) {
2997e92ec75da5e2eb06e659e2226f64749b80ea3d9Earl Ou                    offsetSize = mCorrespondingEvent.firstEntry().getKey() -
3007e92ec75da5e2eb06e659e2226f64749b80ea3d9Earl Ou                            mTiffStream.getReadByteCount();
3017e92ec75da5e2eb06e659e2226f64749b80ea3d9Earl Ou                }
3027e92ec75da5e2eb06e659e2226f64749b80ea3d9Earl Ou                if (offsetSize < 4) {
3037e92ec75da5e2eb06e659e2226f64749b80ea3d9Earl Ou                    Log.w(TAG, "Invalid size of link to next IFD: " + offsetSize);
3047e92ec75da5e2eb06e659e2226f64749b80ea3d9Earl Ou                } else {
3057e92ec75da5e2eb06e659e2226f64749b80ea3d9Earl Ou                    long ifdOffset = readUnsignedLong();
3067e92ec75da5e2eb06e659e2226f64749b80ea3d9Earl Ou                    if (ifdOffset != 0) {
3077e92ec75da5e2eb06e659e2226f64749b80ea3d9Earl Ou                        Log.w(TAG, "Invalid link to next IFD: " + ifdOffset);
3087e92ec75da5e2eb06e659e2226f64749b80ea3d9Earl Ou                    }
3092523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                }
3102523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            }
3112523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        }
312c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        while (mCorrespondingEvent.size() != 0) {
3132523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            Entry<Integer, Object> entry = mCorrespondingEvent.pollFirstEntry();
3142523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            Object event = entry.getValue();
3150490334cba2583a3690b8c58377394689f778ec9Earl Ou            try {
3160490334cba2583a3690b8c58377394689f778ec9Earl Ou                skipTo(entry.getKey());
3170490334cba2583a3690b8c58377394689f778ec9Earl Ou            } catch (IOException e) {
3180490334cba2583a3690b8c58377394689f778ec9Earl Ou                Log.w(TAG, "Failed to skip to data at: " + entry.getKey() +
3190490334cba2583a3690b8c58377394689f778ec9Earl Ou                        " for " + event.getClass().getName() + ", the file may be broken.");
3200490334cba2583a3690b8c58377394689f778ec9Earl Ou                continue;
3210490334cba2583a3690b8c58377394689f778ec9Earl Ou            }
3222523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            if (event instanceof IfdEvent) {
3232523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                mIfdType = ((IfdEvent) event).ifd;
3242523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                mNumOfTagInIfd = mTiffStream.readUnsignedShort();
3252523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                mIfdStartOffset = entry.getKey();
3260490334cba2583a3690b8c58377394689f778ec9Earl Ou
3270490334cba2583a3690b8c58377394689f778ec9Earl Ou                if (mNumOfTagInIfd * TAG_SIZE + mIfdStartOffset + OFFSET_SIZE > mApp1End) {
3280490334cba2583a3690b8c58377394689f778ec9Earl Ou                    Log.w(TAG, "Invalid size of IFD " + mIfdType);
3290490334cba2583a3690b8c58377394689f778ec9Earl Ou                    return EVENT_END;
3300490334cba2583a3690b8c58377394689f778ec9Earl Ou                }
3310490334cba2583a3690b8c58377394689f778ec9Earl Ou
3322523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                mNeedToParseOffsetsInCurrentIfd = needToParseOffsetsInCurrentIfd();
3332523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                if (((IfdEvent) event).isRequested) {
3342523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                    return EVENT_START_OF_IFD;
3352523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                } else {
3362523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                    skipRemainingTagsInCurrentIfd();
3372523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                }
3382523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            } else if (event instanceof ImageEvent) {
3392523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                mImageEvent = (ImageEvent) event;
3402523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                return mImageEvent.type;
3412523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            } else {
3422523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                ExifTagEvent tagEvent = (ExifTagEvent) event;
3432523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                mTag = tagEvent.tag;
3442523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                if (mTag.getDataType() != ExifTag.TYPE_UNDEFINED) {
3452523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                    readFullTagValue(mTag);
3462523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                    checkOffsetOrImageTag(mTag);
3472523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                }
3482523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                if (tagEvent.isRequested) {
3492523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                    return EVENT_VALUE_OF_REGISTERED_TAG;
3502523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                }
3512523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            }
3522523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        }
3532523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        return EVENT_END;
3542523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
3552523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
3562523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
357c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * Skips the tags area of current IFD, if the parser is not in the tag area,
358c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * nothing will happen.
3592523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     *
3602523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @throws IOException
3612523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @throws ExifInvalidFormatException
3622523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
363c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected void skipRemainingTagsInCurrentIfd() throws IOException, ExifInvalidFormatException {
3642523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        int endOfTags = mIfdStartOffset + OFFSET_SIZE + TAG_SIZE * mNumOfTagInIfd;
3652523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        int offset = mTiffStream.getReadByteCount();
366c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        if (offset > endOfTags) {
367c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            return;
368c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        }
3692523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        if (mNeedToParseOffsetsInCurrentIfd) {
3702523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            while (offset < endOfTags) {
3712523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                mTag = readTag();
3722523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                offset += TAG_SIZE;
373c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                if (mTag == null) {
374c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                    continue;
375c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                }
376c57d5a6b1e5e85c40d751b33dd868e29ccf4504eEarl Ou                checkOffsetOrImageTag(mTag);
3772523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            }
3782523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        } else {
3792523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            skipTo(endOfTags);
3802523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        }
3812523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        long ifdOffset = readUnsignedLong();
3822523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        // For ifd0, there is a link to ifd1 in the end of all tags
3832523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        if (mIfdType == IfdId.TYPE_IFD_0
3842523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                && (isIfdRequested(IfdId.TYPE_IFD_1) || isThumbnailRequested())) {
3852523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            if (ifdOffset > 0) {
3862523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                registerIfd(IfdId.TYPE_IFD_1, ifdOffset);
3872523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            }
3882523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        }
3892523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
3902523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
3912523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private boolean needToParseOffsetsInCurrentIfd() {
3922523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        switch (mIfdType) {
3932523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            case IfdId.TYPE_IFD_0:
3942523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                return isIfdRequested(IfdId.TYPE_IFD_EXIF) || isIfdRequested(IfdId.TYPE_IFD_GPS)
395c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou                        || isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY)
396c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou                        || isIfdRequested(IfdId.TYPE_IFD_1);
3972523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            case IfdId.TYPE_IFD_1:
3982523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                return isThumbnailRequested();
3992523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            case IfdId.TYPE_IFD_EXIF:
4002523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                // The offset to interoperability IFD is located in Exif IFD
4012523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                return isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY);
4022523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            default:
4032523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                return false;
4042523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        }
4052523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
4062523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
4072523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
408c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * If {@link #next()} return {@link #EVENT_NEW_TAG} or
409c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * {@link #EVENT_VALUE_OF_REGISTERED_TAG}, call this function to get the
410c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * corresponding tag.
4112523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * <p>
412c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * For {@link #EVENT_NEW_TAG}, the tag may not contain the value if the size
413c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * of the value is greater than 4 bytes. One should call
414c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * {@link ExifTag#hasValue()} to check if the tag contains value. If there
415c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * is no value,call {@link #registerForTagValue(ExifTag)} to have the parser
416c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * emit {@link #EVENT_VALUE_OF_REGISTERED_TAG} when it reaches the area
417c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * pointed by the offset.
4182523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * <p>
419c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * When {@link #EVENT_VALUE_OF_REGISTERED_TAG} is emitted, the value of the
420c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * tag will have already been read except for tags of undefined type. For
421c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * tags of undefined type, call one of the read methods to get the value.
4222523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     *
4232523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @see #registerForTagValue(ExifTag)
4242523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @see #read(byte[])
4252523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @see #read(byte[], int, int)
4262523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @see #readLong()
4272523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @see #readRational()
4282523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @see #readString(int)
4292523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @see #readString(int, Charset)
4302523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
431c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected ExifTag getTag() {
4322523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        return mTag;
4332523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
4342523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
4352523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
4362523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * Gets number of tags in the current IFD area.
4372523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
438c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected int getTagCountInCurrentIfd() {
4392523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        return mNumOfTagInIfd;
4402523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
4412523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
4422523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
4432523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * Gets the ID of current IFD.
4442523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     *
4452523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @see IfdId#TYPE_IFD_0
4462523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @see IfdId#TYPE_IFD_1
4472523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @see IfdId#TYPE_IFD_GPS
4482523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @see IfdId#TYPE_IFD_INTEROPERABILITY
4492523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @see IfdId#TYPE_IFD_EXIF
4502523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
451c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected int getCurrentIfd() {
4522523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        return mIfdType;
4532523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
4542523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
4552523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
456c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * When receiving {@link #EVENT_UNCOMPRESSED_STRIP}, call this function to
457c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * get the index of this strip.
458c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     *
4592523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @see #getStripCount()
4602523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
461c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected int getStripIndex() {
4622523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        return mImageEvent.stripIndex;
4632523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
4642523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
4652523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
466c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * When receiving {@link #EVENT_UNCOMPRESSED_STRIP}, call this function to
467c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * get the number of strip data.
468c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     *
4692523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @see #getStripIndex()
4702523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
471c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected int getStripCount() {
4722523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        return mStripCount;
4732523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
4742523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
4752523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
476c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * When receiving {@link #EVENT_UNCOMPRESSED_STRIP}, call this function to
477c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * get the strip size.
4782523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
479c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected int getStripSize() {
480c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        if (mStripSizeTag == null)
481c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            return 0;
482994234e5b04864c9ac12a78de5ccdbe966cb8fa7Earl Ou        return (int) mStripSizeTag.getValueAt(0);
4832523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
4842523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
4852523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
486c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * When receiving {@link #EVENT_COMPRESSED_IMAGE}, call this function to get
487c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * the image data size.
4882523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
489c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected int getCompressedImageSize() {
490c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        if (mJpegSizeTag == null) {
491c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            return 0;
492c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        }
493994234e5b04864c9ac12a78de5ccdbe966cb8fa7Earl Ou        return (int) mJpegSizeTag.getValueAt(0);
4942523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
4952523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
4962523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private void skipTo(int offset) throws IOException {
4972523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        mTiffStream.skipTo(offset);
4982523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        while (!mCorrespondingEvent.isEmpty() && mCorrespondingEvent.firstKey() < offset) {
4992523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            mCorrespondingEvent.pollFirstEntry();
5002523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        }
5012523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
5022523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
5032523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
504c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * When getting {@link #EVENT_NEW_TAG} in the tag area of IFD, the tag may
505c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * not contain the value if the size of the value is greater than 4 bytes.
506c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * When the value is not available here, call this method so that the parser
507c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * will emit {@link #EVENT_VALUE_OF_REGISTERED_TAG} when it reaches the area
508c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * where the value is located.
509c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     *
5102523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * @see #EVENT_VALUE_OF_REGISTERED_TAG
5112523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
512c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected void registerForTagValue(ExifTag tag) {
513310ef8d4745a15f04e647b834a7d94e9dc7e1cabRuben Brunk        if (tag.getOffset() >= mTiffStream.getReadByteCount()) {
514310ef8d4745a15f04e647b834a7d94e9dc7e1cabRuben Brunk            mCorrespondingEvent.put(tag.getOffset(), new ExifTagEvent(tag, true));
515310ef8d4745a15f04e647b834a7d94e9dc7e1cabRuben Brunk        }
5162523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
5172523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
5182523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private void registerIfd(int ifdType, long offset) {
5192523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        // Cast unsigned int to int since the offset is always smaller
5202523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        // than the size of APP1 (65536)
5212523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        mCorrespondingEvent.put((int) offset, new IfdEvent(ifdType, isIfdRequested(ifdType)));
5222523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
5232523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
5242523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private void registerCompressedImage(long offset) {
5252523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        mCorrespondingEvent.put((int) offset, new ImageEvent(EVENT_COMPRESSED_IMAGE));
5262523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
5272523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
5282523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private void registerUncompressedStrip(int stripIndex, long offset) {
5292523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        mCorrespondingEvent.put((int) offset, new ImageEvent(EVENT_UNCOMPRESSED_STRIP
5302523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                , stripIndex));
5312523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
5322523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
5332523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private ExifTag readTag() throws IOException, ExifInvalidFormatException {
5342523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        short tagId = mTiffStream.readShort();
5352523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        short dataFormat = mTiffStream.readShort();
5362523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        long numOfComp = mTiffStream.readUnsignedInt();
5372523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        if (numOfComp > Integer.MAX_VALUE) {
5382523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            throw new ExifInvalidFormatException(
5392523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                    "Number of component is larger then Integer.MAX_VALUE");
5402523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        }
541c57d5a6b1e5e85c40d751b33dd868e29ccf4504eEarl Ou        // Some invalid image file contains invalid data type. Ignore those tags
542c57d5a6b1e5e85c40d751b33dd868e29ccf4504eEarl Ou        if (!ExifTag.isValidType(dataFormat)) {
543c57d5a6b1e5e85c40d751b33dd868e29ccf4504eEarl Ou            Log.w(TAG, String.format("Tag %04x: Invalid data type %d", tagId, dataFormat));
544c57d5a6b1e5e85c40d751b33dd868e29ccf4504eEarl Ou            mTiffStream.skip(4);
545c57d5a6b1e5e85c40d751b33dd868e29ccf4504eEarl Ou            return null;
546c57d5a6b1e5e85c40d751b33dd868e29ccf4504eEarl Ou        }
547c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        // TODO: handle numOfComp overflow
548c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        ExifTag tag = new ExifTag(tagId, dataFormat, (int) numOfComp, mIfdType,
549c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                ((int) numOfComp) != ExifTag.SIZE_UNDEFINED);
5502523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        int dataSize = tag.getDataSize();
5512523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        if (dataSize > 4) {
5522523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            long offset = mTiffStream.readUnsignedInt();
5532523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            if (offset > Integer.MAX_VALUE) {
5542523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                throw new ExifInvalidFormatException(
5552523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                        "offset is larger then Integer.MAX_VALUE");
5562523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            }
5570490334cba2583a3690b8c58377394689f778ec9Earl Ou            // Some invalid images put some undefined data before IFD0.
5580490334cba2583a3690b8c58377394689f778ec9Earl Ou            // Read the data here.
5590490334cba2583a3690b8c58377394689f778ec9Earl Ou            if ((offset < mIfd0Position) && (dataFormat == ExifTag.TYPE_UNDEFINED)) {
5600490334cba2583a3690b8c58377394689f778ec9Earl Ou                byte[] buf = new byte[(int) numOfComp];
5610490334cba2583a3690b8c58377394689f778ec9Earl Ou                System.arraycopy(mDataAboveIfd0, (int) offset - DEFAULT_IFD0_OFFSET,
5620490334cba2583a3690b8c58377394689f778ec9Earl Ou                        buf, 0, (int) numOfComp);
5630490334cba2583a3690b8c58377394689f778ec9Earl Ou                tag.setValue(buf);
5640490334cba2583a3690b8c58377394689f778ec9Earl Ou            } else {
5650490334cba2583a3690b8c58377394689f778ec9Earl Ou                tag.setOffset((int) offset);
5660490334cba2583a3690b8c58377394689f778ec9Earl Ou            }
5672523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        } else {
568310ef8d4745a15f04e647b834a7d94e9dc7e1cabRuben Brunk            boolean defCount = tag.hasDefinedCount();
569310ef8d4745a15f04e647b834a7d94e9dc7e1cabRuben Brunk            // Set defined count to 0 so we can add \0 to non-terminated strings
570310ef8d4745a15f04e647b834a7d94e9dc7e1cabRuben Brunk            tag.setHasDefinedCount(false);
571310ef8d4745a15f04e647b834a7d94e9dc7e1cabRuben Brunk            // Read value
5722523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            readFullTagValue(tag);
573310ef8d4745a15f04e647b834a7d94e9dc7e1cabRuben Brunk            tag.setHasDefinedCount(defCount);
5742523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            mTiffStream.skip(4 - dataSize);
575c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou            // Set the offset to the position of value.
576c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou            tag.setOffset(mTiffStream.getReadByteCount() - 4);
5772523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        }
5782523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        return tag;
5792523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
5802523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
5812523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
582c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * Check the tag, if the tag is one of the offset tag that points to the IFD
583c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * or image the caller is interested in, register the IFD or image.
5842523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
5852523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private void checkOffsetOrImageTag(ExifTag tag) {
5860490334cba2583a3690b8c58377394689f778ec9Earl Ou        // Some invalid formattd image contains tag with 0 size.
5870490334cba2583a3690b8c58377394689f778ec9Earl Ou        if (tag.getComponentCount() == 0) {
5880490334cba2583a3690b8c58377394689f778ec9Earl Ou            return;
5890490334cba2583a3690b8c58377394689f778ec9Earl Ou        }
590c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        short tid = tag.getTagId();
591c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        int ifd = tag.getIfd();
592c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        if (tid == TAG_EXIF_IFD && checkAllowed(ifd, ExifInterface.TAG_EXIF_IFD)) {
593c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            if (isIfdRequested(IfdId.TYPE_IFD_EXIF)
594c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                    || isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY)) {
595c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                registerIfd(IfdId.TYPE_IFD_EXIF, tag.getValueAt(0));
596c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            }
597c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        } else if (tid == TAG_GPS_IFD && checkAllowed(ifd, ExifInterface.TAG_GPS_IFD)) {
598c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            if (isIfdRequested(IfdId.TYPE_IFD_GPS)) {
599c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                registerIfd(IfdId.TYPE_IFD_GPS, tag.getValueAt(0));
600c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            }
601c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        } else if (tid == TAG_INTEROPERABILITY_IFD
602c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                && checkAllowed(ifd, ExifInterface.TAG_INTEROPERABILITY_IFD)) {
603c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            if (isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY)) {
604c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                registerIfd(IfdId.TYPE_IFD_INTEROPERABILITY, tag.getValueAt(0));
605c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            }
606c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        } else if (tid == TAG_JPEG_INTERCHANGE_FORMAT
607c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                && checkAllowed(ifd, ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT)) {
608c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            if (isThumbnailRequested()) {
609c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                registerCompressedImage(tag.getValueAt(0));
610c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            }
611c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        } else if (tid == TAG_JPEG_INTERCHANGE_FORMAT_LENGTH
612c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                && checkAllowed(ifd, ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH)) {
613c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            if (isThumbnailRequested()) {
614c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                mJpegSizeTag = tag;
615c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            }
616c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        } else if (tid == TAG_STRIP_OFFSETS && checkAllowed(ifd, ExifInterface.TAG_STRIP_OFFSETS)) {
617c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            if (isThumbnailRequested()) {
618c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                if (tag.hasValue()) {
619c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                    for (int i = 0; i < tag.getComponentCount(); i++) {
620c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                        if (tag.getDataType() == ExifTag.TYPE_UNSIGNED_SHORT) {
621c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                            registerUncompressedStrip(i, tag.getValueAt(i));
622c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                        } else {
623c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                            registerUncompressedStrip(i, tag.getValueAt(i));
6242523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                        }
6252523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                    }
626c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                } else {
627c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                    mCorrespondingEvent.put(tag.getOffset(), new ExifTagEvent(tag, false));
6282523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                }
629c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            }
630c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        } else if (tid == TAG_STRIP_BYTE_COUNTS
631c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                && checkAllowed(ifd, ExifInterface.TAG_STRIP_BYTE_COUNTS)
632c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                &&isThumbnailRequested() && tag.hasValue()) {
633c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            mStripSizeTag = tag;
634c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        }
635c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    }
636c274ded801f745d6318186958107622e7a4fef33Ruben Brunk
637c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    private boolean checkAllowed(int ifd, int tagId) {
638c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        int info = mInterface.getTagInfo().get(tagId);
639c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        if (info == ExifInterface.DEFINITION_NULL) {
640c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            return false;
6412523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        }
642c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        return ExifInterface.isIfdAllowed(info, ifd);
6432523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
6442523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
645c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected void readFullTagValue(ExifTag tag) throws IOException {
6460490334cba2583a3690b8c58377394689f778ec9Earl Ou        // Some invalid images contains tags with wrong size, check it here
6470490334cba2583a3690b8c58377394689f778ec9Earl Ou        short type = tag.getDataType();
6480490334cba2583a3690b8c58377394689f778ec9Earl Ou        if (type == ExifTag.TYPE_ASCII || type == ExifTag.TYPE_UNDEFINED ||
6490490334cba2583a3690b8c58377394689f778ec9Earl Ou                type == ExifTag.TYPE_UNSIGNED_BYTE) {
6500490334cba2583a3690b8c58377394689f778ec9Earl Ou            int size = tag.getComponentCount();
6510490334cba2583a3690b8c58377394689f778ec9Earl Ou            if (mCorrespondingEvent.size() > 0) {
652c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                if (mCorrespondingEvent.firstEntry().getKey() < mTiffStream.getReadByteCount()
653c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                        + size) {
654310ef8d4745a15f04e647b834a7d94e9dc7e1cabRuben Brunk                    Object event = mCorrespondingEvent.firstEntry().getValue();
655310ef8d4745a15f04e647b834a7d94e9dc7e1cabRuben Brunk                    if (event instanceof ImageEvent) {
656310ef8d4745a15f04e647b834a7d94e9dc7e1cabRuben Brunk                        // Tag value overlaps thumbnail, ignore thumbnail.
657310ef8d4745a15f04e647b834a7d94e9dc7e1cabRuben Brunk                        Log.w(TAG, "Thumbnail overlaps value for tag: \n" + tag.toString());
658c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                        Entry<Integer, Object> entry = mCorrespondingEvent.pollFirstEntry();
659c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                        Log.w(TAG, "Invalid thumbnail offset: " + entry.getKey());
660c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                    } else {
661310ef8d4745a15f04e647b834a7d94e9dc7e1cabRuben Brunk                        // Tag value overlaps another tag, shorten count
662310ef8d4745a15f04e647b834a7d94e9dc7e1cabRuben Brunk                        if (event instanceof IfdEvent) {
663310ef8d4745a15f04e647b834a7d94e9dc7e1cabRuben Brunk                            Log.w(TAG, "Ifd " + ((IfdEvent) event).ifd
664310ef8d4745a15f04e647b834a7d94e9dc7e1cabRuben Brunk                                    + " overlaps value for tag: \n" + tag.toString());
665310ef8d4745a15f04e647b834a7d94e9dc7e1cabRuben Brunk                        } else if (event instanceof ExifTagEvent) {
666310ef8d4745a15f04e647b834a7d94e9dc7e1cabRuben Brunk                            Log.w(TAG, "Tag value for tag: \n"
667310ef8d4745a15f04e647b834a7d94e9dc7e1cabRuben Brunk                                    + ((ExifTagEvent) event).tag.toString()
668310ef8d4745a15f04e647b834a7d94e9dc7e1cabRuben Brunk                                    + " overlaps value for tag: \n" + tag.toString());
669310ef8d4745a15f04e647b834a7d94e9dc7e1cabRuben Brunk                        }
670c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                        size = mCorrespondingEvent.firstEntry().getKey()
671c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                                - mTiffStream.getReadByteCount();
672c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                        Log.w(TAG, "Invalid size of tag: \n" + tag.toString()
673c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                                + " setting count to: " + size);
674c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                        tag.forceSetComponentCount(size);
675c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                    }
6760490334cba2583a3690b8c58377394689f778ec9Earl Ou                }
6770490334cba2583a3690b8c58377394689f778ec9Earl Ou            }
6780490334cba2583a3690b8c58377394689f778ec9Earl Ou        }
679c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        switch (tag.getDataType()) {
6802523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            case ExifTag.TYPE_UNSIGNED_BYTE:
681c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            case ExifTag.TYPE_UNDEFINED: {
682c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                byte buf[] = new byte[tag.getComponentCount()];
683c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                read(buf);
684c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                tag.setValue(buf);
685c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            }
6862523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                break;
6872523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            case ExifTag.TYPE_ASCII:
6882523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                tag.setValue(readString(tag.getComponentCount()));
6892523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                break;
690c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            case ExifTag.TYPE_UNSIGNED_LONG: {
691c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                long value[] = new long[tag.getComponentCount()];
692c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                for (int i = 0, n = value.length; i < n; i++) {
693c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                    value[i] = readUnsignedLong();
6942523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                }
695c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                tag.setValue(value);
696c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            }
6972523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                break;
698c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            case ExifTag.TYPE_UNSIGNED_RATIONAL: {
699c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                Rational value[] = new Rational[tag.getComponentCount()];
700c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                for (int i = 0, n = value.length; i < n; i++) {
701c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                    value[i] = readUnsignedRational();
702c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou                }
703c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                tag.setValue(value);
704c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            }
705c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou                break;
706c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            case ExifTag.TYPE_UNSIGNED_SHORT: {
707c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                int value[] = new int[tag.getComponentCount()];
708c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                for (int i = 0, n = value.length; i < n; i++) {
709c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                    value[i] = readUnsignedShort();
710c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou                }
711c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                tag.setValue(value);
712c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            }
713c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou                break;
714c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            case ExifTag.TYPE_LONG: {
715c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                int value[] = new int[tag.getComponentCount()];
716c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                for (int i = 0, n = value.length; i < n; i++) {
717c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                    value[i] = readLong();
718c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou                }
719c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                tag.setValue(value);
720c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            }
721c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou                break;
722c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            case ExifTag.TYPE_RATIONAL: {
723c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                Rational value[] = new Rational[tag.getComponentCount()];
724c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                for (int i = 0, n = value.length; i < n; i++) {
725c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                    value[i] = readRational();
726c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou                }
727c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                tag.setValue(value);
728c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            }
729c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou                break;
7302523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        }
731c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        if (LOGV) {
732c274ded801f745d6318186958107622e7a4fef33Ruben Brunk            Log.v(TAG, "\n" + tag.toString());
733c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        }
7342523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
7352523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
7362523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private void parseTiffHeader() throws IOException,
7372523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            ExifInvalidFormatException {
7382523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        short byteOrder = mTiffStream.readShort();
7392523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        if (LITTLE_ENDIAN_TAG == byteOrder) {
7402523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            mTiffStream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
7412523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        } else if (BIG_ENDIAN_TAG == byteOrder) {
7422523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            mTiffStream.setByteOrder(ByteOrder.BIG_ENDIAN);
7432523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        } else {
7442523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            throw new ExifInvalidFormatException("Invalid TIFF header");
7452523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        }
7462523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
7472523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        if (mTiffStream.readShort() != TIFF_HEADER_TAIL) {
7482523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            throw new ExifInvalidFormatException("Invalid TIFF header");
7492523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        }
7502523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
7512523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
7522523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private boolean seekTiffData(InputStream inputStream) throws IOException,
7532523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            ExifInvalidFormatException {
754c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou        CountedDataInputStream dataStream = new CountedDataInputStream(inputStream);
7552523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        if (dataStream.readShort() != JpegHeader.SOI) {
7562523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            throw new ExifInvalidFormatException("Invalid JPEG format");
7572523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        }
7582523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
7592523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        short marker = dataStream.readShort();
760c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        while (marker != JpegHeader.EOI
7612523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan                && !JpegHeader.isSofMarker(marker)) {
7622523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            int length = dataStream.readUnsignedShort();
7633f120e267f39712f0ae3c08557aa713faf45c210Earl Ou            // Some invalid formatted image contains multiple APP1,
7643f120e267f39712f0ae3c08557aa713faf45c210Earl Ou            // try to find the one with Exif data.
7653f120e267f39712f0ae3c08557aa713faf45c210Earl Ou            if (marker == JpegHeader.APP1) {
7663f120e267f39712f0ae3c08557aa713faf45c210Earl Ou                int header = 0;
7673f120e267f39712f0ae3c08557aa713faf45c210Earl Ou                short headerTail = 0;
7683f120e267f39712f0ae3c08557aa713faf45c210Earl Ou                if (length >= 8) {
7693f120e267f39712f0ae3c08557aa713faf45c210Earl Ou                    header = dataStream.readInt();
7703f120e267f39712f0ae3c08557aa713faf45c210Earl Ou                    headerTail = dataStream.readShort();
7713f120e267f39712f0ae3c08557aa713faf45c210Earl Ou                    length -= 6;
7723f120e267f39712f0ae3c08557aa713faf45c210Earl Ou                    if (header == EXIF_HEADER && headerTail == EXIF_HEADER_TAIL) {
773c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou                        mTiffStartPosition = dataStream.getReadByteCount();
7740490334cba2583a3690b8c58377394689f778ec9Earl Ou                        mApp1End = length;
775c274ded801f745d6318186958107622e7a4fef33Ruben Brunk                        mOffsetToApp1EndFromSOF = mTiffStartPosition + mApp1End;
7763f120e267f39712f0ae3c08557aa713faf45c210Earl Ou                        return true;
7773f120e267f39712f0ae3c08557aa713faf45c210Earl Ou                    }
7783f120e267f39712f0ae3c08557aa713faf45c210Earl Ou                }
7793f120e267f39712f0ae3c08557aa713faf45c210Earl Ou            }
7803f120e267f39712f0ae3c08557aa713faf45c210Earl Ou            if (length < 2 || (length - 2) != dataStream.skip(length - 2)) {
7813f120e267f39712f0ae3c08557aa713faf45c210Earl Ou                Log.w(TAG, "Invalid JPEG format.");
7823f120e267f39712f0ae3c08557aa713faf45c210Earl Ou                return false;
7832523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            }
7842523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            marker = dataStream.readShort();
7852523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        }
7863f120e267f39712f0ae3c08557aa713faf45c210Earl Ou        return false;
7872523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
7882523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
789c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected int getOffsetToExifEndFromSOF() {
790c274ded801f745d6318186958107622e7a4fef33Ruben Brunk        return mOffsetToApp1EndFromSOF;
791c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    }
792c274ded801f745d6318186958107622e7a4fef33Ruben Brunk
793c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected int getTiffStartPosition() {
794c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou        return mTiffStartPosition;
795c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou    }
796c06c8045b159d68f8fda051d59a0eb82215067eeEarl Ou
7972523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
7982523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * Reads bytes from the InputStream.
7992523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
800c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected int read(byte[] buffer, int offset, int length) throws IOException {
8012523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        return mTiffStream.read(buffer, offset, length);
8022523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
8032523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
8042523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
8052523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * Equivalent to read(buffer, 0, buffer.length).
8062523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
807c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected int read(byte[] buffer) throws IOException {
8082523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        return mTiffStream.read(buffer);
8092523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
8102523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
8112523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
812c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * Reads a String from the InputStream with US-ASCII charset. The parser
813c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * will read n bytes and convert it to ascii string. This is used for
814c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * reading values of type {@link ExifTag#TYPE_ASCII}.
8152523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
816c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected String readString(int n) throws IOException {
817ff0f96c07827c39df5a0b408a028e7198dc8294bEarl Ou        return readString(n, US_ASCII);
8182523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
8192523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
8202523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
821c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * Reads a String from the InputStream with the given charset. The parser
822c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * will read n bytes and convert it to string. This is used for reading
823c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * values of type {@link ExifTag#TYPE_ASCII}.
8242523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
825c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected String readString(int n, Charset charset) throws IOException {
826ff0f96c07827c39df5a0b408a028e7198dc8294bEarl Ou        if (n > 0) {
827ff0f96c07827c39df5a0b408a028e7198dc8294bEarl Ou            return mTiffStream.readString(n, charset);
828ff0f96c07827c39df5a0b408a028e7198dc8294bEarl Ou        } else {
829ff0f96c07827c39df5a0b408a028e7198dc8294bEarl Ou            return "";
830ff0f96c07827c39df5a0b408a028e7198dc8294bEarl Ou        }
8312523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
8322523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
8332523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
834c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * Reads value of type {@link ExifTag#TYPE_UNSIGNED_SHORT} from the
835c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * InputStream.
8362523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
837c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected int readUnsignedShort() throws IOException {
8382523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        return mTiffStream.readShort() & 0xffff;
8392523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
8402523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
8412523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
842c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * Reads value of type {@link ExifTag#TYPE_UNSIGNED_LONG} from the
843c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * InputStream.
8442523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
845c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected long readUnsignedLong() throws IOException {
8462523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        return readLong() & 0xffffffffL;
8472523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
8482523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
8492523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
850c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * Reads value of type {@link ExifTag#TYPE_UNSIGNED_RATIONAL} from the
851c274ded801f745d6318186958107622e7a4fef33Ruben Brunk     * InputStream.
8522523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
853c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected Rational readUnsignedRational() throws IOException {
8542523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        long nomi = readUnsignedLong();
8552523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        long denomi = readUnsignedLong();
8562523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        return new Rational(nomi, denomi);
8572523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
8582523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
8592523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
8602523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * Reads value of type {@link ExifTag#TYPE_LONG} from the InputStream.
8612523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
862c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected int readLong() throws IOException {
8632523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        return mTiffStream.readInt();
8642523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
8652523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
8662523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
8672523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * Reads value of type {@link ExifTag#TYPE_RATIONAL} from the InputStream.
8682523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
869c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected Rational readRational() throws IOException {
8702523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        int nomi = readLong();
8712523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        int denomi = readLong();
8722523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        return new Rational(nomi, denomi);
8732523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
8742523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
8752523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private static class ImageEvent {
8762523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        int stripIndex;
8772523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        int type;
878c274ded801f745d6318186958107622e7a4fef33Ruben Brunk
8792523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        ImageEvent(int type) {
8802523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            this.stripIndex = 0;
8812523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            this.type = type;
8822523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        }
883c274ded801f745d6318186958107622e7a4fef33Ruben Brunk
8842523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        ImageEvent(int type, int stripIndex) {
8852523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            this.type = type;
8862523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            this.stripIndex = stripIndex;
8872523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        }
8882523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
8892523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
8902523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private static class IfdEvent {
8912523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        int ifd;
8922523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        boolean isRequested;
893c274ded801f745d6318186958107622e7a4fef33Ruben Brunk
8942523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        IfdEvent(int ifd, boolean isInterestedIfd) {
8952523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            this.ifd = ifd;
8962523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            this.isRequested = isInterestedIfd;
8972523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        }
8982523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
8992523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
9002523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    private static class ExifTagEvent {
9012523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        ExifTag tag;
9022523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        boolean isRequested;
903c274ded801f745d6318186958107622e7a4fef33Ruben Brunk
9042523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        ExifTagEvent(ExifTag tag, boolean isRequireByUser) {
9052523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            this.tag = tag;
9062523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan            this.isRequested = isRequireByUser;
9072523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        }
9082523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
9092523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan
9102523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    /**
9112523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     * Gets the byte order of the current InputStream.
9122523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan     */
913c274ded801f745d6318186958107622e7a4fef33Ruben Brunk    protected ByteOrder getByteOrder() {
9142523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan        return mTiffStream.getByteOrder();
9152523f4344661b1e6a734d1ba20e92308c87a7c54Hung-ying Tyan    }
916ff0f96c07827c39df5a0b408a028e7198dc8294bEarl Ou}
917