/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifParser.java

https://github.com/aizuzi/platform_frameworks_base · Java · 916 lines · 593 code · 64 blank · 259 comment · 169 complexity · 8c2c90db5bb7c6491f6bad65a7b7d123 MD5 · raw file

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