blob: 534f2f6d901b73f04aa3054ced5723ddeeccfe08 [file] [log] [blame]
/*
* 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;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteOrder;
public class ExifParser {
private static final String TAG = "ExifParser";
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 int EXIF_HEADER = 0x45786966; // EXIF header "Exif"
private static final short EXIF_HEADER_TAIL = (short) 0x0000; // EXIF header in APP1
// TIFF header
private static final short LITTLE_ENDIAN_TAG = (short) 0x4949; // "II"
private static final short BIG_ENDIAN_TAG = (short) 0x4d4d; // "MM"
private static final short TIFF_HEADER_TAIL = 0x002A;
public IfdParser parse(InputStream inputStream) throws ExifInvalidFormatException, IOException{
if (!seekTiffData(inputStream)) {
return null;
}
TiffInputStream tiffStream = new TiffInputStream(inputStream);
parseTiffHeader(tiffStream);
long offset = tiffStream.readUnsignedInt();
if (offset > Integer.MAX_VALUE) {
throw new ExifInvalidFormatException("Offset value is larger than Integer.MAX_VALUE");
}
return new IfdParser(tiffStream, (int)offset);
}
private void parseTiffHeader(TiffInputStream tiffStream) throws IOException,
ExifInvalidFormatException {
short byteOrder = tiffStream.readShort();
ByteOrder order;
if (LITTLE_ENDIAN_TAG == byteOrder) {
tiffStream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
} else if (BIG_ENDIAN_TAG == byteOrder) {
tiffStream.setByteOrder(ByteOrder.BIG_ENDIAN);
} else {
throw new ExifInvalidFormatException("Invalid TIFF header");
}
if (tiffStream.readShort() != TIFF_HEADER_TAIL) {
throw new ExifInvalidFormatException("Invalid TIFF header");
}
}
/**
* Try to seek the tiff data. If there is no tiff data, return false, else return true and
* the inputstream will be at the start of tiff data
*/
private boolean seekTiffData(InputStream inputStream) throws IOException,
ExifInvalidFormatException {
DataInputStream dataStream = new DataInputStream(inputStream);
// SOI and APP1
if (dataStream.readShort() != SOI) {
throw new ExifInvalidFormatException("Invalid JPEG format");
}
if (dataStream.readShort() != APP1) {
return false;
}
// 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;
return false;
}
return true;
}
}