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