diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/DebugHandler.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/DebugHandler.kt index fd36169d4..9f223655f 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/DebugHandler.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/DebugHandler.kt @@ -275,7 +275,7 @@ class DebugHandler(private val context: Context) : MethodCallHandler { if (canReadWithMetadataExtractor(mimeType)) { try { Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input -> - val metadata = Helper.safeRead(input) + val metadata = Helper.safeRead(input, sizeBytes) metadataMap["mimeType"] = metadata.getDirectoriesOfType(FileTypeDirectory::class.java).joinToString { dir -> if (dir.containsTag(FileTypeDirectory.TAG_DETECTED_FILE_MIME_TYPE)) { dir.getString(FileTypeDirectory.TAG_DETECTED_FILE_MIME_TYPE) diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/EmbeddedDataHandler.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/EmbeddedDataHandler.kt index e46d31a46..a96f84e90 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/EmbeddedDataHandler.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/EmbeddedDataHandler.kt @@ -102,7 +102,7 @@ class EmbeddedDataHandler(private val context: Context) : MethodCallHandler { if (canReadWithMetadataExtractor(mimeType)) { try { Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input -> - val metadata = Helper.safeRead(input) + val metadata = Helper.safeRead(input, sizeBytes) // data can be large and stored in "Extended XMP", // which is returned as a second XMP directory val xmpDirs = metadata.getDirectoriesOfType(XmpDirectory::class.java) @@ -272,7 +272,7 @@ class EmbeddedDataHandler(private val context: Context) : MethodCallHandler { if (canReadWithMetadataExtractor(mimeType)) { try { Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input -> - val metadata = Helper.safeRead(input) + val metadata = Helper.safeRead(input, sizeBytes) // data can be large and stored in "Extended XMP", // which is returned as a second XMP directory val xmpDirs = metadata.getDirectoriesOfType(XmpDirectory::class.java) diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataFetchHandler.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataFetchHandler.kt index 8819f24ff..7719d796b 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataFetchHandler.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataFetchHandler.kt @@ -229,7 +229,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler { if (canReadWithMetadataExtractor(mimeType)) { try { Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input -> - val metadata = Helper.safeRead(input) + val metadata = Helper.safeRead(input, sizeBytes) foundExif = metadata.directories.any { it is ExifDirectoryBase && it.tagCount > 0 } foundMp4Uuid = metadata.directories.any { it is Mp4UuidBoxDirectory && it.tagCount > 0 } @@ -599,7 +599,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler { if (canReadWithMetadataExtractor(mimeType)) { try { Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input -> - val metadata = Helper.safeRead(input) + val metadata = Helper.safeRead(input, sizeBytes) foundExif = metadata.directories.any { it is ExifDirectoryBase && it.tagCount > 0 } foundMp4Uuid = metadata.directories.any { it is Mp4UuidBoxDirectory && it.tagCount > 0 } @@ -803,7 +803,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler { } StorageUtils.openInputStream(context, uri)?.let { input -> input.skip(dataOffset) - val pageMetadata = Helper.safeRead(input) + val pageMetadata = Helper.safeRead(input, sizeBytes) if (pageMetadata.getDirectoriesOfType(XmpDirectory::class.java).any { it.xmpMeta.hasHdrGainMap() }) { return true } @@ -897,7 +897,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler { if (canReadWithMetadataExtractor(mimeType)) { try { Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input -> - val metadata = Helper.safeRead(input) + val metadata = Helper.safeRead(input, sizeBytes) for (dir in metadata.getDirectoriesOfType(ExifSubIFDDirectory::class.java)) { foundExif = true if (fields.contains(KEY_APERTURE)) { @@ -1007,7 +1007,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler { if (canReadWithMetadataExtractor(mimeType)) { try { Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input -> - val metadata = Helper.safeRead(input) + val metadata = Helper.safeRead(input, sizeBytes) val fields = HashMap() for (dir in metadata.getDirectoriesOfType(ExifIFD0Directory::class.java)) { if (dir.containsGeoTiffTags()) { @@ -1084,7 +1084,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler { if (canReadWithMetadataExtractor(mimeType) && !isLargeMp4(mimeType, sizeBytes)) { try { Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input -> - val metadata = Helper.safeRead(input) + val metadata = Helper.safeRead(input, sizeBytes) metadata.getDirectoriesOfType(XmpDirectory::class.java).map { it.xmpMeta }.forEach { processXmp(it, allowMultiple = true) } @@ -1166,7 +1166,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler { if (canReadWithMetadataExtractor(mimeType) && !isLargeMp4(mimeType, sizeBytes)) { try { Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input -> - val metadata = Helper.safeRead(input) + val metadata = Helper.safeRead(input, sizeBytes) metadata.getDirectoriesOfType(XmpDirectory::class.java).map { it.xmpMeta }.forEach { processXmp(it, allowMultiple = true) } @@ -1244,7 +1244,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler { if (canReadWithMetadataExtractor(mimeType)) { try { Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input -> - val metadata = Helper.safeRead(input) + val metadata = Helper.safeRead(input, sizeBytes) val tag = when (field) { ExifInterface.TAG_DATETIME -> ExifIFD0Directory.TAG_DATETIME ExifInterface.TAG_DATETIME_DIGITIZED -> ExifSubIFDDirectory.TAG_DATETIME_DIGITIZED @@ -1345,7 +1345,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler { if (canReadWithMetadataExtractor(mimeType)) { try { Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input -> - val metadata = Helper.safeRead(input) + val metadata = Helper.safeRead(input, sizeBytes) for (dir in metadata.getDirectoriesOfType(ExifDirectoryBase::class.java)) { foundExif = true val allTags = ExifInterfaceHelper.allTags diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/metadata/MultiPage.kt b/android/app/src/main/kotlin/deckers/thibault/aves/metadata/MultiPage.kt index 2a7d679ac..113562fee 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/metadata/MultiPage.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/metadata/MultiPage.kt @@ -97,7 +97,7 @@ object MultiPage { if (canReadWithMetadataExtractor(mimeType)) { try { Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input -> - val metadata = Helper.safeRead(input) + val metadata = Helper.safeRead(input, sizeBytes) foundExif = metadata.directories.any { it is ExifDirectoryBase && it.tagCount > 0 } for (dir in metadata.getDirectoriesOfType(ExifIFD0Directory::class.java)) { dir.getSafeInt(ExifDirectoryBase.TAG_ORIENTATION) { @@ -168,7 +168,7 @@ object MultiPage { val mimeType = MimeTypes.JPEG try { Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input -> - val metadata = Helper.safeRead(input) + val metadata = Helper.safeRead(input, sizeBytes) return metadata.getDirectoriesOfType(MpEntryDirectory::class.java).map { it.entry } } } catch (e: Exception) { @@ -332,7 +332,7 @@ object MultiPage { try { Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input -> - val metadata = Helper.safeRead(input) + val metadata = Helper.safeRead(input, sizeBytes) foundXmp = metadata.directories.any { it is XmpDirectory && it.tagCount > 0 } metadata.getDirectoriesOfType(XmpDirectory::class.java).map { it.xmpMeta }.forEach(::processXmp) } diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/metadata/metadataextractor/Helper.kt b/android/app/src/main/kotlin/deckers/thibault/aves/metadata/metadataextractor/Helper.kt index 0d2608a06..1858962ae 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/metadata/metadataextractor/Helper.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/metadata/metadataextractor/Helper.kt @@ -29,6 +29,7 @@ import deckers.thibault.aves.metadata.GeoTiffKeys import deckers.thibault.aves.metadata.Metadata import deckers.thibault.aves.metadata.metadataextractor.mpf.MpfReader import deckers.thibault.aves.utils.LogUtils +import deckers.thibault.aves.utils.MemoryUtils import java.io.BufferedInputStream import java.io.IOException import java.io.InputStream @@ -68,9 +69,10 @@ object Helper { } @Throws(IOException::class, ImageProcessingException::class) - fun safeRead(input: InputStream): com.drew.metadata.Metadata { + fun safeRead(input: InputStream, sizeBytes: Long?): com.drew.metadata.Metadata { val inputStream = if (input is BufferedInputStream) input else BufferedInputStream(input) val fileType = FileTypeDetector.detectFileType(inputStream) + val streamLength = sizeBytes ?: SAFE_READ_STREAM_LENGTH val metadata = when (fileType) { FileType.Jpeg -> safeReadJpeg(inputStream) @@ -82,9 +84,9 @@ object Helper { FileType.Cr2, FileType.Nef, FileType.Orf, - FileType.Rw2 -> safeReadTiff(inputStream) + FileType.Rw2 -> safeReadTiff(inputStream, streamLength) - else -> ImageMetadataReader.readMetadata(inputStream, SAFE_READ_STREAM_LENGTH, fileType) + else -> ImageMetadataReader.readMetadata(inputStream, streamLength, fileType) } metadata.addDirectory(FileTypeDirectory(fileType)) @@ -115,10 +117,11 @@ object Helper { } @Throws(IOException::class, TiffProcessingException::class) - fun safeReadTiff(input: InputStream): com.drew.metadata.Metadata { - val reader = RandomAccessStreamReader(input, RandomAccessStreamReader.DEFAULT_CHUNK_LENGTH, SAFE_READ_STREAM_LENGTH) + fun safeReadTiff(input: InputStream, streamLength: Long): com.drew.metadata.Metadata { + val reader = RandomAccessStreamReader(input, RandomAccessStreamReader.DEFAULT_CHUNK_LENGTH, streamLength) val metadata = com.drew.metadata.Metadata() val handler = SafeExifTiffHandler(metadata, null, 0) + Log.d(LOG_TAG, "safeReadTiff: availableHeapSize=${MemoryUtils.getAvailableHeapSize()}") TiffReader().processTiff(reader, handler, 0) return metadata } diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/model/SourceEntry.kt b/android/app/src/main/kotlin/deckers/thibault/aves/model/SourceEntry.kt index 3fbb68b33..d339fda96 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/model/SourceEntry.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/model/SourceEntry.kt @@ -163,7 +163,7 @@ class SourceEntry { try { Metadata.openSafeInputStream(context, uri, sourceMimeType, sizeBytes)?.use { input -> - val metadata = Helper.safeRead(input) + val metadata = Helper.safeRead(input, sizeBytes) // do not switch on specific MIME types, as the reported MIME type could be wrong // (e.g. PNG registered as JPG)