* Bug 651482 - Allow decoding bitmaps with 52 and 56 byte info headers. r=tnikkel draft
authorwesj <we.j@live.com>
Fri, 22 May 2020 03:35:15 +0000
changeset 2913055 93f52a7b4680becb72f7db15eaf20fa1b7dfcf2c
parent 2912807 9a2f741cef6ae4ae568a17fd3ffe52599f0a574f
child 2913056 df26e3b4bb545130892164bd5af6e086627fd43b
push id542224
push usertnikkel@gmail.com
push dateSun, 24 May 2020 04:28:53 +0000
treeherdertry@df26e3b4bb54 [default view] [failures only]
reviewerstnikkel
bugs651482
milestone78.0a1
* Bug 651482 - Allow decoding bitmaps with 52 and 56 byte info headers. r=tnikkel Differential Revision: https://phabricator.services.mozilla.com/D75803
image/BMPHeaders.h
image/decoders/nsBMPDecoder.cpp
image/test/reftest/bmp/bmp-24bpp/24bpp-rgb-ref.png
image/test/reftest/bmp/bmp-24bpp/24bpp-rgb.bmp
image/test/reftest/bmp/bmp-24bpp/reftest.list
image/test/reftest/bmp/bmp-32bpp/32bpp-rgb-ref.png
image/test/reftest/bmp/bmp-32bpp/32bpp-rgb.bmp
image/test/reftest/bmp/bmp-32bpp/reftest.list
image/test/reftest/bmp/bmpsuite/q/reftest.list
image/test/reftest/bmp/bmpsuite/q/rgb32h52.png
image/test/reftest/bmp/bmpsuite/q/rgba32h56.png
image/test/reftest/bmp/reftest.list
--- a/image/BMPHeaders.h
+++ b/image/BMPHeaders.h
@@ -15,16 +15,18 @@ namespace bmp {
 // The length of the file header as defined in the BMP spec.
 static const size_t FILE_HEADER_LENGTH = 14;
 
 // This lengths of the info header for the different BMP versions.
 struct InfoHeaderLength {
   enum {
     WIN_V2 = 12,
     WIN_V3 = 40,
+    WIN_V3_NT = 52,
+    WIN_V3_NT_ALPHA = 56,
     WIN_V4 = 108,
     WIN_V5 = 124,
 
     // OS2_V1 is omitted; it's the same as WIN_V2.
     OS2_V2_MIN = 16,  // Minimum allowed value for OS2v2.
     OS2_V2_MAX = 64,  // Maximum allowed value for OS2v2.
 
     WIN_ICO = WIN_V3,
--- a/image/decoders/nsBMPDecoder.cpp
+++ b/image/decoders/nsBMPDecoder.cpp
@@ -31,29 +31,33 @@
 //   (|mBpp|) which must be 1, 4, 8 or 24.
 // - Next is the semi-optional color table, which has length 2^|mBpp| and has 3
 //   bytes per value (BGR). The color table is required if |mBpp| is 1, 4, or 8.
 // - Next is an optional gap.
 // - Next is the pixel data, which is pointed to by |mDataOffset|.
 //
 // WinBMPv3. This is the most widely used version.
 // - It changed the info header to 40 bytes by taking the WinBMPv2 info
-//   header, enlargening its width and height fields, and adding more fields
+//   header, enlarging its width and height fields, and adding more fields
 //   including: a compression type (|mCompression|) and number of colors
 //   (|mNumColors|).
 // - The semi-optional color table is now 4 bytes per value (BGR0), and its
 //   length is |mNumColors|, or 2^|mBpp| if |mNumColors| is zero.
 // - |mCompression| can be RGB (i.e. no compression), RLE4 (if |mBpp|==4) or
 //   RLE8 (if |mBpp|==8) values.
 //
 // WinBMPv3-NT. A variant of WinBMPv3.
 // - It did not change the info header layout from WinBMPv3.
 // - |mBpp| can now be 16 or 32, in which case |mCompression| can be RGB or the
 //   new BITFIELDS value; in the latter case an additional 12 bytes of color
-//   bitfields follow the info header.
+//   bitfields follow the info header (52 bytes total).
+//
+// WinBMPv3-NT-Alpha. A variant of WinBMPv3-NT with support for alpha channels.
+//   Adds an additional 4 bytes in in the info header (now 56 bytes total), and
+//   supports an alpha channel in the BITFIELDS sections.
 //
 // WinBMPv4.
 // - It extended the info header to 108 bytes, including the 12 bytes of color
 //   mask data from WinBMPv3-NT, plus alpha mask data, and also color-space and
 //   gamma correction fields.
 //
 // WinBMPv5.
 // - It extended the info header to 124 bytes, adding color profile data.
@@ -489,16 +493,18 @@ LexerTransition<nsBMPDecoder::State> nsB
 LexerTransition<nsBMPDecoder::State> nsBMPDecoder::ReadInfoHeaderSize(
     const char* aData, size_t aLength) {
   mPreGapLength += aLength;
 
   mH.mBIHSize = LittleEndian::readUint32(aData);
 
   bool bihSizeOk = mH.mBIHSize == InfoHeaderLength::WIN_V2 ||
                    mH.mBIHSize == InfoHeaderLength::WIN_V3 ||
+                   mH.mBIHSize == InfoHeaderLength::WIN_V3_NT ||
+                   mH.mBIHSize == InfoHeaderLength::WIN_V3_NT_ALPHA ||
                    mH.mBIHSize == InfoHeaderLength::WIN_V4 ||
                    mH.mBIHSize == InfoHeaderLength::WIN_V5 ||
                    (mH.mBIHSize >= InfoHeaderLength::OS2_V2_MIN &&
                     mH.mBIHSize <= InfoHeaderLength::OS2_V2_MAX);
   if (!bihSizeOk) {
     return Transition::TerminateFailure();
   }
   // ICO BMPs must have a WinBMPv3 header. nsICODecoder should have already
@@ -606,16 +612,18 @@ LexerTransition<nsBMPDecoder::State> nsB
        (mH.mBpp == 1 || mH.mBpp == 4 || mH.mBpp == 8 || mH.mBpp == 16 ||
         mH.mBpp == 24 || mH.mBpp == 32)) ||
       (mH.mCompression == Compression::RLE8 && mH.mBpp == 8) ||
       (mH.mCompression == Compression::RLE4 && mH.mBpp == 4) ||
       (mH.mCompression == Compression::BITFIELDS &&
        // For BITFIELDS compression we require an exact match for one of the
        // WinBMP BIH sizes; this clearly isn't an OS2 BMP.
        (mH.mBIHSize == InfoHeaderLength::WIN_V3 ||
+        mH.mBIHSize == InfoHeaderLength::WIN_V3_NT ||
+        mH.mBIHSize == InfoHeaderLength::WIN_V3_NT_ALPHA ||
         mH.mBIHSize == InfoHeaderLength::WIN_V4 ||
         mH.mBIHSize == InfoHeaderLength::WIN_V5) &&
        (mH.mBpp == 16 || mH.mBpp == 32));
   if (!bppCompressionOk) {
     return Transition::TerminateFailure();
   }
 
   // Initialize our current row to the top of the image.
@@ -628,17 +636,17 @@ LexerTransition<nsBMPDecoder::State> nsB
   uint32_t surplus = mPixelRowSize % 4;
   if (surplus != 0) {
     mPixelRowSize += 4 - surplus;
   }
 
   size_t bitFieldsLengthStillToRead = 0;
   if (mH.mCompression == Compression::BITFIELDS) {
     // Need to read bitfields.
-    if (mH.mBIHSize >= InfoHeaderLength::WIN_V4) {
+    if (mH.mBIHSize >= InfoHeaderLength::WIN_V3_NT) {
       // Bitfields are present in the info header, so we can read them
       // immediately.
       mBitFields.ReadFromHeader(aData + 36, /* aReadAlpha = */ true);
 
       // If this came from the clipboard, then we know that even if the header
       // explicitly includes the bitfield masks, we need to add an additional
       // offset for the start of the RGB data.
       if (mIsForClipboard) {
@@ -1034,18 +1042,17 @@ LexerTransition<nsBMPDecoder::State> nsB
       while (lpos > 0) {
         SetPixel(dst, src[2], src[1], src[0]);
         --lpos;
         src += 3;
       }
       break;
 
     case 32:
-      if (mH.mCompression == Compression::RGB && mIsWithinICO &&
-          mH.mBpp == 32) {
+      if (mH.mCompression == Compression::RGB && mIsWithinICO) {
         // This is a special case only used for 32bpp WinBMPv3-ICO files, which
         // could be in either 0RGB or ARGB format. We start by assuming it's
         // an 0RGB image. If we hit a non-zero alpha value, then we know it's
         // actually an ARGB image, and change tack accordingly.
         // (Note: a fully-transparent ARGB image is indistinguishable from a
         // 0RGB image, and we will render such an image as a 0RGB image, i.e.
         // opaquely. This is unlikely to be a problem in practice.)
         while (lpos > 0) {
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9de5fc22a23a0574caa860abe9748e7cb733d1a5
GIT binary patch
literal 100
zc%17D@N?(olHy`uVBq!ia0vp^Y#_|R1SIp<RmcM=#^NA%Cx&(BWL^R}a-J@ZAspA&
wo-kx&VBla@Nc(@zxMBUAB??@;$38}KJM3lVwi5gG4ycmB)78&qol`;+04CoV#Q*>R
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..65e2cf418ce5bd279c1bc817225ff07038240847
GIT binary patch
literal 174
rc${<cUB>_cW<aa~#B5N^$RGh0uK;3UZU{zz|3LH~Off(ydWZo4CUGWF
--- a/image/test/reftest/bmp/bmp-24bpp/reftest.list
+++ b/image/test/reftest/bmp/bmp-24bpp/reftest.list
@@ -14,8 +14,9 @@
 == bmp-size-16x16-24bpp.bmp bmp-size-16x16-24bpp.png
 == bmp-size-17x17-24bpp.bmp bmp-size-17x17-24bpp.png
 == bmp-size-31x31-24bpp.bmp bmp-size-31x31-24bpp.png
 == bmp-size-32x32-24bpp.bmp bmp-size-32x32-24bpp.png
 == bmp-size-33x33-24bpp.bmp bmp-size-33x33-24bpp.png
 == bmp-not-square-24bpp.bmp bmp-not-square-24bpp.png
 == os2bmp-size-32x32-24bpp.bmp bmp-size-32x32-24bpp.png
 == top-to-bottom-16x16-24bpp.bmp bmp-size-16x16-24bpp.png
+== 24bpp-rgb.bmp 24bpp-rgb-ref.png
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9de5fc22a23a0574caa860abe9748e7cb733d1a5
GIT binary patch
literal 100
zc%17D@N?(olHy`uVBq!ia0vp^Y#_|R1SIp<RmcM=#^NA%Cx&(BWL^R}a-J@ZAspA&
wo-kx&VBla@Nc(@zxMBUAB??@;$38}KJM3lVwi5gG4ycmB)78&qol`;+04CoV#Q*>R
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9dd5c28f5117ef279bad56a46e720e4c138d4975
GIT binary patch
literal 214
vc${<cy~Y3mZa{1S#B5N^$e_T$45TLju`o9TBZ2=ggx~}5e<%x`L1%FQAmu5!
new file mode 100644
--- /dev/null
+++ b/image/test/reftest/bmp/bmp-32bpp/reftest.list
@@ -0,0 +1,4 @@
+# BMP 32BPP tests
+
+# Images of various odd size info header sizes
+== 32bpp-rgb.bmp 32bpp-rgb-ref.png
--- a/image/test/reftest/bmp/bmpsuite/q/reftest.list
+++ b/image/test/reftest/bmp/bmpsuite/q/reftest.list
@@ -178,19 +178,18 @@ fuzzy(10-10,6590-6597) == rgb24prof2.bmp
 # BMP: bihsize=64, 127 x 64, bpp=24, compression=4, colors=0
 # "An OS/2v2 bitmap with RLE24 compression. This image uses a limited number
 # of colors, just to make it more compressible."
 # [We reject it. Chromium accepts it.]
 == wrapper.html?rgb24rle24.bmp about:blank
 
 # BMP: bihsize=52, 127 x 64, bpp=32, compression=3, colors=0
 # "Similar to g/rgb32bf.bmp, but with a 52-byte “BITMAPV2INFOHEADER”. This is
-# an uncommon version of BMP, and I can’t confirm that this file is correct."
-# [We reject it. Chromium accepts it.]
-== wrapper.html?rgb32h52.bmp about:blank
+# an uncommon version of BMP."
+== rgb32h52.bmp rgb32h52.png 
 
 # BMP: bihsize=124, 127 x 64, bpp=32, compression=3, colors=0
 # "Color channels are the same size and order as rgb32bfdef.bmp, but they use
 # the highest available bits, instead of the lowest (or vice versa, depending
 # on your byte-order perspective)."
 == rgb32-xbgr.bmp rgb24.png
 
 # BMP: bihsize=40, 127 x 64, bpp=32, compression=0, colors=0
@@ -241,11 +240,10 @@ fuzzy(0-1,0-1554) == rgba32-61754.bmp rg
 # "An image of type BI_ALPHABITFIELDS. Supposedly, this was used on Windows CE.
 # I don’t know whether it is constructed correctly."
 # [We reject it. Chromium accepts it.]
 == wrapper.html?rgba32abf.bmp about:blank
 
 # BMP: bihsize=56, 127 x 64, bpp=32, compression=3, colors=0
 # "Similar to q/rgba32.bmp, but with a 56-byte “BITMAPV3INFOHEADER”. This is an
 # uncommon version of BMP, and I can’t confirm that this file is correct."
-# [We reject it. Chromium accepts it.]
-== wrapper.html?rgba32h56.bmp about:blank
+== rgba32h56.bmp rgba32h56.png
 
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..86a9c945b0bfe98d71fb50f86f11434bea521882
GIT binary patch
literal 1072
zc%17D@N?(olHy`uVBq!ia0vp^^+4>v!2~4te73g%QjEnx?oJHr&dIz4aySb-B8wRq
zxP?KOkzv*x2?hq{tDY{7Ar-gY&N1}4?I7atKU6lSv~gliN^|d;9v{uDB~nutdhjTu
zW`tZ}X=<6{z-l;k)`gI@FBpPawG1CIc9t|v6x_C<RktU_TSX_9-Tm0cxu=g>nsffq
z=kI&}=l%WN_5a^l`*E-`crtl1Mdr=3I49{UbCpBj^CX^4p;zn9X*^o#=CR<};fogq
z88}~5WI7x$dcqsv)g0XSWuo0B_g^0JFO_ST^g}uJ0>Ahj4@-VxyYSuclLA5<q=<o`
z!&PbCb?FNk4vX1LkL~Te-17U8Qw}4;IluEYm#=@7V9?Q@KTF<J_u209R;NOa+WG$9
zl7BNSc(rPGhM8IQy7|8s#A|6XJwJXcN{Hdp&-YB#e-AMTltu(!Z8xb6zG!2@bVkGY
zZS+^Y9XkS|++PGH>x(VBJb#6Sp#T2kA7;%wZ(%aa_44P-f4=DJKaY0a#vrYm`}*}E
zHiZ=@oH<@@OP+G+S!|m-tCPo*+9iLM-!c3Y6R*E3%-eZQ>!N9o8asZsOqljh;@)5N
z79Tyou)1)GFZp@X_Pmft(v{)+#XjX2e`J2})JLlSO0UQ?d<fc674UUUZMAfM^Rirh
ze?Pt(`N4uh{CUz+Id}5+Ynbsro&KnHw)f)NQ|*rw%kS*pUG4I|ODjh@vVB?Ryf5rl
z@3vnMpJG4r^8GoCi{;&3+rJ8X8<o4%wrZPTTYpZrg_6JfuPU$iTphIxPef<dEoN|A
zJTYm}`_4MG$&z8eG@UAnVy$=Fxh^9ORN&FI!?dKeB2Vw?@#Fk|@4vr&aOG~T=;X@n
zZz7mwq}0^P8jDq5GJaoh{O`Iwhgr7o+IwqeKjYN5UKPeUXBl?4ef*ev?9=_-|D%e%
zBc5>n@y@TSe6Tk7Y?!mPVm5!Clce<NZQ+Uwri=YrtDAd4ng5~K>8an!zU}z7fvth@
zyY%-kZ3Y9QO$WEH{gS-!Di=de-aC$(bC>_eT;JD~6~86M>iAB{waZ@@#j!DXdX;y*
zWU88ZwvJ69N&Y*#x4mbk;n6dt-KxhKQa;Ue+H|0EqMD}WvWE1X8M9xj-Q1aH_WRVI
zsr~}-o4-`<UtbgQWqwuu?&9Xl0*yDX2`|)d620_&?rXVM9`+iRPfnLktg}CQ(|O5%
z`{G!4tL87iH@r6YFM40(5zpW*zi40RU6Ux0qRaWFhac!vE!#K0V)6usPgBhnzGr4|
z`10!1T%CWlXTR!8&J*Zcd|c-0oaxJ!E$Z99f5WR4Syv`ruq(ZP{JRB8W|(hT`)94y
kFFQ9mlpFx#9C{+pc`19x)s39Hfw`W+)78&qol`;+07_!{jsO4v
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..25e542a6551acf16d58489d2d7fde3a5d423b477
GIT binary patch
literal 1229
zc${^Vdr%T~0LOm>wZyqpG<$h=(?#XV>nULkBNeSCkJ>eSMa%4^DB_ESLSA5HnQTK*
zS!$=VBJq_{ouXl)9)x8R^N~OoK_zM-f{8fy=Wg5G=llKM_rCvsuMi?}F7P#Q0DwzG
zcnE1RS&Ir@zHHHV@NS=93<#Zs!ve8t-Mhu&loC#+1K^DKTM$qxTm=9uH6mpH(X3&U
z5R-_A@Q}CfiEU8tsu1L+RV_jHa|<@-srpyPUOjLN^mc{j)jtmJ$v}NGCQNfGMqKuH
zcM3%k8$<n=o<}dcKMMAIL?9Gy<<(D%QB6^&7veKA)&9xShOl9aN?FEe&rVLbIVgg;
z{<xAt4!#4kqKq*$hm~kJT&+EV?cMhkdT<j$Qb6jV+g^^2!YWdGH8VUq`mMJsZ!{k9
zo$kNManrJTqpjVo(EH4&f6tBwkLwQOadDVc%$fR{fib(9X>1npMSyLH?z=9_6vBa4
zetnBIXhghf;Klp*!`qtduy-{5Hc+9zk5$BoW8}^Tj+?D5F5U0uYt`>)Kslwa;~77e
zIVdP{0)D$?TDMSitl5_ndpEA%7?XCfI6wpm%*P9!({`0f)_+}MAa(}wV?vt^!zW}O
zK&gD{$6fer5#r<IzI6R)TiLuzVeyC;6i%WB&G$5JpEvJpSr{tN&uFA=D}f_ilAIPp
z4p`PrQ+fFmI(P^9=0Vj-LvO)Kd*-A#kKLE1vR)TGn;Hxyj69or5mu)@)Rb@p#J~US
zkujL*>(8<g@<APPe5fhigh|@?gCc3I;DfNPVJwwynLL+vKqq_ROmE!18f{?NjnDuZ
zXI2q%dZfiy=S5TbaLcoWVSD}0?U_|XjAKT9?zT!Yk3d_gd6q9cPrc$~%+a(#F34JO
z9+lny)cp+}@~r#u{sV|shRu{QmnBQy$oG>4!fwyu0*fjc$zXs`Y5D_lL4UAQ39s*=
z=Ug=vg5dKHtG6UxU<9SOxc)iukgg~-Gj?CF-|Cy)oODe)^V*d4c@i3wA0&tppvNKH
z;eGT3;^~sot_RG9T;;2ri9Y;>?~nh&*O<nCN<I5&N*V>U)9(txI!n$etFsrRvENDp
zg30Vpl)?scg<})Qs-Ip@65xvZqFGYwkSGztMj$7a?tXI~`RH1e60kX(YTlC>oM{G0
zQhAocQ2rg{rL7W{<atttCEk0DF^BF`&36YKjitm1CbrXr7Z4(A%xl4}MvV>U(muZL
zPCli!a<wk{Lv|Zv%sGX~&WC3W#GO6aEd9Ca-ueWR*X?FG(VRtw<}gsQV}k`#>1fSE
z#SJ3nB~PU99x@zb)yf!e&XCiuZAW{DQ)Ux#_i|e79&XY`u2{j<cDFEPfnREdQkJ)e
zQ(3;`OE;+P%ZtiWeC?NtF!HITFAt7zmu$X-ky9~UIjpxIXx5souN<fjD|QDj3e$qM
zjQ`4amA3cIhnzYy%k8(XFxOMM94C;KdgMmDjar&*-mvqDWzzcbc<Z|Ak(ws_Nwt$S
zMJG$t9{R0KA6+}tVf5CO?W|go$)0j5|0fuzjR{3+IwBNErtJUl!Pyod#bxSyk<5!L
Q7B2}zghqylv6S4u01TOF5C8xG
--- a/image/test/reftest/bmp/reftest.list
+++ b/image/test/reftest/bmp/reftest.list
@@ -1,14 +1,15 @@
 # BMP tests
 
 include bmp-1bpp/reftest.list
 include bmp-4bpp/reftest.list
 include bmp-8bpp/reftest.list
 include bmp-24bpp/reftest.list
+include bmp-32bpp/reftest.list
 include bmp-corrupted/reftest.list
 include bmpsuite/reftest.list
 
 # Two bmp files where the offset to the start of the image data in the file
 # is past the end of the file. In 1240629-1.bmp the offset us uint32_max,
 # so we are testing that we don't try to allocate a buffer that size (and
 # fail on 32 bit platforms) and declare the image in error state. If in the
 # future we decide that such bmps (offset past the end of the file) are