From b02aec53e5742c13e8b7e5f03083c4d7f2bf7ab6 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Fri, 27 May 2022 13:26:17 +0900 Subject: [PATCH] fixed crash when cataloguing large TIFF --- CHANGELOG.md | 1 + .../thibault/aves/channel/calls/DebugHandler.kt | 2 +- .../aves/channel/calls/EmbeddedDataHandler.kt | 2 +- .../aves/channel/calls/MetadataFetchHandler.kt | 14 +++++++------- .../aves/metadata/MetadataExtractorHelper.kt | 6 +++--- .../deckers/thibault/aves/metadata/MultiPage.kt | 4 ++-- .../deckers/thibault/aves/model/SourceEntry.kt | 6 +++--- .../deckers/thibault/aves/utils/MimeTypes.kt | 2 +- 8 files changed, 19 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa9e26211..8b921a92c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file. - wrong window metrics on startup in some cases - home albums not updated on startup in some cases +- crash when cataloguing large TIFF ## [v1.6.7] - 2022-05-25 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 84f6db94f..a9d23fe13 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 @@ -284,7 +284,7 @@ class DebugHandler(private val context: Context) : MethodCallHandler { if (canReadWithMetadataExtractor(mimeType)) { try { Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input -> - val metadata = MetadataExtractorHelper.safeRead(input, sizeBytes) + val metadata = MetadataExtractorHelper.safeRead(input) 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 f09bf8ce1..ef9210cf1 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 @@ -150,7 +150,7 @@ class EmbeddedDataHandler(private val context: Context) : MethodCallHandler { if (canReadWithMetadataExtractor(mimeType)) { try { Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input -> - val metadata = MetadataExtractorHelper.safeRead(input, sizeBytes) + val metadata = MetadataExtractorHelper.safeRead(input) // 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 ce3d27742..b76620d2c 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 @@ -126,7 +126,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler { if (canReadWithMetadataExtractor(mimeType)) { try { Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input -> - val metadata = MetadataExtractorHelper.safeRead(input, sizeBytes) + val metadata = MetadataExtractorHelper.safeRead(input) foundExif = metadata.directories.any { it is ExifDirectoryBase && it.tagCount > 0 } foundXmp = metadata.directories.any { it is XmpDirectory && it.tagCount > 0 } val uuidDirCount = HashMap() @@ -451,7 +451,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler { if (canReadWithMetadataExtractor(mimeType)) { try { Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input -> - val metadata = MetadataExtractorHelper.safeRead(input, sizeBytes) + val metadata = MetadataExtractorHelper.safeRead(input) foundExif = metadata.directories.any { it is ExifDirectoryBase && it.tagCount > 0 } // File type @@ -718,7 +718,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler { if (canReadWithMetadataExtractor(mimeType)) { try { Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input -> - val metadata = MetadataExtractorHelper.safeRead(input, sizeBytes) + val metadata = MetadataExtractorHelper.safeRead(input) for (dir in metadata.getDirectoriesOfType(ExifSubIFDDirectory::class.java)) { foundExif = true dir.getSafeRational(ExifDirectoryBase.TAG_FNUMBER) { metadataMap[KEY_APERTURE] = it.numerator.toDouble() / it.denominator } @@ -768,7 +768,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler { if (canReadWithMetadataExtractor(mimeType)) { try { Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input -> - val metadata = MetadataExtractorHelper.safeRead(input, sizeBytes) + val metadata = MetadataExtractorHelper.safeRead(input) val fields = HashMap() for (dir in metadata.getDirectoriesOfType(ExifIFD0Directory::class.java)) { if (dir.containsGeoTiffTags()) { @@ -831,7 +831,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler { if (canReadWithMetadataExtractor(mimeType)) { try { Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input -> - val metadata = MetadataExtractorHelper.safeRead(input, sizeBytes) + val metadata = MetadataExtractorHelper.safeRead(input) val fields: FieldMap = hashMapOf( "projectionType" to XMP.GPANO_PROJECTION_TYPE_DEFAULT, ) @@ -895,7 +895,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler { if (canReadWithMetadataExtractor(mimeType)) { try { Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input -> - val metadata = MetadataExtractorHelper.safeRead(input, sizeBytes) + val metadata = MetadataExtractorHelper.safeRead(input) val xmpStrings = metadata.getDirectoriesOfType(XmpDirectory::class.java).mapNotNull { XMPMetaFactory.serializeToString(it.xmpMeta, xmpSerializeOptions) } result.success(xmpStrings.toMutableList()) return @@ -1000,7 +1000,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler { if (canReadWithMetadataExtractor(mimeType)) { try { Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input -> - val metadata = MetadataExtractorHelper.safeRead(input, sizeBytes) + val metadata = MetadataExtractorHelper.safeRead(input) val tag = when (field) { ExifInterface.TAG_DATETIME -> ExifIFD0Directory.TAG_DATETIME ExifInterface.TAG_DATETIME_DIGITIZED -> ExifSubIFDDirectory.TAG_DATETIME_DIGITIZED diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/metadata/MetadataExtractorHelper.kt b/android/app/src/main/kotlin/deckers/thibault/aves/metadata/MetadataExtractorHelper.kt index bbd790fcf..ef5639d22 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/metadata/MetadataExtractorHelper.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/metadata/MetadataExtractorHelper.kt @@ -48,15 +48,15 @@ object MetadataExtractorHelper { return FileTypeDetector.detectFileType(bufferedInputStream).mimeType } - fun safeRead(input: InputStream, sizeBytes: Long?): com.drew.metadata.Metadata { - val streamLength = sizeBytes ?: -1 + fun safeRead(input: InputStream): com.drew.metadata.Metadata { val bufferedInputStream = if (input is BufferedInputStream) input else BufferedInputStream(input) val fileType = FileTypeDetector.detectFileType(bufferedInputStream) val metadata = if (fileType == FileType.Jpeg) { safeReadJpeg(bufferedInputStream) } else { - ImageMetadataReader.readMetadata(bufferedInputStream, streamLength, fileType) + // providing the stream length is risky, as it may crash if it is incorrect + ImageMetadataReader.readMetadata(bufferedInputStream, -1L, fileType) } metadata.addDirectory(FileTypeDirectory(fileType)) 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 e9a5dcabf..6d17f94e2 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 @@ -140,7 +140,7 @@ object MultiPage { fun getMotionPhotoOffset(context: Context, uri: Uri, mimeType: String, sizeBytes: Long): Long? { try { Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input -> - val metadata = MetadataExtractorHelper.safeRead(input, sizeBytes) + val metadata = MetadataExtractorHelper.safeRead(input) for (dir in metadata.getDirectoriesOfType(XmpDirectory::class.java)) { var offsetFromEnd: Long? = null val xmpMeta = dir.xmpMeta @@ -194,7 +194,7 @@ object MultiPage { return pages } - fun isMultiPageTiff(context: Context, uri: Uri) = getTiffPageInfo(context, uri, 0)?.outDirectoryCount ?: 1 > 1 + fun isMultiPageTiff(context: Context, uri: Uri) = (getTiffPageInfo(context, uri, 0)?.outDirectoryCount ?: 1) > 1 private fun getTiffPageInfo(context: Context, uri: Uri, page: Int): TiffBitmapFactory.Options? { try { 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 09406b448..347835fef 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 @@ -97,10 +97,10 @@ class SourceEntry { get() = if (uri.scheme == ContentResolver.SCHEME_CONTENT) uri.tryParseId() else null val isSized: Boolean - get() = width ?: 0 > 0 && height ?: 0 > 0 + get() = (width ?: 0) > 0 && (height ?: 0) > 0 private val hasDuration: Boolean - get() = durationMillis ?: 0 > 0 + get() = (durationMillis ?: 0) > 0 val isVideo: Boolean get() = MimeTypes.isVideo(sourceMimeType) @@ -161,7 +161,7 @@ class SourceEntry { try { Metadata.openSafeInputStream(context, uri, sourceMimeType, sizeBytes)?.use { input -> - val metadata = MetadataExtractorHelper.safeRead(input, sizeBytes) + val metadata = MetadataExtractorHelper.safeRead(input) // do not switch on specific MIME types, as the reported MIME type could be wrong // (e.g. PNG registered as JPG) diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/utils/MimeTypes.kt b/android/app/src/main/kotlin/deckers/thibault/aves/utils/MimeTypes.kt index c1a41b665..55a134192 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/utils/MimeTypes.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/utils/MimeTypes.kt @@ -84,7 +84,7 @@ object MimeTypes { // as of Flutter v1.22.0, with additional custom handling for SVG fun canDecodeWithFlutter(mimeType: String, rotationDegrees: Int?, isFlipped: Boolean?) = when (mimeType) { JPEG, GIF, WEBP, BMP, WBMP, ICO, SVG -> true - PNG -> rotationDegrees ?: 0 == 0 && !(isFlipped ?: false) + PNG -> (rotationDegrees ?: 0) == 0 && !(isFlipped ?: false) else -> false }