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