From 481302dabf6e2f09a23fad3c8d8586664ce6929d Mon Sep 17 00:00:00 2001 From: Peter Abbondanzo Date: Wed, 16 Oct 2024 12:27:11 -0700 Subject: [PATCH] Add binary XML format to default image formats Reviewed By: oprisnik Differential Revision: D64332670 --- .../imageformat/DefaultImageFormatChecker.kt | 29 ++++++++++++++++++- .../imageformat/DefaultImageFormats.kt | 2 ++ .../decoder/DefaultImageDecoder.java | 2 ++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/imagepipeline-base/src/main/java/com/facebook/imageformat/DefaultImageFormatChecker.kt b/imagepipeline-base/src/main/java/com/facebook/imageformat/DefaultImageFormatChecker.kt index 77af7ce9e5..7d69e1a957 100644 --- a/imagepipeline-base/src/main/java/com/facebook/imageformat/DefaultImageFormatChecker.kt +++ b/imagepipeline-base/src/main/java/com/facebook/imageformat/DefaultImageFormatChecker.kt @@ -28,7 +28,9 @@ class DefaultImageFormatChecker : FormatChecker { GIF_HEADER_LENGTH, BMP_HEADER_LENGTH, ICO_HEADER_LENGTH, - HEIF_HEADER_LENGTH) + HEIF_HEADER_LENGTH, + BINARY_XML_HEADER_LENGTH, + ) .maxOrNull()) /** @@ -61,6 +63,9 @@ class DefaultImageFormatChecker : FormatChecker { if (isHeifHeader(headerBytes, headerSize)) { return DefaultImageFormats.HEIF } + if (isBinaryXmlHeader(headerBytes, headerSize)) { + return DefaultImageFormats.BINARY_XML + } return if (isDngHeader(headerBytes, headerSize)) { DefaultImageFormats.DNG } else { @@ -277,5 +282,27 @@ class DefaultImageFormatChecker : FormatChecker { headerSize >= DNG_HEADER_LENGTH && (ImageFormatCheckerUtils.startsWithPattern(imageHeaderBytes, DNG_HEADER_II) || ImageFormatCheckerUtils.startsWithPattern(imageHeaderBytes, DNG_HEADER_MM)) + + /** + * These are the first 4 bytes of a binary XML file. We can only support binary XML files and + * not raw XML files because Android explicitly disallows raw XML files when inflating + * drawables. Binary XML files are created at build time by Android's AAPT. + * + * @see + * https://developer.android.com/reference/android/view/LayoutInflater#inflate(org.xmlpull.v1.XmlPullParser,%20android.view.ViewGroup) + */ + private val BINARY_XML_HEADER: ByteArray = + byteArrayOf( + 3.toByte(), + 0.toByte(), + 8.toByte(), + 0.toByte(), + ) + private const val BINARY_XML_HEADER_LENGTH: Int = 4 + + private fun isBinaryXmlHeader(headerBytes: ByteArray, headerSize: Int): Boolean { + return headerSize >= BINARY_XML_HEADER_LENGTH && + ImageFormatCheckerUtils.startsWithPattern(headerBytes, BINARY_XML_HEADER) + } } } diff --git a/imagepipeline-base/src/main/java/com/facebook/imageformat/DefaultImageFormats.kt b/imagepipeline-base/src/main/java/com/facebook/imageformat/DefaultImageFormats.kt index e3ed98bf3a..2c2a37bae7 100644 --- a/imagepipeline-base/src/main/java/com/facebook/imageformat/DefaultImageFormats.kt +++ b/imagepipeline-base/src/main/java/com/facebook/imageformat/DefaultImageFormats.kt @@ -22,6 +22,7 @@ object DefaultImageFormats { @JvmField val WEBP_ANIMATED: ImageFormat = ImageFormat("WEBP_ANIMATED", "webp") @JvmField val HEIF: ImageFormat = ImageFormat("HEIF", "heif") @JvmField val DNG: ImageFormat = ImageFormat("DNG", "dng") + @JvmField val BINARY_XML: ImageFormat = ImageFormat("BINARY_XML", "xml") /** * Check if the given image format is a WebP image format (static or animated). @@ -67,5 +68,6 @@ object DefaultImageFormats { WEBP_EXTENDED_WITH_ALPHA, WEBP_ANIMATED, HEIF, + BINARY_XML, ) } diff --git a/imagepipeline/src/main/java/com/facebook/imagepipeline/decoder/DefaultImageDecoder.java b/imagepipeline/src/main/java/com/facebook/imagepipeline/decoder/DefaultImageDecoder.java index 41f6806b4d..a87013b1d8 100644 --- a/imagepipeline/src/main/java/com/facebook/imagepipeline/decoder/DefaultImageDecoder.java +++ b/imagepipeline/src/main/java/com/facebook/imagepipeline/decoder/DefaultImageDecoder.java @@ -76,6 +76,8 @@ public class DefaultImageDecoder implements ImageDecoder { return decodeGif(encodedImage, length, qualityInfo, options); } else if (imageFormat == DefaultImageFormats.WEBP_ANIMATED) { return decodeAnimatedWebp(encodedImage, length, qualityInfo, options); + } else if (imageFormat == DefaultImageFormats.BINARY_XML) { + throw new DecodeException("unsupported image format", encodedImage); } else if (imageFormat == ImageFormat.UNKNOWN) { throw new DecodeException("unknown image format", encodedImage); }