Loading media/java/android/media/ExifInterface.java +18 −76 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,12 @@ package android.media; package android.media; import static android.media.ExifInterfaceUtils.byteArrayToHexString; import static android.media.ExifInterfaceUtils.closeQuietly; import static android.media.ExifInterfaceUtils.convertToLongArray; import static android.media.ExifInterfaceUtils.copy; import static android.media.ExifInterfaceUtils.startsWith; import android.annotation.CurrentTimeMillisLong; import android.annotation.CurrentTimeMillisLong; import android.annotation.IntDef; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.NonNull; Loading @@ -32,10 +38,6 @@ import android.util.Log; import android.util.Pair; import android.util.Pair; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ArrayUtils; import libcore.io.IoUtils; import libcore.io.Streams; import java.io.BufferedInputStream; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedOutputStream; Loading Loading @@ -1540,7 +1542,7 @@ public class ExifInterface { in = new FileInputStream(fileDescriptor, isFdOwner); in = new FileInputStream(fileDescriptor, isFdOwner); loadAttributes(in); loadAttributes(in); } finally { } finally { IoUtils.closeQuietly(in); closeQuietly(in); } } } } Loading Loading @@ -2092,13 +2094,13 @@ public class ExifInterface { Os.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET); Os.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET); in = new FileInputStream(mSeekableFileDescriptor); in = new FileInputStream(mSeekableFileDescriptor); out = new FileOutputStream(tempFile); out = new FileOutputStream(tempFile); Streams.copy(in, out); copy(in, out); } } } catch (Exception e) { } catch (Exception e) { throw new IOException("Failed to copy original file to temp file", e); throw new IOException("Failed to copy original file to temp file", e); } finally { } finally { IoUtils.closeQuietly(in); closeQuietly(in); IoUtils.closeQuietly(out); closeQuietly(out); } } in = null; in = null; Loading Loading @@ -2129,8 +2131,8 @@ public class ExifInterface { } } throw new IOException("Failed to save new file", e); throw new IOException("Failed to save new file", e); } finally { } finally { IoUtils.closeQuietly(in); closeQuietly(in); IoUtils.closeQuietly(out); closeQuietly(out); tempFile.delete(); tempFile.delete(); } } Loading Loading @@ -2215,7 +2217,7 @@ public class ExifInterface { // Couldn't get a thumbnail image. // Couldn't get a thumbnail image. Log.d(TAG, "Encountered exception while getting thumbnail", e); Log.d(TAG, "Encountered exception while getting thumbnail", e); } finally { } finally { IoUtils.closeQuietly(in); closeQuietly(in); } } return null; return null; } } Loading Loading @@ -2536,7 +2538,7 @@ public class ExifInterface { } } loadAttributes(in); loadAttributes(in); } finally { } finally { IoUtils.closeQuietly(in); closeQuietly(in); } } } } Loading Loading @@ -2839,14 +2841,14 @@ public class ExifInterface { bytesRead += length; bytesRead += length; length = 0; length = 0; if (ArrayUtils.startsWith(bytes, IDENTIFIER_EXIF_APP1)) { if (startsWith(bytes, IDENTIFIER_EXIF_APP1)) { final long offset = start + IDENTIFIER_EXIF_APP1.length; final long offset = start + IDENTIFIER_EXIF_APP1.length; final byte[] value = Arrays.copyOfRange(bytes, final byte[] value = Arrays.copyOfRange(bytes, IDENTIFIER_EXIF_APP1.length, bytes.length); IDENTIFIER_EXIF_APP1.length, bytes.length); // Save offset values for handleThumbnailFromJfif() function // Save offset values for handleThumbnailFromJfif() function mExifOffset = (int) offset; mExifOffset = (int) offset; readExifSegment(value, imageType); readExifSegment(value, imageType); } else if (ArrayUtils.startsWith(bytes, IDENTIFIER_XMP_APP1)) { } else if (startsWith(bytes, IDENTIFIER_XMP_APP1)) { // See XMP Specification Part 3: Storage in Files, 1.1.3 JPEG, Table 6 // See XMP Specification Part 3: Storage in Files, 1.1.3 JPEG, Table 6 final long offset = start + IDENTIFIER_XMP_APP1.length; final long offset = start + IDENTIFIER_XMP_APP1.length; final byte[] value = Arrays.copyOfRange(bytes, final byte[] value = Arrays.copyOfRange(bytes, Loading Loading @@ -3527,7 +3529,7 @@ public class ExifInterface { dataOutputStream.writeByte(MARKER); dataOutputStream.writeByte(MARKER); dataOutputStream.writeByte(marker); dataOutputStream.writeByte(marker); // Copy all the remaining data // Copy all the remaining data Streams.copy(dataInputStream, dataOutputStream); copy(dataInputStream, dataOutputStream); return; return; } } default: { default: { Loading Loading @@ -3605,7 +3607,7 @@ public class ExifInterface { dataOutputStream.writeInt((int) crc.getValue()); dataOutputStream.writeInt((int) crc.getValue()); } } // Copy the rest of the file // Copy the rest of the file Streams.copy(dataInputStream, dataOutputStream); copy(dataInputStream, dataOutputStream); } } // Reads the given EXIF byte area and save its tag data into attributes. // Reads the given EXIF byte area and save its tag data into attributes. Loading Loading @@ -4865,64 +4867,4 @@ public class ExifInterface { } } } } } } // Checks if there is a match private boolean containsMatch(byte[] mainBytes, byte[] findBytes) { for (int i = 0; i < mainBytes.length - findBytes.length; i++) { for (int j = 0; j < findBytes.length; j++) { if (mainBytes[i + j] != findBytes[j]) { break; } if (j == findBytes.length - 1) { return true; } } } return false; } /** * Copies the given number of the bytes from {@code in} to {@code out}. Neither stream is * closed. */ private static void copy(InputStream in, OutputStream out, int numBytes) throws IOException { int remainder = numBytes; byte[] buffer = new byte[8192]; while (remainder > 0) { int bytesToRead = Math.min(remainder, 8192); int bytesRead = in.read(buffer, 0, bytesToRead); if (bytesRead != bytesToRead) { throw new IOException("Failed to copy the given amount of bytes from the input" + "stream to the output stream."); } remainder -= bytesRead; out.write(buffer, 0, bytesRead); } } /** * Convert given int[] to long[]. If long[] is given, just return it. * Return null for other types of input. */ private static long[] convertToLongArray(Object inputObj) { if (inputObj instanceof int[]) { int[] input = (int[]) inputObj; long[] result = new long[input.length]; for (int i = 0; i < input.length; i++) { result[i] = input[i]; } return result; } else if (inputObj instanceof long[]) { return (long[]) inputObj; } return null; } private static String byteArrayToHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(bytes.length * 2); for (int i = 0; i < bytes.length; i++) { sb.append(String.format("%02x", bytes[i])); } return sb.toString(); } } } media/java/android/media/ExifInterfaceUtils.java 0 → 100644 +117 −0 Original line number Original line Diff line number Diff line /* * Copyright 2020 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 android.media; import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * Package private utility class for ExifInterface. */ class ExifInterfaceUtils { /** * Copies all of the bytes from {@code in} to {@code out}. Neither stream is closed. * Returns the total number of bytes transferred. */ public static int copy(InputStream in, OutputStream out) throws IOException { int total = 0; byte[] buffer = new byte[8192]; int c; while ((c = in.read(buffer)) != -1) { total += c; out.write(buffer, 0, c); } return total; } /** * Copies the given number of the bytes from {@code in} to {@code out}. Neither stream is * closed. */ public static void copy(InputStream in, OutputStream out, int numBytes) throws IOException { int remainder = numBytes; byte[] buffer = new byte[8192]; while (remainder > 0) { int bytesToRead = Math.min(remainder, 8192); int bytesRead = in.read(buffer, 0, bytesToRead); if (bytesRead != bytesToRead) { throw new IOException("Failed to copy the given amount of bytes from the input" + "stream to the output stream."); } remainder -= bytesRead; out.write(buffer, 0, bytesRead); } } /** * Convert given int[] to long[]. If long[] is given, just return it. * Return null for other types of input. */ public static long[] convertToLongArray(Object inputObj) { if (inputObj instanceof int[]) { int[] input = (int[]) inputObj; long[] result = new long[input.length]; for (int i = 0; i < input.length; i++) { result[i] = input[i]; } return result; } else if (inputObj instanceof long[]) { return (long[]) inputObj; } return null; } /** * Convert given byte array to hex string. */ public static String byteArrayToHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(bytes.length * 2); for (int i = 0; i < bytes.length; i++) { sb.append(String.format("%02x", bytes[i])); } return sb.toString(); } /** * Checks if the start of the first byte array is equal to the second byte array. */ public static boolean startsWith(byte[] cur, byte[] val) { if (cur == null || val == null) return false; if (cur.length < val.length) return false; if (cur.length == 0 || val.length == 0) return false; for (int i = 0; i < val.length; i++) { if (cur[i] != val[i]) return false; } return true; } /** * Closes 'closeable', ignoring any checked exceptions. Does nothing if 'closeable' is null. */ public static void closeQuietly(Closeable closeable) { if (closeable != null) { try { closeable.close(); } catch (RuntimeException rethrown) { throw rethrown; } catch (Exception ignored) { } } } } Loading
media/java/android/media/ExifInterface.java +18 −76 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,12 @@ package android.media; package android.media; import static android.media.ExifInterfaceUtils.byteArrayToHexString; import static android.media.ExifInterfaceUtils.closeQuietly; import static android.media.ExifInterfaceUtils.convertToLongArray; import static android.media.ExifInterfaceUtils.copy; import static android.media.ExifInterfaceUtils.startsWith; import android.annotation.CurrentTimeMillisLong; import android.annotation.CurrentTimeMillisLong; import android.annotation.IntDef; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.NonNull; Loading @@ -32,10 +38,6 @@ import android.util.Log; import android.util.Pair; import android.util.Pair; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ArrayUtils; import libcore.io.IoUtils; import libcore.io.Streams; import java.io.BufferedInputStream; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedOutputStream; Loading Loading @@ -1540,7 +1542,7 @@ public class ExifInterface { in = new FileInputStream(fileDescriptor, isFdOwner); in = new FileInputStream(fileDescriptor, isFdOwner); loadAttributes(in); loadAttributes(in); } finally { } finally { IoUtils.closeQuietly(in); closeQuietly(in); } } } } Loading Loading @@ -2092,13 +2094,13 @@ public class ExifInterface { Os.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET); Os.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET); in = new FileInputStream(mSeekableFileDescriptor); in = new FileInputStream(mSeekableFileDescriptor); out = new FileOutputStream(tempFile); out = new FileOutputStream(tempFile); Streams.copy(in, out); copy(in, out); } } } catch (Exception e) { } catch (Exception e) { throw new IOException("Failed to copy original file to temp file", e); throw new IOException("Failed to copy original file to temp file", e); } finally { } finally { IoUtils.closeQuietly(in); closeQuietly(in); IoUtils.closeQuietly(out); closeQuietly(out); } } in = null; in = null; Loading Loading @@ -2129,8 +2131,8 @@ public class ExifInterface { } } throw new IOException("Failed to save new file", e); throw new IOException("Failed to save new file", e); } finally { } finally { IoUtils.closeQuietly(in); closeQuietly(in); IoUtils.closeQuietly(out); closeQuietly(out); tempFile.delete(); tempFile.delete(); } } Loading Loading @@ -2215,7 +2217,7 @@ public class ExifInterface { // Couldn't get a thumbnail image. // Couldn't get a thumbnail image. Log.d(TAG, "Encountered exception while getting thumbnail", e); Log.d(TAG, "Encountered exception while getting thumbnail", e); } finally { } finally { IoUtils.closeQuietly(in); closeQuietly(in); } } return null; return null; } } Loading Loading @@ -2536,7 +2538,7 @@ public class ExifInterface { } } loadAttributes(in); loadAttributes(in); } finally { } finally { IoUtils.closeQuietly(in); closeQuietly(in); } } } } Loading Loading @@ -2839,14 +2841,14 @@ public class ExifInterface { bytesRead += length; bytesRead += length; length = 0; length = 0; if (ArrayUtils.startsWith(bytes, IDENTIFIER_EXIF_APP1)) { if (startsWith(bytes, IDENTIFIER_EXIF_APP1)) { final long offset = start + IDENTIFIER_EXIF_APP1.length; final long offset = start + IDENTIFIER_EXIF_APP1.length; final byte[] value = Arrays.copyOfRange(bytes, final byte[] value = Arrays.copyOfRange(bytes, IDENTIFIER_EXIF_APP1.length, bytes.length); IDENTIFIER_EXIF_APP1.length, bytes.length); // Save offset values for handleThumbnailFromJfif() function // Save offset values for handleThumbnailFromJfif() function mExifOffset = (int) offset; mExifOffset = (int) offset; readExifSegment(value, imageType); readExifSegment(value, imageType); } else if (ArrayUtils.startsWith(bytes, IDENTIFIER_XMP_APP1)) { } else if (startsWith(bytes, IDENTIFIER_XMP_APP1)) { // See XMP Specification Part 3: Storage in Files, 1.1.3 JPEG, Table 6 // See XMP Specification Part 3: Storage in Files, 1.1.3 JPEG, Table 6 final long offset = start + IDENTIFIER_XMP_APP1.length; final long offset = start + IDENTIFIER_XMP_APP1.length; final byte[] value = Arrays.copyOfRange(bytes, final byte[] value = Arrays.copyOfRange(bytes, Loading Loading @@ -3527,7 +3529,7 @@ public class ExifInterface { dataOutputStream.writeByte(MARKER); dataOutputStream.writeByte(MARKER); dataOutputStream.writeByte(marker); dataOutputStream.writeByte(marker); // Copy all the remaining data // Copy all the remaining data Streams.copy(dataInputStream, dataOutputStream); copy(dataInputStream, dataOutputStream); return; return; } } default: { default: { Loading Loading @@ -3605,7 +3607,7 @@ public class ExifInterface { dataOutputStream.writeInt((int) crc.getValue()); dataOutputStream.writeInt((int) crc.getValue()); } } // Copy the rest of the file // Copy the rest of the file Streams.copy(dataInputStream, dataOutputStream); copy(dataInputStream, dataOutputStream); } } // Reads the given EXIF byte area and save its tag data into attributes. // Reads the given EXIF byte area and save its tag data into attributes. Loading Loading @@ -4865,64 +4867,4 @@ public class ExifInterface { } } } } } } // Checks if there is a match private boolean containsMatch(byte[] mainBytes, byte[] findBytes) { for (int i = 0; i < mainBytes.length - findBytes.length; i++) { for (int j = 0; j < findBytes.length; j++) { if (mainBytes[i + j] != findBytes[j]) { break; } if (j == findBytes.length - 1) { return true; } } } return false; } /** * Copies the given number of the bytes from {@code in} to {@code out}. Neither stream is * closed. */ private static void copy(InputStream in, OutputStream out, int numBytes) throws IOException { int remainder = numBytes; byte[] buffer = new byte[8192]; while (remainder > 0) { int bytesToRead = Math.min(remainder, 8192); int bytesRead = in.read(buffer, 0, bytesToRead); if (bytesRead != bytesToRead) { throw new IOException("Failed to copy the given amount of bytes from the input" + "stream to the output stream."); } remainder -= bytesRead; out.write(buffer, 0, bytesRead); } } /** * Convert given int[] to long[]. If long[] is given, just return it. * Return null for other types of input. */ private static long[] convertToLongArray(Object inputObj) { if (inputObj instanceof int[]) { int[] input = (int[]) inputObj; long[] result = new long[input.length]; for (int i = 0; i < input.length; i++) { result[i] = input[i]; } return result; } else if (inputObj instanceof long[]) { return (long[]) inputObj; } return null; } private static String byteArrayToHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(bytes.length * 2); for (int i = 0; i < bytes.length; i++) { sb.append(String.format("%02x", bytes[i])); } return sb.toString(); } } }
media/java/android/media/ExifInterfaceUtils.java 0 → 100644 +117 −0 Original line number Original line Diff line number Diff line /* * Copyright 2020 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 android.media; import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * Package private utility class for ExifInterface. */ class ExifInterfaceUtils { /** * Copies all of the bytes from {@code in} to {@code out}. Neither stream is closed. * Returns the total number of bytes transferred. */ public static int copy(InputStream in, OutputStream out) throws IOException { int total = 0; byte[] buffer = new byte[8192]; int c; while ((c = in.read(buffer)) != -1) { total += c; out.write(buffer, 0, c); } return total; } /** * Copies the given number of the bytes from {@code in} to {@code out}. Neither stream is * closed. */ public static void copy(InputStream in, OutputStream out, int numBytes) throws IOException { int remainder = numBytes; byte[] buffer = new byte[8192]; while (remainder > 0) { int bytesToRead = Math.min(remainder, 8192); int bytesRead = in.read(buffer, 0, bytesToRead); if (bytesRead != bytesToRead) { throw new IOException("Failed to copy the given amount of bytes from the input" + "stream to the output stream."); } remainder -= bytesRead; out.write(buffer, 0, bytesRead); } } /** * Convert given int[] to long[]. If long[] is given, just return it. * Return null for other types of input. */ public static long[] convertToLongArray(Object inputObj) { if (inputObj instanceof int[]) { int[] input = (int[]) inputObj; long[] result = new long[input.length]; for (int i = 0; i < input.length; i++) { result[i] = input[i]; } return result; } else if (inputObj instanceof long[]) { return (long[]) inputObj; } return null; } /** * Convert given byte array to hex string. */ public static String byteArrayToHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(bytes.length * 2); for (int i = 0; i < bytes.length; i++) { sb.append(String.format("%02x", bytes[i])); } return sb.toString(); } /** * Checks if the start of the first byte array is equal to the second byte array. */ public static boolean startsWith(byte[] cur, byte[] val) { if (cur == null || val == null) return false; if (cur.length < val.length) return false; if (cur.length == 0 || val.length == 0) return false; for (int i = 0; i < val.length; i++) { if (cur[i] != val[i]) return false; } return true; } /** * Closes 'closeable', ignoring any checked exceptions. Does nothing if 'closeable' is null. */ public static void closeQuietly(Closeable closeable) { if (closeable != null) { try { closeable.close(); } catch (RuntimeException rethrown) { throw rethrown; } catch (Exception ignored) { } } } }