Merge "ExifInterface: handle the invalid offsets and count numbers" into nyc-dev

This commit is contained in:
Jaesung Chung
2016-03-15 08:27:37 +00:00
committed by Android (Google) Code Review

View File

@@ -1197,8 +1197,9 @@ public class ExifInterface {
}
bytesRead += 2;
int length = dataInputStream.readUnsignedShort() - 2;
if (length < 0)
if (length < 0) {
throw new IOException("Invalid length");
}
bytesRead += length;
switch (marker) {
case MARKER_APP1: {
@@ -1221,6 +1222,9 @@ public class ExifInterface {
if (length <= 0) {
throw new IOException("Invalid exif");
}
if (DEBUG) {
Log.d(TAG, "readExifSegment with a byte array (length: " + length + ")");
}
byte[] bytes = new byte[length];
if (dataInputStream.read(bytes) != length) {
throw new IOException("Invalid exif");
@@ -1309,8 +1313,9 @@ public class ExifInterface {
case MARKER_APP1: {
// Rewrite EXIF segment
int length = dataInputStream.readUnsignedShort() - 2;
if (length < 0)
if (length < 0) {
throw new IOException("Invalid length");
}
bytesRead += 2;
int read;
while ((read = dataInputStream.read(
@@ -1331,8 +1336,9 @@ public class ExifInterface {
// Copy JPEG segment
int length = dataInputStream.readUnsignedShort();
dataOutputStream.writeUnsignedShort(length);
if (length < 0)
if (length < 0) {
throw new IOException("Invalid length");
}
length -= 2;
bytesRead += 2;
int read;
@@ -1385,8 +1391,9 @@ public class ExifInterface {
}
firstIfdOffset -= 8;
if (firstIfdOffset > 0) {
if (dataInputStream.skip(firstIfdOffset) != firstIfdOffset)
if (dataInputStream.skip(firstIfdOffset) != firstIfdOffset) {
throw new IOException("Couldn't jump to first Ifd: " + firstIfdOffset);
}
}
// Read primary image TIFF image file directory.
@@ -1582,8 +1589,16 @@ public class ExifInterface {
// Reads image file directory, which is a tag group in EXIF.
private void readImageFileDirectory(ByteOrderAwarenessDataInputStream dataInputStream, int hint)
throws IOException {
if (dataInputStream.peek() + 2 > dataInputStream.mLength) {
// Return if there is no data from the offset.
return;
}
// See JEITA CP-3451 Figure 5. page 9.
short numberOfDirectoryEntry = dataInputStream.readShort();
if (dataInputStream.peek() + 12 * numberOfDirectoryEntry > dataInputStream.mLength) {
// Return if the size of entries is too big.
return;
}
if (DEBUG) {
Log.d(TAG, "numberOfDirectoryEntry: " + numberOfDirectoryEntry);
@@ -1595,10 +1610,25 @@ public class ExifInterface {
int numberOfComponents = dataInputStream.readInt();
long nextEntryOffset = dataInputStream.peek() + 4; // next four bytes is for data
// offset or value.
// Look up a corresponding tag from tag number
String tagName = (String) sExifTagMapsForReading[hint].get(tagNumber);
if (DEBUG) {
Log.d(TAG, String.format("tagNumber: %d, dataFormat: %d, numberOfComponents: %d",
tagNumber, dataFormat, numberOfComponents));
Log.d(TAG, String.format("hint: %d, tagNumber: %d, tagName: %s, dataFormat: %d," +
"numberOfComponents: %d", hint, tagNumber, tagName, dataFormat,
numberOfComponents));
}
if (tagName == null || dataFormat <= 0 ||
dataFormat >= IFD_FORMAT_BYTES_PER_FORMAT.length) {
// Skip if the parsed tag number is not defined or invalid data format.
if (tagName == null) {
Log.w(TAG, "Skip the tag entry since tag number is not defined: " + tagNumber);
} else {
Log.w(TAG, "Skip the tag entry since data format is invalid: " + dataFormat);
}
dataInputStream.seek(nextEntryOffset);
continue;
}
// Read a value from data field or seek to the value offset which is stored in data
@@ -1609,19 +1639,21 @@ public class ExifInterface {
if (DEBUG) {
Log.d(TAG, "seek to data offset: " + offset);
}
dataInputStream.seek(offset);
}
// Look up a corresponding tag from tag number
String tagName = (String) sExifTagMapsForReading[hint].get(tagNumber);
// Skip if the parsed tag number is not defined.
if (tagName == null) {
dataInputStream.seek(nextEntryOffset);
continue;
if (offset + byteCount <= dataInputStream.mLength) {
dataInputStream.seek(offset);
} else {
// Skip if invalid data offset.
Log.w(TAG, "Skip the tag entry since data offset is invalid: " + offset);
dataInputStream.seek(nextEntryOffset);
continue;
}
}
// Recursively parse IFD when a IFD pointer tag appears.
int innerIfdHint = getIfdHintFromTagNumber(tagNumber);
if (DEBUG) {
Log.d(TAG, "innerIfdHint: " + innerIfdHint + " byteCount: " + byteCount);
}
if (innerIfdHint >= 0) {
long offset = -1L;
// Get offset from data field
@@ -1650,9 +1682,11 @@ public class ExifInterface {
if (DEBUG) {
Log.d(TAG, String.format("Offset: %d, tagName: %s", offset, tagName));
}
if (offset > 0L) {
if (offset > 0L && offset < dataInputStream.mLength) {
dataInputStream.seek(offset);
readImageFileDirectory(dataInputStream, innerIfdHint);
} else {
Log.w(TAG, "Skip jump into the IFD since its offset is invalid: " + offset);
}
dataInputStream.seek(nextEntryOffset);
@@ -1683,14 +1717,17 @@ public class ExifInterface {
}
}
long nextIfdOffset = dataInputStream.readUnsignedInt();
if (DEBUG) {
Log.d(TAG, String.format("nextIfdOffset: %d", nextIfdOffset));
}
// The next IFD offset needs to be bigger than 8 since the first IFD offset is at least 8.
if (nextIfdOffset > 8) {
dataInputStream.seek(nextIfdOffset);
readImageFileDirectory(dataInputStream, IFD_THUMBNAIL_HINT);
if (dataInputStream.peek() + 4 <= dataInputStream.mLength) {
long nextIfdOffset = dataInputStream.readUnsignedInt();
if (DEBUG) {
Log.d(TAG, String.format("nextIfdOffset: %d", nextIfdOffset));
}
// The next IFD offset needs to be bigger than 8
// since the first IFD offset is at least 8.
if (nextIfdOffset > 8 && nextIfdOffset < dataInputStream.mLength) {
dataInputStream.seek(nextIfdOffset);
readImageFileDirectory(dataInputStream, IFD_THUMBNAIL_HINT);
}
}
}
@@ -1748,17 +1785,18 @@ public class ExifInterface {
}
StringBuilder stringBuilder = new StringBuilder();
while (true) {
while (index < numberOfComponents) {
int ch = bytes[index];
if (ch == 0)
if (ch == 0) {
break;
if (ch >= 32)
}
if (ch >= 32) {
stringBuilder.append((char) ch);
else
}
else {
stringBuilder.append('?');
}
++index;
if (index == numberOfComponents)
break;
}
return stringBuilder.toString();
}
@@ -1772,8 +1810,9 @@ public class ExifInterface {
// Gets the corresponding IFD group index of the given tag number for writing Exif Tags.
private static int getIfdHintFromTagNumber(int tagNumber) {
for (int i = 0; i < IFD_POINTER_TAG_HINTS.length; ++i) {
if (IFD_POINTER_TAGS[i].number == tagNumber)
if (IFD_POINTER_TAGS[i].number == tagNumber) {
return IFD_POINTER_TAG_HINTS[i];
}
}
return -1;
}
@@ -2076,8 +2115,9 @@ public class ExifInterface {
public void seek(long byteCount) throws IOException {
mPosition = 0L;
reset();
if (skip(byteCount) != byteCount)
if (skip(byteCount) != byteCount) {
throw new IOException("Couldn't seek up to the byteCount");
}
}
public long peek() {
@@ -2086,8 +2126,9 @@ public class ExifInterface {
public void readFully(byte[] buffer) throws IOException {
mPosition += buffer.length;
if (mPosition > mLength)
if (mPosition > mLength) {
throw new EOFException();
}
if (super.read(buffer, 0, buffer.length) != buffer.length) {
throw new IOException("Couldn't read up to the length of buffer");
}
@@ -2095,22 +2136,26 @@ public class ExifInterface {
public byte readByte() throws IOException {
++mPosition;
if (mPosition > mLength)
if (mPosition > mLength) {
throw new EOFException();
}
int ch = super.read();
if (ch < 0)
if (ch < 0) {
throw new EOFException();
}
return (byte) ch;
}
public short readShort() throws IOException {
mPosition += 2;
if (mPosition > mLength)
if (mPosition > mLength) {
throw new EOFException();
}
int ch1 = super.read();
int ch2 = super.read();
if ((ch1 | ch2) < 0)
if ((ch1 | ch2) < 0) {
throw new EOFException();
}
if (mByteOrder == LITTLE_ENDIAN) {
return (short) ((ch2 << 8) + (ch1));
} else if (mByteOrder == BIG_ENDIAN) {
@@ -2121,14 +2166,16 @@ public class ExifInterface {
public int readInt() throws IOException {
mPosition += 4;
if (mPosition > mLength)
if (mPosition > mLength) {
throw new EOFException();
}
int ch1 = super.read();
int ch2 = super.read();
int ch3 = super.read();
int ch4 = super.read();
if ((ch1 | ch2 | ch3 | ch4) < 0)
if ((ch1 | ch2 | ch3 | ch4) < 0) {
throw new EOFException();
}
if (mByteOrder == LITTLE_ENDIAN) {
return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + ch1);
} else if (mByteOrder == BIG_ENDIAN) {
@@ -2146,12 +2193,14 @@ public class ExifInterface {
public int readUnsignedShort() throws IOException {
mPosition += 2;
if (mPosition > mLength)
if (mPosition > mLength) {
throw new EOFException();
}
int ch1 = super.read();
int ch2 = super.read();
if ((ch1 | ch2) < 0)
if ((ch1 | ch2) < 0) {
throw new EOFException();
}
if (mByteOrder == LITTLE_ENDIAN) {
return ((ch2 << 8) + (ch1));
} else if (mByteOrder == BIG_ENDIAN) {
@@ -2166,8 +2215,9 @@ public class ExifInterface {
public long readLong() throws IOException {
mPosition += 8;
if (mPosition > mLength)
if (mPosition > mLength) {
throw new EOFException();
}
int ch1 = super.read();
int ch2 = super.read();
int ch3 = super.read();
@@ -2176,8 +2226,9 @@ public class ExifInterface {
int ch6 = super.read();
int ch7 = super.read();
int ch8 = super.read();
if ((ch1 | ch2 | ch3 | ch4 | ch5 | ch6 | ch7 | ch8) < 0)
if ((ch1 | ch2 | ch3 | ch4 | ch5 | ch6 | ch7 | ch8) < 0) {
throw new EOFException();
}
if (mByteOrder == LITTLE_ENDIAN) {
return (((long) ch8 << 56) + ((long) ch7 << 48) + ((long) ch6 << 40)
+ ((long) ch5 << 32) + ((long) ch4 << 24) + ((long) ch3 << 16)