Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1a506af9 authored by Jaesung Chung's avatar Jaesung Chung Committed by Android (Google) Code Review
Browse files

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

parents 531d8d2f 49371caf
Loading
Loading
Loading
Loading
+94 −43
Original line number Diff line number Diff line
@@ -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,9 +1391,10 @@ 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.
        readImageFileDirectory(dataInputStream, IFD_TIFF_HINT);
@@ -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);
                }
                if (offset + byteCount <= dataInputStream.mLength) {
                    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) {
                } 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,16 +1717,19 @@ public class ExifInterface {
            }
        }

        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) {
            // 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);
            }
        }
    }

    // Reads a value from where the entry value are stored.
    private String readExifEntryValue(ByteOrderAwarenessDataInputStream dataInputStream,
@@ -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,9 +1810,10 @@ 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,9 +2115,10 @@ 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() {
            return mPosition;
@@ -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)