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.messaging.util.exif;
     18 
     19 import android.util.Log;
     20 import com.android.messaging.util.LogUtil;
     21 
     22 import java.io.IOException;
     23 import java.io.InputStream;
     24 import java.nio.ByteOrder;
     25 import java.nio.charset.Charset;
     26 import java.util.Map.Entry;
     27 import java.util.TreeMap;
     28 
     29 /**
     30  * This class provides a low-level EXIF parsing API. Given a JPEG format
     31  * InputStream, the caller can request which IFD's to read via
     32  * {@link #parse(java.io.InputStream, int)} with given options.
     33  * <p>
     34  * Below is an example of getting EXIF data from IFD 0 and EXIF IFD using the
     35  * parser.
     36  *
     37  * <pre>
     38  * void parse() {
     39  *     ExifParser parser = ExifParser.parse(mImageInputStream,
     40  *             ExifParser.OPTION_IFD_0 | ExifParser.OPTIONS_IFD_EXIF);
     41  *     int event = parser.next();
     42  *     while (event != ExifParser.EVENT_END) {
     43  *         switch (event) {
     44  *             case ExifParser.EVENT_START_OF_IFD:
     45  *                 break;
     46  *             case ExifParser.EVENT_NEW_TAG:
     47  *                 ExifTag tag = parser.getTag();
     48  *                 if (!tag.hasValue()) {
     49  *                     parser.registerForTagValue(tag);
     50  *                 } else {
     51  *                     processTag(tag);
     52  *                 }
     53  *                 break;
     54  *             case ExifParser.EVENT_VALUE_OF_REGISTERED_TAG:
     55  *                 tag = parser.getTag();
     56  *                 if (tag.getDataType() != ExifTag.TYPE_UNDEFINED) {
     57  *                     processTag(tag);
     58  *                 }
     59  *                 break;
     60  *         }
     61  *         event = parser.next();
     62  *     }
     63  * }
     64  *
     65  * void processTag(ExifTag tag) {
     66  *     // process the tag as you like.
     67  * }
     68  * </pre>
     69  */
     70 public class ExifParser {
     71     private static final boolean LOGV = false;
     72     private static final String TAG = LogUtil.BUGLE_TAG;
     73     /**
     74      * When the parser reaches a new IFD area. Call {@link #getCurrentIfd()} to
     75      * know which IFD we are in.
     76      */
     77     public static final int EVENT_START_OF_IFD = 0;
     78     /**
     79      * When the parser reaches a new tag. Call {@link #getTag()}to get the
     80      * corresponding tag.
     81      */
     82     public static final int EVENT_NEW_TAG = 1;
     83     /**
     84      * When the parser reaches the value area of tag that is registered by
     85      * {@link #registerForTagValue(ExifTag)} previously. Call {@link #getTag()}
     86      * to get the corresponding tag.
     87      */
     88     public static final int EVENT_VALUE_OF_REGISTERED_TAG = 2;
     89 
     90     /**
     91      * When the parser reaches the compressed image area.
     92      */
     93     public static final int EVENT_COMPRESSED_IMAGE = 3;
     94     /**
     95      * When the parser reaches the uncompressed image strip. Call
     96      * {@link #getStripIndex()} to get the index of the strip.
     97      *
     98      * @see #getStripIndex()
     99      * @see #getStripCount()
    100      */
    101     public static final int EVENT_UNCOMPRESSED_STRIP = 4;
    102     /**
    103      * When there is nothing more to parse.
    104      */
    105     public static final int EVENT_END = 5;
    106 
    107     /**
    108      * Option bit to request to parse IFD0.
    109      */
    110     public static final int OPTION_IFD_0 = 1 << 0;
    111     /**
    112      * Option bit to request to parse IFD1.
    113      */
    114     public static final int OPTION_IFD_1 = 1 << 1;
    115     /**
    116      * Option bit to request to parse Exif-IFD.
    117      */
    118     public static final int OPTION_IFD_EXIF = 1 << 2;
    119     /**
    120      * Option bit to request to parse GPS-IFD.
    121      */
    122     public static final int OPTION_IFD_GPS = 1 << 3;
    123     /**
    124      * Option bit to request to parse Interoperability-IFD.
    125      */
    126     public static final int OPTION_IFD_INTEROPERABILITY = 1 << 4;
    127     /**
    128      * Option bit to request to parse thumbnail.
    129      */
    130     public static final int OPTION_THUMBNAIL = 1 << 5;
    131 
    132     protected static final int EXIF_HEADER = 0x45786966; // EXIF header "Exif"
    133     protected static final short EXIF_HEADER_TAIL = (short) 0x0000; // EXIF header in APP1
    134 
    135     // TIFF header
    136     protected static final short LITTLE_ENDIAN_TAG = (short) 0x4949; // "II"
    137     protected static final short BIG_ENDIAN_TAG = (short) 0x4d4d; // "MM"
    138     protected static final short TIFF_HEADER_TAIL = 0x002A;
    139 
    140     protected static final int TAG_SIZE = 12;
    141     protected static final int OFFSET_SIZE = 2;
    142 
    143     private static final Charset US_ASCII = Charset.forName("US-ASCII");
    144 
    145     protected static final int DEFAULT_IFD0_OFFSET = 8;
    146 
    147     private final CountedDataInputStream mTiffStream;
    148     private final int mOptions;
    149     private int mIfdStartOffset = 0;
    150     private int mNumOfTagInIfd = 0;
    151     private int mIfdType;
    152     private ExifTag mTag;
    153     private ImageEvent mImageEvent;
    154     private int mStripCount;
    155     private ExifTag mStripSizeTag;
    156     private ExifTag mJpegSizeTag;
    157     private boolean mNeedToParseOffsetsInCurrentIfd;
    158     private boolean mContainExifData = false;
    159     private int mApp1End;
    160     private int mOffsetToApp1EndFromSOF = 0;
    161     private byte[] mDataAboveIfd0;
    162     private int mIfd0Position;
    163     private int mTiffStartPosition;
    164     private final ExifInterface mInterface;
    165 
    166     private static final short TAG_EXIF_IFD = ExifInterface
    167             .getTrueTagKey(ExifInterface.TAG_EXIF_IFD);
    168     private static final short TAG_GPS_IFD = ExifInterface.getTrueTagKey(ExifInterface.TAG_GPS_IFD);
    169     private static final short TAG_INTEROPERABILITY_IFD = ExifInterface
    170             .getTrueTagKey(ExifInterface.TAG_INTEROPERABILITY_IFD);
    171     private static final short TAG_JPEG_INTERCHANGE_FORMAT = ExifInterface
    172             .getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT);
    173     private static final short TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = ExifInterface
    174             .getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
    175     private static final short TAG_STRIP_OFFSETS = ExifInterface
    176             .getTrueTagKey(ExifInterface.TAG_STRIP_OFFSETS);
    177     private static final short TAG_STRIP_BYTE_COUNTS = ExifInterface
    178             .getTrueTagKey(ExifInterface.TAG_STRIP_BYTE_COUNTS);
    179 
    180     private final TreeMap<Integer, Object> mCorrespondingEvent = new TreeMap<Integer, Object>();
    181 
    182     private boolean isIfdRequested(int ifdType) {
    183         switch (ifdType) {
    184             case IfdId.TYPE_IFD_0:
    185                 return (mOptions & OPTION_IFD_0) != 0;
    186             case IfdId.TYPE_IFD_1:
    187                 return (mOptions & OPTION_IFD_1) != 0;
    188             case IfdId.TYPE_IFD_EXIF:
    189                 return (mOptions & OPTION_IFD_EXIF) != 0;
    190             case IfdId.TYPE_IFD_GPS:
    191                 return (mOptions & OPTION_IFD_GPS) != 0;
    192             case IfdId.TYPE_IFD_INTEROPERABILITY:
    193                 return (mOptions & OPTION_IFD_INTEROPERABILITY) != 0;
    194         }
    195         return false;
    196     }
    197 
    198     private boolean isThumbnailRequested() {
    199         return (mOptions & OPTION_THUMBNAIL) != 0;
    200     }
    201 
    202     private ExifParser(InputStream inputStream, int options, ExifInterface iRef)
    203             throws IOException, ExifInvalidFormatException {
    204         if (inputStream == null) {
    205             throw new IOException("Null argument inputStream to ExifParser");
    206         }
    207         if (LOGV) {
    208             Log.v(TAG, "Reading exif...");
    209         }
    210         mInterface = iRef;
    211         mContainExifData = seekTiffData(inputStream);
    212         mTiffStream = new CountedDataInputStream(inputStream);
    213         mOptions = options;
    214         if (!mContainExifData) {
    215             return;
    216         }
    217 
    218         parseTiffHeader();
    219         long offset = mTiffStream.readUnsignedInt();
    220         if (offset > Integer.MAX_VALUE) {
    221             throw new ExifInvalidFormatException("Invalid offset " + offset);
    222         }
    223         mIfd0Position = (int) offset;
    224         mIfdType = IfdId.TYPE_IFD_0;
    225         if (isIfdRequested(IfdId.TYPE_IFD_0) || needToParseOffsetsInCurrentIfd()) {
    226             registerIfd(IfdId.TYPE_IFD_0, offset);
    227             if (offset != DEFAULT_IFD0_OFFSET) {
    228                 mDataAboveIfd0 = new byte[(int) offset - DEFAULT_IFD0_OFFSET];
    229                 read(mDataAboveIfd0);
    230             }
    231         }
    232     }
    233 
    234     /**
    235      * Parses the the given InputStream with the given options
    236      *
    237      * @exception java.io.IOException
    238      * @exception ExifInvalidFormatException
    239      */
    240     protected static ExifParser parse(InputStream inputStream, int options, ExifInterface iRef)
    241             throws IOException, ExifInvalidFormatException {
    242         return new ExifParser(inputStream, options, iRef);
    243     }
    244 
    245     /**
    246      * Parses the the given InputStream with default options; that is, every IFD
    247      * and thumbnaill will be parsed.
    248      *
    249      * @exception java.io.IOException
    250      * @exception ExifInvalidFormatException
    251      * @see #parse(java.io.InputStream, int)
    252      */
    253     protected static ExifParser parse(InputStream inputStream, ExifInterface iRef)
    254             throws IOException, ExifInvalidFormatException {
    255         return new ExifParser(inputStream, OPTION_IFD_0 | OPTION_IFD_1
    256                 | OPTION_IFD_EXIF | OPTION_IFD_GPS | OPTION_IFD_INTEROPERABILITY
    257                 | OPTION_THUMBNAIL, iRef);
    258     }
    259 
    260     /**
    261      * Moves the parser forward and returns the next parsing event
    262      *
    263      * @exception java.io.IOException
    264      * @exception ExifInvalidFormatException
    265      * @see #EVENT_START_OF_IFD
    266      * @see #EVENT_NEW_TAG
    267      * @see #EVENT_VALUE_OF_REGISTERED_TAG
    268      * @see #EVENT_COMPRESSED_IMAGE
    269      * @see #EVENT_UNCOMPRESSED_STRIP
    270      * @see #EVENT_END
    271      */
    272     protected int next() throws IOException, ExifInvalidFormatException {
    273         if (!mContainExifData) {
    274             return EVENT_END;
    275         }
    276         int offset = mTiffStream.getReadByteCount();
    277         int endOfTags = mIfdStartOffset + OFFSET_SIZE + TAG_SIZE * mNumOfTagInIfd;
    278         if (offset < endOfTags) {
    279             mTag = readTag();
    280             if (mTag == null) {
    281                 return next();
    282             }
    283             if (mNeedToParseOffsetsInCurrentIfd) {
    284                 checkOffsetOrImageTag(mTag);
    285             }
    286             return EVENT_NEW_TAG;
    287         } else if (offset == endOfTags) {
    288             // There is a link to ifd1 at the end of ifd0
    289             if (mIfdType == IfdId.TYPE_IFD_0) {
    290                 long ifdOffset = readUnsignedLong();
    291                 if (isIfdRequested(IfdId.TYPE_IFD_1) || isThumbnailRequested()) {
    292                     if (ifdOffset != 0) {
    293                         registerIfd(IfdId.TYPE_IFD_1, ifdOffset);
    294                     }
    295                 }
    296             } else {
    297                 int offsetSize = 4;
    298                 // Some camera models use invalid length of the offset
    299                 if (mCorrespondingEvent.size() > 0) {
    300                     offsetSize = mCorrespondingEvent.firstEntry().getKey() -
    301                             mTiffStream.getReadByteCount();
    302                 }
    303                 if (offsetSize < 4) {
    304                     Log.w(TAG, "Invalid size of link to next IFD: " + offsetSize);
    305                 } else {
    306                     long ifdOffset = readUnsignedLong();
    307                     if (ifdOffset != 0) {
    308                         Log.w(TAG, "Invalid link to next IFD: " + ifdOffset);
    309                     }
    310                 }
    311             }
    312         }
    313         while (mCorrespondingEvent.size() != 0) {
    314             Entry<Integer, Object> entry = mCorrespondingEvent.pollFirstEntry();
    315             Object event = entry.getValue();
    316             try {
    317                 skipTo(entry.getKey());
    318             } catch (IOException e) {
    319                 Log.w(TAG, "Failed to skip to data at: " + entry.getKey() +
    320                         " for " + event.getClass().getName() + ", the file may be broken.");
    321                 continue;
    322             }
    323             if (event instanceof IfdEvent) {
    324                 mIfdType = ((IfdEvent) event).ifd;
    325                 mNumOfTagInIfd = mTiffStream.readUnsignedShort();
    326                 mIfdStartOffset = entry.getKey();
    327 
    328                 if (mNumOfTagInIfd * TAG_SIZE + mIfdStartOffset + OFFSET_SIZE > mApp1End) {
    329                     Log.w(TAG, "Invalid size of IFD " + mIfdType);
    330                     return EVENT_END;
    331                 }
    332 
    333                 mNeedToParseOffsetsInCurrentIfd = needToParseOffsetsInCurrentIfd();
    334                 if (((IfdEvent) event).isRequested) {
    335                     return EVENT_START_OF_IFD;
    336                 } else {
    337                     skipRemainingTagsInCurrentIfd();
    338                 }
    339             } else if (event instanceof ImageEvent) {
    340                 mImageEvent = (ImageEvent) event;
    341                 return mImageEvent.type;
    342             } else {
    343                 ExifTagEvent tagEvent = (ExifTagEvent) event;
    344                 mTag = tagEvent.tag;
    345                 if (mTag.getDataType() != ExifTag.TYPE_UNDEFINED) {
    346                     readFullTagValue(mTag);
    347                     checkOffsetOrImageTag(mTag);
    348                 }
    349                 if (tagEvent.isRequested) {
    350                     return EVENT_VALUE_OF_REGISTERED_TAG;
    351                 }
    352             }
    353         }
    354         return EVENT_END;
    355     }
    356 
    357     /**
    358      * Skips the tags area of current IFD, if the parser is not in the tag area,
    359      * nothing will happen.
    360      *
    361      * @throws java.io.IOException
    362      * @throws ExifInvalidFormatException
    363      */
    364     protected void skipRemainingTagsInCurrentIfd() throws IOException, ExifInvalidFormatException {
    365         int endOfTags = mIfdStartOffset + OFFSET_SIZE + TAG_SIZE * mNumOfTagInIfd;
    366         int offset = mTiffStream.getReadByteCount();
    367         if (offset > endOfTags) {
    368             return;
    369         }
    370         if (mNeedToParseOffsetsInCurrentIfd) {
    371             while (offset < endOfTags) {
    372                 mTag = readTag();
    373                 offset += TAG_SIZE;
    374                 if (mTag == null) {
    375                     continue;
    376                 }
    377                 checkOffsetOrImageTag(mTag);
    378             }
    379         } else {
    380             skipTo(endOfTags);
    381         }
    382         long ifdOffset = readUnsignedLong();
    383         // For ifd0, there is a link to ifd1 in the end of all tags
    384         if (mIfdType == IfdId.TYPE_IFD_0
    385                 && (isIfdRequested(IfdId.TYPE_IFD_1) || isThumbnailRequested())) {
    386             if (ifdOffset > 0) {
    387                 registerIfd(IfdId.TYPE_IFD_1, ifdOffset);
    388             }
    389         }
    390     }
    391 
    392     private boolean needToParseOffsetsInCurrentIfd() {
    393         switch (mIfdType) {
    394             case IfdId.TYPE_IFD_0:
    395                 return isIfdRequested(IfdId.TYPE_IFD_EXIF) || isIfdRequested(IfdId.TYPE_IFD_GPS)
    396                         || isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY)
    397                         || isIfdRequested(IfdId.TYPE_IFD_1);
    398             case IfdId.TYPE_IFD_1:
    399                 return isThumbnailRequested();
    400             case IfdId.TYPE_IFD_EXIF:
    401                 // The offset to interoperability IFD is located in Exif IFD
    402                 return isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY);
    403             default:
    404                 return false;
    405         }
    406     }
    407 
    408     /**
    409      * If {@link #next()} return {@link #EVENT_NEW_TAG} or
    410      * {@link #EVENT_VALUE_OF_REGISTERED_TAG}, call this function to get the
    411      * corresponding tag.
    412      * <p>
    413      * For {@link #EVENT_NEW_TAG}, the tag may not contain the value if the size
    414      * of the value is greater than 4 bytes. One should call
    415      * {@link ExifTag#hasValue()} to check if the tag contains value. If there
    416      * is no value,call {@link #registerForTagValue(ExifTag)} to have the parser
    417      * emit {@link #EVENT_VALUE_OF_REGISTERED_TAG} when it reaches the area
    418      * pointed by the offset.
    419      * <p>
    420      * When {@link #EVENT_VALUE_OF_REGISTERED_TAG} is emitted, the value of the
    421      * tag will have already been read except for tags of undefined type. For
    422      * tags of undefined type, call one of the read methods to get the value.
    423      *
    424      * @see #registerForTagValue(ExifTag)
    425      * @see #read(byte[])
    426      * @see #read(byte[], int, int)
    427      * @see #readLong()
    428      * @see #readRational()
    429      * @see #readString(int)
    430      * @see #readString(int, java.nio.charset.Charset)
    431      */
    432     protected ExifTag getTag() {
    433         return mTag;
    434     }
    435 
    436     /**
    437      * Gets number of tags in the current IFD area.
    438      */
    439     protected int getTagCountInCurrentIfd() {
    440         return mNumOfTagInIfd;
    441     }
    442 
    443     /**
    444      * Gets the ID of current IFD.
    445      *
    446      * @see IfdId#TYPE_IFD_0
    447      * @see IfdId#TYPE_IFD_1
    448      * @see IfdId#TYPE_IFD_GPS
    449      * @see IfdId#TYPE_IFD_INTEROPERABILITY
    450      * @see IfdId#TYPE_IFD_EXIF
    451      */
    452     protected int getCurrentIfd() {
    453         return mIfdType;
    454     }
    455 
    456     /**
    457      * When receiving {@link #EVENT_UNCOMPRESSED_STRIP}, call this function to
    458      * get the index of this strip.
    459      *
    460      * @see #getStripCount()
    461      */
    462     protected int getStripIndex() {
    463         return mImageEvent.stripIndex;
    464     }
    465 
    466     /**
    467      * When receiving {@link #EVENT_UNCOMPRESSED_STRIP}, call this function to
    468      * get the number of strip data.
    469      *
    470      * @see #getStripIndex()
    471      */
    472     protected int getStripCount() {
    473         return mStripCount;
    474     }
    475 
    476     /**
    477      * When receiving {@link #EVENT_UNCOMPRESSED_STRIP}, call this function to
    478      * get the strip size.
    479      */
    480     protected int getStripSize() {
    481         if (mStripSizeTag == null) {
    482             return 0;
    483         }
    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