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