From dcd42b7048a177ef09503dd90f1bfd670da54cb1 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Tue, 11 Mar 2025 00:24:03 +0100 Subject: [PATCH] #1471 check file length after metadata editing via PixyMeta --- .../thibault/aves/metadata/PixyMetaHelper.kt | 1 + .../aves/model/provider/ImageProvider.kt | 26 +++++++++++++++---- .../info/metadata/metadata_section.dart | 2 +- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/metadata/PixyMetaHelper.kt b/android/app/src/main/kotlin/deckers/thibault/aves/metadata/PixyMetaHelper.kt index 04e5365ef..e1d11786e 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/metadata/PixyMetaHelper.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/metadata/PixyMetaHelper.kt @@ -92,6 +92,7 @@ object PixyMetaHelper { fun getXmp(input: InputStream): XMP? = Metadata.readMetadata(input)[MetadataType.XMP] as XMP? + // PixyMeta may fail with just a log, and write nothing to the output fun setXmp( input: InputStream, output: OutputStream, diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/model/provider/ImageProvider.kt b/android/app/src/main/kotlin/deckers/thibault/aves/model/provider/ImageProvider.kt index 39fbf091d..9d36f1812 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/model/provider/ImageProvider.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/model/provider/ImageProvider.kt @@ -680,18 +680,19 @@ abstract class ImageProvider { try { edit(ExifInterface(editableFile)) + if (editableFile.length() == 0L) { + callback.onFailure(Exception("editing Exif yielded an empty file")) + return false + } + val editedMimeType = detectMimeType(context, Uri.fromFile(editableFile), mimeType) if (editedMimeType != mimeType) { throw Exception("editing Exif changes mimeType=$mimeType -> $editedMimeType for uri=$uri path=$path") } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - // 1) as of androidx.exifinterface:exifinterface:1.3.6, editing some specific WEBP - // makes them undecodable by some decoders (including Android's and Chrome's) - // even though `BitmapFactory` successfully decodes their bounds, + // editing may corrupt the file for various reasons, // so we check whether decoding it throws an exception - // 2) some users have reported corruption when editing JPEG as well, - // but conditions are unknown (specific image, custom ROM, low storage, race condition, etc.) ImageDecoder.decodeBitmap(ImageDecoder.createSource(editableFile)) } @@ -781,6 +782,11 @@ abstract class ImageProvider { } } + if (editableFile.length() == 0L) { + callback.onFailure(Exception("editing IPTC yielded an empty file")) + return false + } + if (trailerVideoBytes != null) { // append trailer video, if any editableFile.appendBytes(trailerVideoBytes!!) @@ -917,6 +923,11 @@ abstract class ImageProvider { } } + if (editableFile.length() == 0L) { + callback.onFailure(Exception("editing XMP yielded an empty file")) + return false + } + try { // copy the edited temporary file back to the original editableFile.transferTo(outputStream(context, mimeType, uri, path)) @@ -1330,6 +1341,11 @@ abstract class ImageProvider { } } + if (editableFile.length() == 0L) { + callback.onFailure(Exception("removing metadata yielded an empty file")) + return + } + try { // copy the edited temporary file back to the original editableFile.transferTo(outputStream(context, mimeType, uri, path)) diff --git a/lib/widgets/viewer/info/metadata/metadata_section.dart b/lib/widgets/viewer/info/metadata/metadata_section.dart index bd0d34c34..00f24d51f 100644 --- a/lib/widgets/viewer/info/metadata/metadata_section.dart +++ b/lib/widgets/viewer/info/metadata/metadata_section.dart @@ -144,8 +144,8 @@ class _MetadataSectionSliverState extends State { } Future _getMetadata() async { - if (!mounted) return; final titledDirectories = await entry.getMetadataDirectories(context); + if (!mounted) return; metadataNotifier.value = Map.fromEntries(titledDirectories); _expandedDirectoryNotifier.value = null; }