From 3d502a496e08efcbb87cea69744d4380ab3d4973 Mon Sep 17 00:00:00 2001 From: sandtechnology <20417547+sandtechnology@users.noreply.github.com> Date: Thu, 28 Oct 2021 20:43:31 +0800 Subject: [PATCH] Handle other cases in jpeg header (#1611) * Handle other cases in jpeg header Co-authored-by: sandtechnology * Add unit tests Co-authored-by: Karlatemp --- .../commonMain/kotlin/message/ImageDecoder.kt | 28 ++++++++++-------- .../kotlin/message/ImageReadingTest.kt | 25 ++++++++++++++++ .../image/jpeg-header-issue-1610.bin | Bin 0 -> 156825 bytes 3 files changed, 40 insertions(+), 13 deletions(-) create mode 100644 mirai-core/src/commonTest/resources/image/jpeg-header-issue-1610.bin diff --git a/mirai-core/src/commonMain/kotlin/message/ImageDecoder.kt b/mirai-core/src/commonMain/kotlin/message/ImageDecoder.kt index c179dafb3..513815153 100644 --- a/mirai-core/src/commonMain/kotlin/message/ImageDecoder.kt +++ b/mirai-core/src/commonMain/kotlin/message/ImageDecoder.kt @@ -18,20 +18,21 @@ import java.io.IOException //SOF0-SOF3 SOF5-SOF7 SOF9-SOF11 SOF13-SOF15 Segment // (0xC4, 0xC8 and 0xCC not included due to is not an SOF) private val JPG_SOF_RANGE = listOf( - 0xC0.toByte()..0xC3.toByte(), - 0xC5.toByte()..0xC7.toByte(), - 0xC9.toByte()..0xCB.toByte(), - 0xCD.toByte()..0xCF.toByte() + 0xC0..0xC3, + 0xC5..0xC7, + 0xC9..0xCB, + 0xCD..0xCF ) // https://docs.fileformat.com/image/jpeg/ +// http://www.vip.sugovica.hu/Sardi/kepnezo/JPEG%20File%20Layout%20and%20Format.htm private fun Input.getJPGImageInfo(): ImageInfo { require(readBytes(2).contentEquals(byteArrayOf(0xFF.toByte(), 0xD8.toByte()))) { "It's not a valid jpg file" } //0xFF Segment Start while (readByte() == 0xFF.toByte()) { - val type = readByte() + val type = readByte().toIntUnsigned() //Find SOF if (JPG_SOF_RANGE.any { it.contains(type) }) { //Length @@ -42,15 +43,16 @@ private fun Input.getJPGImageInfo(): ImageInfo { val width = readShort().toInt() return ImageInfo(width = width, height = height, imageType = ImageType.JPG) } else { - //SOS Segment, header is ended - if (type == 0xDA.toByte()) { - break + when (type) { + //SOS Segment, header is ended + 0xDA -> break + //0x00 (Byte alignment) and 0x01 (TEM) + in 0x00..0x01 -> continue + //RST[0-7] no length and content, skip + in 0xD0..0xD7 -> continue + //Normal segment, Skipped size=Segment Length - 2 (Length data itself) + else -> discardExact(readShort().toIntUnsigned() - 2) } - //Other segment, skip - discardExact( - //Skip size=segment length - 2 (length data itself) - readShort().toIntUnsigned() - 2 - ) } } throw IllegalArgumentException("It's not a valid jpg file, failed to find an SOF segment") diff --git a/mirai-core/src/commonTest/kotlin/message/ImageReadingTest.kt b/mirai-core/src/commonTest/kotlin/message/ImageReadingTest.kt index 5ab1751ac..b40f2a680 100644 --- a/mirai-core/src/commonTest/kotlin/message/ImageReadingTest.kt +++ b/mirai-core/src/commonTest/kotlin/message/ImageReadingTest.kt @@ -15,6 +15,7 @@ import net.mamoe.mirai.utils.ExternalResource.Companion.toExternalResource import net.mamoe.mirai.utils.hexToBytes import net.mamoe.mirai.utils.withUse import org.junit.jupiter.api.Test +import java.io.File import java.io.IOException import kotlin.test.assertEquals import kotlin.test.assertFailsWith @@ -52,6 +53,23 @@ internal class ImageReadingTest : AbstractTest() { "FF D8 FF E0 00 10 4A 46 49 46 00 01 01 01 00 78 00 78 00 00 FF E1 00 5A 45 78 69 66 00 00 4D 4D 00 2A 00 00 00 08 00 05 03 01 00 05 00 00 00 01 00 00 00 4A 03 03 00 01 00 00 00 01 00 00 00 00 51 10 00 01 00 00 00 01 01 00 00 00 51 11 00 04 00 00 00 01 00 00 12 74 51 12 00 04 00 00 00 01 00 00 12 74 00 00 00 00 00 01 86 A0 00 00 B1 8F FF DB 00 43 00 02 01 01 02 01 01 02 02 02 02 02 02 02 02 03 05 03 03 03 03 03 06 04 04 03 05 07 06 07 07 07 06 07 07 08 09 0B 09 08 08 0A 08 07 07 0A 0D 0A 0A 0B 0C 0C 0C 0C 07 09 0E 0F 0D 0C 0E 0B 0C 0C 0C FF DB 00 43 01 02 02 02 03 03 03 06 03 03 06 0C 08 07 08 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C FF C2 00 11 08 01 90 01 E0 03 01 22 00 02 11 01 03 11 01 FF DA".testMatch( ImageType.JPG ) + //FF 01 + "FF D8 FF E0 00 10 4A 46 49 46 00 01 01 01 00 78 00 78 00 00 FF 01 FF E1 00 5A 45 78 69 66 00 00 4D 4D 00 2A 00 00 00 08 00 05 03 01 00 05 00 00 00 01 00 00 00 4A 03 03 00 01 00 00 00 01 00 00 00 00 51 10 00 01 00 00 00 01 01 00 00 00 51 11 00 04 00 00 00 01 00 00 12 74 51 12 00 04 00 00 00 01 00 00 12 74 00 00 00 00 00 01 86 A0 00 00 B1 8F FF DB 00 43 00 02 01 01 02 01 01 02 02 02 02 02 02 02 02 03 05 03 03 03 03 03 06 04 04 03 05 07 06 07 07 07 06 07 07 08 09 0B 09 08 08 0A 08 07 07 0A 0D 0A 0A 0B 0C 0C 0C 0C 07 09 0E 0F 0D 0C 0E 0B 0C 0C 0C FF DB 00 43 01 02 02 02 03 03 03 06 03 03 06 0C 08 07 08 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C FF C2 00 11 08 01 90 01 E0 03 01 22 00 02 11 01 03 11 01 FF DA".testMatch( + ImageType.JPG + ) + //FF 00 + "FF D8 FF E0 00 10 4A 46 49 46 00 01 01 01 00 78 00 78 00 00 FF 00 FF E1 00 5A 45 78 69 66 00 00 4D 4D 00 2A 00 00 00 08 00 05 03 01 00 05 00 00 00 01 00 00 00 4A 03 03 00 01 00 00 00 01 00 00 00 00 51 10 00 01 00 00 00 01 01 00 00 00 51 11 00 04 00 00 00 01 00 00 12 74 51 12 00 04 00 00 00 01 00 00 12 74 00 00 00 00 00 01 86 A0 00 00 B1 8F FF DB 00 43 00 02 01 01 02 01 01 02 02 02 02 02 02 02 02 03 05 03 03 03 03 03 06 04 04 03 05 07 06 07 07 07 06 07 07 08 09 0B 09 08 08 0A 08 07 07 0A 0D 0A 0A 0B 0C 0C 0C 0C 07 09 0E 0F 0D 0C 0E 0B 0C 0C 0C FF DB 00 43 01 02 02 02 03 03 03 06 03 03 06 0C 08 07 08 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C FF C2 00 11 08 01 90 01 E0 03 01 22 00 02 11 01 03 11 01 FF DA".testMatch( + ImageType.JPG + ) + //RST[0-7] + "FF D8 FF E0 00 10 4A 46 49 46 00 01 01 01 00 78 00 78 00 00 FF D0 FF D1 FF D2 FF D3 FF D4 FF D5 FF D6 FF D7 FF E1 00 5A 45 78 69 66 00 00 4D 4D 00 2A 00 00 00 08 00 05 03 01 00 05 00 00 00 01 00 00 00 4A 03 03 00 01 00 00 00 01 00 00 00 00 51 10 00 01 00 00 00 01 01 00 00 00 51 11 00 04 00 00 00 01 00 00 12 74 51 12 00 04 00 00 00 01 00 00 12 74 00 00 00 00 00 01 86 A0 00 00 B1 8F FF DB 00 43 00 02 01 01 02 01 01 02 02 02 02 02 02 02 02 03 05 03 03 03 03 03 06 04 04 03 05 07 06 07 07 07 06 07 07 08 09 0B 09 08 08 0A 08 07 07 0A 0D 0A 0A 0B 0C 0C 0C 0C 07 09 0E 0F 0D 0C 0E 0B 0C 0C 0C FF DB 00 43 01 02 02 02 03 03 03 06 03 03 06 0C 08 07 08 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C FF C2 00 11 08 01 90 01 E0 03 01 22 00 02 11 01 03 11 01 FF DA".testMatch( + ImageType.JPG + ) + println("Current path: "+File(".").absolutePath) + //Issue 1610 + File("./src/commonTest/resources/image/jpeg-header-issue-1610.bin").readBytes().testRead( + ImageType.JPG + ) //Failed to find assertFailsWith(IllegalArgumentException::class) { "FF D8 FF E0 00 10 4A 46 49 46 00 01 01 01 00 78 00 78 00 00 FF E1 00 5A 45 78 69 66 00 00 4D 4D 00 2A 00 00 00 08 00 05 03 01 00 05 00 00 00 01 00 00 00 4A 03 03 00 01 00 00 00 01 00 00 00 00 51 10 00 01 00 00 00 01 01 00 00 00 51 11 00 04 00 00 00 01 00 00 12 74 51 12 00 04 00 00 00 01 00 00 12 74 00 00 00 00 00 01 86 A0 00 00 B1 8F FF DB 00 43 00 02 01 01 02 01 01 02 02 02 02 02 02 02 02 03 05 03 03 03 03 03 06 04 04 03 05 07 06 07 07 07 06 07 07 08 09 0B 09 08 08 0A 08 07 07 0A 0D 0A 0A 0B 0C 0C 0C 0C 07 09 0E 0F 0D 0C 0E 0B 0C 0C 0C FF DB 00 43 01 02 02 02 03 03 03 06 03 03 06 0C 08 07 08 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C FF DA".testMatch( @@ -83,6 +101,13 @@ internal class ImageReadingTest : AbstractTest() { } } + private fun ByteArray.testRead(type: ImageType) { + this.toExternalResource().withUse { + calculateImageInfo().run { + assertEquals(type, imageType, "imageType") + } + } + } private fun String.testMatch(type: ImageType) { this.hexToBytes().toExternalResource().withUse { calculateImageInfo().run { diff --git a/mirai-core/src/commonTest/resources/image/jpeg-header-issue-1610.bin b/mirai-core/src/commonTest/resources/image/jpeg-header-issue-1610.bin new file mode 100644 index 0000000000000000000000000000000000000000..bebf5752eff6a42d9c86f263f29fb41a2043f24c GIT binary patch literal 156825 zcmeI&O>Y~=8315PvI`@Z!aem=sOqht`6ZGP1)G6o*NB102<)Osj!SZ76OKrMq-(|J z{xJWH0_`Pe`#ad>a%c2K3AB3&nr8t~FL!5W-}jlB6)Eie@AIEZzx&hK@VHcZ{``-n zd!7cJjk$dT{n=C-3`& z^69hU?Cjm6og&Bg@84J6?^ec>*VTHb)2Y@P)kfn%*5bkR$I&b~doY^*A@8H;RH~V+Rq#1<8q$Z#q$sTl1`>st=&eY z{;<08NS;@g*`ZhahXgo-}kKfJ4S9-W~{MH_x zj7NjvV!&?e=Dg8OeLeYMc#@puIdxx*N9px^F1EP6m#6P0*~n)ZWg~ydEvstTOKfpd zN6)86Nq;hanT%ei-K%4hb#v+X%1)k*`|qZ&X2~q==3zScdYrAx!IhLQG`qQ*$CEU9 z@$TeWBKgVT;LWFhGoF6etv8$Xy}hdG1WNS-08R-)pv3W^l2ir{~kJ)6w*3{MX_}b7{Ke^*Shot$Hv-fq80zSCR=jlKMLt=tYlY+UOUhhh-HWAI7k)Iwd^ zZD@J*c&&AU+Fk+P3(k!}=qCh&&~wZ=UTZI0J&r}3HrLCEhvHbQli@9Gj>9_bhhTBb zT5RQZ$hi@MnEZa&6O-?SDq_yDoa@0Y`Fz@;R*~wU5pr%7^7WA6d52+7Eay1n9Fy;a zJ*^PLJ+X@O4#R5tygl_^NPbWRtuR}nd<u0t5`QL*m-#0RL94U; zgHcZQi(qh^=JTf9D?Xi^4@#UZ*MnF^4B`;PsU9W|-tS;xyIoyiLza@YtEAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK;V}yF#q>_{!2GdKLG*+2oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXFWCHX59R3yr0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7e?&rx9hkJ8^t z8<)4u{O#uE=0^6jwUxbOuXnZrTFHZQZ?l_s-o#T%4Yrx0y95jxSrS_d5Sr Xx_|H9KY#skYh$Ohd4FT;{>Fa+U=y&j literal 0 HcmV?d00001