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