drewnoakes / metadata-extractor

Extracts Exif, IPTC, XMP, ICC and other metadata from image, video and audio files
Apache License 2.0
2.56k stars 480 forks source link

EXIF Metadata parsing fails with IllegalArgumentException: Input is not a bplist #508

Closed swurzinger closed 3 years ago

swurzinger commented 3 years ago

Regression in 2.14.0 (issue does not occur in 2.13.0 or earlier)

Sample code to reproduce (Kotlin):

    fun parseExifTest() {
        val jpgFile = File("sample.jpg")
        val metadata = ImageMetadataReader.readMetadata(jpgFile)
    }

sample.jpg (downsized to 1px * 1px, because image data size doesn't matter): https://user-images.githubusercontent.com/6787397/95858295-293e4b00-0d5d-11eb-840a-5819da541d6b.jpg

Exception (in 2.14; works in 2.13 or earlier):

Input is not a bplist
java.lang.IllegalArgumentException: Input is not a bplist
    at com.drew.metadata.plist.BplistReader.parse(BplistReader.java:68)
    at com.drew.metadata.exif.ExifTiffHandler.processAppleRunTime(ExifTiffHandler.java:369)
    at com.drew.metadata.exif.ExifTiffHandler.customProcessTag(ExifTiffHandler.java:251)
    at com.drew.imaging.tiff.TiffReader.processIfd(TiffReader.java:220)
    at com.drew.metadata.exif.ExifTiffHandler.processMakernote(ExifTiffHandler.java:645)
    at com.drew.metadata.exif.ExifTiffHandler.customProcessTag(ExifTiffHandler.java:207)
    at com.drew.imaging.tiff.TiffReader.processIfd(TiffReader.java:220)
    at com.drew.imaging.tiff.TiffReader.processIfd(TiffReader.java:214)
    at com.drew.imaging.tiff.TiffReader.processTiff(TiffReader.java:78)
    at com.drew.metadata.exif.ExifReader.extract(ExifReader.java:94)
    at com.drew.metadata.exif.ExifReader.extract(ExifReader.java:84)
    at com.drew.metadata.exif.ExifReader.readJpegSegments(ExifReader.java:63)
    at com.drew.imaging.jpeg.JpegMetadataReader.processJpegSegmentData(JpegMetadataReader.java:134)
    at com.drew.imaging.jpeg.JpegMetadataReader.process(JpegMetadataReader.java:126)
    at com.drew.imaging.jpeg.JpegMetadataReader.readMetadata(JpegMetadataReader.java:77)
    at com.drew.imaging.jpeg.JpegMetadataReader.readMetadata(JpegMetadataReader.java:84)
    at com.drew.imaging.ImageMetadataReader.readMetadata(ImageMetadataReader.java:146)
    at com.drew.imaging.ImageMetadataReader.readMetadata(ImageMetadataReader.java:124)
    at com.drew.imaging.ImageMetadataReader.readMetadata(ImageMetadataReader.java:204)
    at com.example.demo.UnitTest.parseExifTest(UnitTest.kt:14)
nosnhojbob commented 3 years ago

I downloaded this sample and it looks like malformed data. The "normal" expectation is that it would start with the bplist\0\0 bytes, but in this sample, that structure appears "deeper" into the array. Even the data in that offset-bplist did not appear to be parse-able.

Since the ExifTiffHandler.customProcessTag() method catches IOException while analyzing the BPLIST data, changing from IllegalArgumentException to IOException should give the desired effect. We would simply see the error message added to the directory while processing and it wouldn't fail the entire document.

nosnhojbob commented 3 years ago

Additional note on the data in the image; I extracted the 104-byte array and attempted to preview on a Mac - nothing viewable. The 20-byte section that contained the header was not pre-viewable either.

paperboyo commented 3 years ago

downsized to 1px * 1px, because image data size doesn't matter

This may be totally unrelated, but could I ask how was it resized? Because I haven’t found a way to resize an image without affecting any metadata (eg. an example in https://github.com/drewnoakes/metadata-extractor/issues/435#issue-490266692 was concocted using a hex editor because of that). If anyone knows an easier way to strip/minimise image data, I would love to know!

swurzinger commented 3 years ago

@BobJohnsonGitHub what kind of data is that bplist? According to the metadata the image was created by an iPhone XR. I just can tell that version 2.13 did not throw an exception while parsing the metadata and all simple EXIF fields like e.g. orientation or dataTaken were available. Common software like ExifTool, Windows Explorer or XnViewMP also display EXIF data nicely:

image

image

@paperboyo I used paint.net, but it did not leave the metadata unmodified, the error just occurs both with the original image and the downscaled one.

nosnhojbob commented 3 years ago

@swurzinger The bplist is supposed to contain data about how long your phone has been running since the last boot (excluding standby time).

@drewnoakes I can pick this up and fix, if you think the use of IOException (as noted in https://github.com/drewnoakes/metadata-extractor/issues/508#issuecomment-782725582) is a good approach.

drewnoakes commented 3 years ago

@nosnhojbob thanks, that would be great. At the point it's thrown, it doesn't really seem like an IOException. Is there a place higher in the call stack where the current exception could be caught and an error added to the Directory?

nosnhojbob commented 3 years ago

Please see PR https://github.com/drewnoakes/metadata-extractor/pull/531 ^^^ @drewnoakes

I tested with existing images and a local copy of the problematic one.

drewnoakes commented 3 years ago

Fixed by @nosnhojbob in #531.

charlesritchea commented 2 years ago

@drewnoakes what's the chance of getting a new release with this fix?

drewnoakes commented 2 years ago

Released in https://github.com/drewnoakes/metadata-extractor/releases/tag/2.17.0