From 4c1cb48500c2da3307c3da3744f2c0ce32930ef9 Mon Sep 17 00:00:00 2001 From: Earl Ou Date: Fri, 31 Aug 2012 10:52:18 +0800 Subject: Handle other header tag in ExifParser before APP1 Change-Id: I44398e3ed054de441810b795daff8d1edb06df59 --- .../android/gallery3d/exif/ExifOutputStream.java | 29 +++------------- src/com/android/gallery3d/exif/ExifParser.java | 33 +++++++++--------- src/com/android/gallery3d/exif/JpegHeader.java | 39 ++++++++++++++++++++++ 3 files changed, 59 insertions(+), 42 deletions(-) create mode 100644 src/com/android/gallery3d/exif/JpegHeader.java diff --git a/src/com/android/gallery3d/exif/ExifOutputStream.java b/src/com/android/gallery3d/exif/ExifOutputStream.java index 0f56014a4..e9475c53e 100644 --- a/src/com/android/gallery3d/exif/ExifOutputStream.java +++ b/src/com/android/gallery3d/exif/ExifOutputStream.java @@ -29,25 +29,6 @@ public class ExifOutputStream extends FilterOutputStream { private static final int STATE_FRAME_HEADER = 1; private static final int STATE_JPEG_DATA = 2; - private static final short SOI = (short) 0xFFD8; - private static final short APP1 = (short) 0xFFE1; - private static final short EOI = (short) 0xFFD9; - - /** - * SOF (start of frame). All value between SOF0 and SOF15 is SOF tag except for DHT, JPG, - * and DAC tag. - */ - private static final short SOF0 = (short) 0xFFC0; - private static final short SOF15 = (short) 0xFFCF; - private static final short DHT = (short) 0xFFC4; - private static final short JPG = (short) 0xFFC8; - private static final short DAC = (short) 0xFFCC; - - private static final boolean isSofMarker(short marker) { - return marker >= SOF0 && marker <= SOF15 && marker != DHT && marker != JPG - && marker != DAC; - } - private static final int EXIF_HEADER = 0x45786966; private static final short TIFF_HEADER = 0x002A; private static final short TIFF_BIG_ENDIAN = 0x4d4d; @@ -106,7 +87,7 @@ public class ExifOutputStream extends FilterOutputStream { length -= byteRead; if (mBuffer.position() < 2) return; mBuffer.rewind(); - assert(mBuffer.getShort() == SOI); + assert(mBuffer.getShort() == JpegHeader.SOI); out.write(mBuffer.array(), 0 ,2); mState = STATE_FRAME_HEADER; mBuffer.rewind(); @@ -120,7 +101,7 @@ public class ExifOutputStream extends FilterOutputStream { // Check if this image data doesn't contain SOF. if (mBuffer.position() == 2) { short tag = mBuffer.getShort(); - if (tag == EOI) { + if (tag == JpegHeader.EOI) { out.write(mBuffer.array(), 0, 2); mBuffer.rewind(); } @@ -128,10 +109,10 @@ public class ExifOutputStream extends FilterOutputStream { if (mBuffer.position() < 4) return; mBuffer.rewind(); short marker = mBuffer.getShort(); - if (marker == APP1) { + if (marker == JpegHeader.APP1) { mByteToSkip = (mBuffer.getShort() & 0xff) - 2; mState = STATE_JPEG_DATA; - } else if (!isSofMarker(marker)) { + } else if (!JpegHeader.isSofMarker(marker)) { out.write(mBuffer.array(), 0, 4); mByteToCopy = (mBuffer.getShort() & 0xff) - 2; } else { @@ -162,7 +143,7 @@ public class ExifOutputStream extends FilterOutputStream { int exifSize = calculateAllOffset(); OrderedDataOutputStream dataOutputStream = new OrderedDataOutputStream(out); dataOutputStream.setByteOrder(ByteOrder.BIG_ENDIAN); - dataOutputStream.writeShort(APP1); + dataOutputStream.writeShort(JpegHeader.APP1); dataOutputStream.writeShort((short) (exifSize + 8)); dataOutputStream.writeInt(EXIF_HEADER); dataOutputStream.writeShort((short) 0x0000); diff --git a/src/com/android/gallery3d/exif/ExifParser.java b/src/com/android/gallery3d/exif/ExifParser.java index f6ecd7798..72b479bed 100644 --- a/src/com/android/gallery3d/exif/ExifParser.java +++ b/src/com/android/gallery3d/exif/ExifParser.java @@ -122,10 +122,6 @@ public class ExifParser { */ public static final int OPTION_THUMBNAIL = 1 << 5; - private static final short SOI = (short) 0xFFD8; // SOI marker of JPEG - private static final short APP1 = (short) 0xFFE1; // APP1 marker of JPEG - private static final short APP0 = (short) 0xFFE0; // APP0 marder of JPEG - private static final int EXIF_HEADER = 0x45786966; // EXIF header "Exif" private static final short EXIF_HEADER_TAIL = (short) 0x0000; // EXIF header in APP1 @@ -148,6 +144,7 @@ public class ExifParser { private ExifTag mStripSizeTag; private ExifTag mJpegSizeTag; private boolean mNeedToParseOffsetsInCurrentIfd; + private boolean mContainExifData = false; private final TreeMap mCorrespondingEvent = new TreeMap(); @@ -173,9 +170,10 @@ public class ExifParser { private ExifParser(InputStream inputStream, int options) throws IOException, ExifInvalidFormatException { - seekTiffData(inputStream); + mContainExifData = seekTiffData(inputStream); mTiffStream = new CountedDataInputStream(inputStream); mOptions = options; + if (!mContainExifData) return; if (mTiffStream.getReadByteCount() == 0) { parseTiffHeader(); long offset = mTiffStream.readUnsignedInt(); @@ -220,6 +218,9 @@ public class ExifParser { * @see #EVENT_END */ public int next() throws IOException, ExifInvalidFormatException { + if (!mContainExifData) { + return EVENT_END; + } int offset = mTiffStream.getReadByteCount(); int endOfTags = mIfdStartOffset + OFFSET_SIZE + TAG_SIZE * mNumOfTagInIfd; if (offset < endOfTags) { @@ -599,37 +600,33 @@ public class ExifParser { } } - private void seekTiffData(InputStream inputStream) throws IOException, + private boolean seekTiffData(InputStream inputStream) throws IOException, ExifInvalidFormatException { DataInputStream dataStream = new DataInputStream(inputStream); // SOI and APP1 - if (dataStream.readShort() != SOI) { + if (dataStream.readShort() != JpegHeader.SOI) { throw new ExifInvalidFormatException("Invalid JPEG format"); } - short tag = dataStream.readShort(); - if (tag == APP0) { + short marker = dataStream.readShort(); + while(marker != JpegHeader.APP1 && marker != JpegHeader.EOI + && !JpegHeader.isSofMarker(marker)) { int length = dataStream.readUnsignedShort(); if ((length - 2) != dataStream.skip(length - 2)) { throw new EOFException(); } - tag = dataStream.readShort(); + marker = dataStream.readShort(); } - if (tag != APP1) { - throw new ExifInvalidFormatException("No APP1 segment"); - } + if (marker != JpegHeader.APP1) return false; // No APP1 segment // APP1 length, it's not used for us dataStream.readShort(); // Exif header - if (dataStream.readInt() != EXIF_HEADER - || dataStream.readShort() != EXIF_HEADER_TAIL) { - // There is no EXIF data; - throw new ExifInvalidFormatException("No Exif header in APP1"); - } + return (dataStream.readInt() == EXIF_HEADER + && dataStream.readShort() == EXIF_HEADER_TAIL); } public int read(byte[] buffer, int offset, int length) throws IOException { diff --git a/src/com/android/gallery3d/exif/JpegHeader.java b/src/com/android/gallery3d/exif/JpegHeader.java new file mode 100644 index 000000000..e3e787eff --- /dev/null +++ b/src/com/android/gallery3d/exif/JpegHeader.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.gallery3d.exif; + +class JpegHeader { + public static final short SOI = (short) 0xFFD8; + public static final short APP1 = (short) 0xFFE1; + public static final short APP0 = (short) 0xFFE0; + public static final short EOI = (short) 0xFFD9; + + /** + * SOF (start of frame). All value between SOF0 and SOF15 is SOF marker except for DHT, JPG, + * and DAC marker. + */ + public static final short SOF0 = (short) 0xFFC0; + public static final short SOF15 = (short) 0xFFCF; + public static final short DHT = (short) 0xFFC4; + public static final short JPG = (short) 0xFFC8; + public static final short DAC = (short) 0xFFCC; + + public static final boolean isSofMarker(short marker) { + return marker >= SOF0 && marker <= SOF15 && marker != DHT && marker != JPG + && marker != DAC; + } +} -- cgit v1.2.3