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