Add basic unit tests for BMP decoding

Adds unit tests for decoding simple indexed 8-bit BMP images.

Bug: pdfium:1168
Change-Id: I854cd200f40c329bd98bb516d0b5c4fa6ed15e01
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/98632
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: K. Moon <kmoon@chromium.org>
diff --git a/core/fxcodec/progressive_decoder_unittest.cpp b/core/fxcodec/progressive_decoder_unittest.cpp
index 4d22dd1..ed5c4de 100644
--- a/core/fxcodec/progressive_decoder_unittest.cpp
+++ b/core/fxcodec/progressive_decoder_unittest.cpp
@@ -7,7 +7,6 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include <memory>
 #include <tuple>
 
 #include "core/fxcodec/fx_codec.h"
@@ -20,6 +19,10 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/base/span.h"
 
+#ifdef PDF_ENABLE_XFA_BMP
+#include "core/fxcodec/bmp/bmp_decoder.h"
+#endif  // PDF_ENABLE_XFA_BMP
+
 #ifdef PDF_ENABLE_XFA_GIF
 #include "core/fxcodec/gif/gif_decoder.h"
 #endif  // PDF_ENABLE_XFA_GIF
@@ -41,6 +44,73 @@
 
 }  // namespace
 
+#ifdef PDF_ENABLE_XFA_BMP
+TEST(ProgressiveDecoder, Indexed8Bmp) {
+  static constexpr uint8_t kInput[] = {
+      0x42, 0x4d, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a,
+      0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x04, 0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x13, 0x0b,
+      0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc0,
+      0x80, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+  ProgressiveDecoder decoder;
+
+  auto source = pdfium::MakeRetain<CFX_ReadOnlySpanStream>(kInput);
+  CFX_DIBAttribute attr;
+  FXCODEC_STATUS status =
+      decoder.LoadImageInfo(source, FXCODEC_IMAGE_BMP, &attr, true);
+  ASSERT_EQ(FXCODEC_STATUS::kFrameReady, status);
+
+  ASSERT_EQ(1, decoder.GetWidth());
+  ASSERT_EQ(1, decoder.GetHeight());
+
+  auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
+  bitmap->Create(decoder.GetWidth(), decoder.GetHeight(), FXDIB_Format::kRgb);
+
+  size_t frames;
+  std::tie(status, frames) = decoder.GetFrames();
+  ASSERT_EQ(FXCODEC_STATUS::kDecodeReady, status);
+  ASSERT_EQ(1u, frames);
+
+  status = DecodeToBitmap(decoder, bitmap);
+  EXPECT_EQ(FXCODEC_STATUS::kDecodeFinished, status);
+  EXPECT_THAT(bitmap->GetScanline(0), ElementsAre(0xc0, 0x80, 0x40, 0x00));
+}
+
+TEST(ProgressiveDecoder, Indexed8BmpWithInvalidIndex) {
+  static constexpr uint8_t kInput[] = {
+      0x42, 0x4d, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a,
+      0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x04, 0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x13, 0x0b,
+      0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc0,
+      0x80, 0x40, 0x00, 0x01, 0x00, 0x00, 0x00};
+
+  ProgressiveDecoder decoder;
+
+  auto source = pdfium::MakeRetain<CFX_ReadOnlySpanStream>(kInput);
+  CFX_DIBAttribute attr;
+  FXCODEC_STATUS status =
+      decoder.LoadImageInfo(source, FXCODEC_IMAGE_BMP, &attr, true);
+  ASSERT_EQ(FXCODEC_STATUS::kFrameReady, status);
+
+  ASSERT_EQ(1, decoder.GetWidth());
+  ASSERT_EQ(1, decoder.GetHeight());
+
+  auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
+  bitmap->Create(decoder.GetWidth(), decoder.GetHeight(), FXDIB_Format::kRgb);
+
+  size_t frames;
+  std::tie(status, frames) = decoder.GetFrames();
+  ASSERT_EQ(FXCODEC_STATUS::kDecodeReady, status);
+  ASSERT_EQ(1u, frames);
+
+  status = DecodeToBitmap(decoder, bitmap);
+  EXPECT_EQ(FXCODEC_STATUS::kError, status);
+}
+#endif  // PDF_ENABLE_XFA_BMP
+
 #ifdef PDF_ENABLE_XFA_GIF
 TEST(ProgressiveDecoder, Gif87a) {
   static constexpr uint8_t kInput[] = {
@@ -48,27 +118,26 @@
       0x00, 0x40, 0x80, 0xc0, 0x80, 0x80, 0x80, 0x2c, 0x00, 0x00, 0x00, 0x00,
       0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x44, 0x01, 0x00, 0x3b};
 
-  auto decoder = std::make_unique<ProgressiveDecoder>();
+  ProgressiveDecoder decoder;
 
   auto source = pdfium::MakeRetain<CFX_ReadOnlySpanStream>(kInput);
   CFX_DIBAttribute attr;
   FXCODEC_STATUS status =
-      decoder->LoadImageInfo(source, FXCODEC_IMAGE_GIF, &attr, true);
+      decoder.LoadImageInfo(source, FXCODEC_IMAGE_GIF, &attr, true);
   ASSERT_EQ(FXCODEC_STATUS::kFrameReady, status);
 
-  ASSERT_EQ(1, decoder->GetWidth());
-  ASSERT_EQ(1, decoder->GetHeight());
+  ASSERT_EQ(1, decoder.GetWidth());
+  ASSERT_EQ(1, decoder.GetHeight());
 
   auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
-  bitmap->Create(decoder->GetWidth(), decoder->GetHeight(),
-                 FXDIB_Format::kArgb);
+  bitmap->Create(decoder.GetWidth(), decoder.GetHeight(), FXDIB_Format::kArgb);
 
   size_t frames;
-  std::tie(status, frames) = decoder->GetFrames();
+  std::tie(status, frames) = decoder.GetFrames();
   ASSERT_EQ(FXCODEC_STATUS::kDecodeReady, status);
   ASSERT_EQ(1u, frames);
 
-  status = DecodeToBitmap(*decoder, bitmap);
+  status = DecodeToBitmap(decoder, bitmap);
   EXPECT_EQ(FXCODEC_STATUS::kDecodeFinished, status);
   EXPECT_THAT(bitmap->GetScanline(0), ElementsAre(0xc0, 0x80, 0x40, 0xff));
 }
@@ -80,27 +149,26 @@
       0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x01,
       0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x44, 0x01, 0x00, 0x3b};
 
-  auto decoder = std::make_unique<ProgressiveDecoder>();
+  ProgressiveDecoder decoder;
 
   auto source = pdfium::MakeRetain<CFX_ReadOnlySpanStream>(kInput);
   CFX_DIBAttribute attr;
   FXCODEC_STATUS status =
-      decoder->LoadImageInfo(source, FXCODEC_IMAGE_GIF, &attr, true);
+      decoder.LoadImageInfo(source, FXCODEC_IMAGE_GIF, &attr, true);
   ASSERT_EQ(FXCODEC_STATUS::kFrameReady, status);
 
-  ASSERT_EQ(1, decoder->GetWidth());
-  ASSERT_EQ(1, decoder->GetHeight());
+  ASSERT_EQ(1, decoder.GetWidth());
+  ASSERT_EQ(1, decoder.GetHeight());
 
   auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
-  bitmap->Create(decoder->GetWidth(), decoder->GetHeight(),
-                 FXDIB_Format::kArgb);
+  bitmap->Create(decoder.GetWidth(), decoder.GetHeight(), FXDIB_Format::kArgb);
 
   size_t frames;
-  std::tie(status, frames) = decoder->GetFrames();
+  std::tie(status, frames) = decoder.GetFrames();
   ASSERT_EQ(FXCODEC_STATUS::kDecodeReady, status);
   ASSERT_EQ(1u, frames);
 
-  status = DecodeToBitmap(*decoder, bitmap);
+  status = DecodeToBitmap(decoder, bitmap);
   EXPECT_EQ(FXCODEC_STATUS::kDecodeFinished, status);
   EXPECT_THAT(bitmap->GetScanline(0), ElementsAre(0xc0, 0x80, 0x40, 0xff));
 }
@@ -115,27 +183,26 @@
       0x85, 0x86, 0x86, 0x86, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
       0x01, 0x00, 0x00, 0x02, 0x2,  0x44, 0x01, 0x00, 0x3b};
 
-  auto decoder = std::make_unique<ProgressiveDecoder>();
+  ProgressiveDecoder decoder;
 
   auto source = pdfium::MakeRetain<CFX_ReadOnlySpanStream>(kInput);
   CFX_DIBAttribute attr;
   FXCODEC_STATUS status =
-      decoder->LoadImageInfo(source, FXCODEC_IMAGE_GIF, &attr, true);
+      decoder.LoadImageInfo(source, FXCODEC_IMAGE_GIF, &attr, true);
   ASSERT_EQ(FXCODEC_STATUS::kFrameReady, status);
 
-  ASSERT_EQ(1, decoder->GetWidth());
-  ASSERT_EQ(1, decoder->GetHeight());
+  ASSERT_EQ(1, decoder.GetWidth());
+  ASSERT_EQ(1, decoder.GetHeight());
 
   auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
-  bitmap->Create(decoder->GetWidth(), decoder->GetHeight(),
-                 FXDIB_Format::kArgb);
+  bitmap->Create(decoder.GetWidth(), decoder.GetHeight(), FXDIB_Format::kArgb);
 
   size_t frames;
-  std::tie(status, frames) = decoder->GetFrames();
+  std::tie(status, frames) = decoder.GetFrames();
   ASSERT_EQ(FXCODEC_STATUS::kDecodeReady, status);
   ASSERT_EQ(1u, frames);
 
-  status = DecodeToBitmap(*decoder, bitmap);
+  status = DecodeToBitmap(decoder, bitmap);
   EXPECT_EQ(FXCODEC_STATUS::kError, status);
 }
 
@@ -147,27 +214,26 @@
       0x00, 0x40, 0x80, 0xc0, 0x80, 0x80, 0x80, 0x2c, 0x00, 0x00, 0x00, 0x00,
       0x04, 0x00, 0x02, 0x00, 0x00, 0x02, 0x03, 0x84, 0x6f, 0x05, 0x00, 0x3b};
 
-  auto decoder = std::make_unique<ProgressiveDecoder>();
+  ProgressiveDecoder decoder;
 
   auto source = pdfium::MakeRetain<CFX_ReadOnlySpanStream>(kInput);
   CFX_DIBAttribute attr;
   FXCODEC_STATUS status =
-      decoder->LoadImageInfo(source, FXCODEC_IMAGE_GIF, &attr, true);
+      decoder.LoadImageInfo(source, FXCODEC_IMAGE_GIF, &attr, true);
   ASSERT_EQ(FXCODEC_STATUS::kFrameReady, status);
 
-  ASSERT_EQ(4, decoder->GetWidth());
-  ASSERT_EQ(2, decoder->GetHeight());
+  ASSERT_EQ(4, decoder.GetWidth());
+  ASSERT_EQ(2, decoder.GetHeight());
 
   auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
-  bitmap->Create(decoder->GetWidth(), decoder->GetHeight(),
-                 FXDIB_Format::kArgb);
+  bitmap->Create(decoder.GetWidth(), decoder.GetHeight(), FXDIB_Format::kArgb);
 
   size_t frames;
-  std::tie(status, frames) = decoder->GetFrames();
+  std::tie(status, frames) = decoder.GetFrames();
   ASSERT_EQ(FXCODEC_STATUS::kDecodeReady, status);
   ASSERT_EQ(1u, frames);
 
-  status = DecodeToBitmap(*decoder, bitmap);
+  status = DecodeToBitmap(decoder, bitmap);
   EXPECT_EQ(FXCODEC_STATUS::kDecodeFinished, status);
   EXPECT_THAT(bitmap->GetScanline(0),
               ElementsAre(0xc0, 0x80, 0x40, 0xff, 0xc0, 0x80, 0x40, 0xff, 0xc0,
@@ -186,27 +252,26 @@
       0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x02,
       0x02, 0x84, 0x6f, 0x01, 0x05, 0x00, 0x3b};
 
-  auto decoder = std::make_unique<ProgressiveDecoder>();
+  ProgressiveDecoder decoder;
 
   auto source = pdfium::MakeRetain<CFX_ReadOnlySpanStream>(kInput);
   CFX_DIBAttribute attr;
   FXCODEC_STATUS status =
-      decoder->LoadImageInfo(source, FXCODEC_IMAGE_GIF, &attr, true);
+      decoder.LoadImageInfo(source, FXCODEC_IMAGE_GIF, &attr, true);
   ASSERT_EQ(FXCODEC_STATUS::kFrameReady, status);
 
-  ASSERT_EQ(4, decoder->GetWidth());
-  ASSERT_EQ(2, decoder->GetHeight());
+  ASSERT_EQ(4, decoder.GetWidth());
+  ASSERT_EQ(2, decoder.GetHeight());
 
   auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
-  bitmap->Create(decoder->GetWidth(), decoder->GetHeight(),
-                 FXDIB_Format::kArgb);
+  bitmap->Create(decoder.GetWidth(), decoder.GetHeight(), FXDIB_Format::kArgb);
 
   size_t frames;
-  std::tie(status, frames) = decoder->GetFrames();
+  std::tie(status, frames) = decoder.GetFrames();
   ASSERT_EQ(FXCODEC_STATUS::kDecodeReady, status);
   ASSERT_EQ(1u, frames);
 
-  status = DecodeToBitmap(*decoder, bitmap);
+  status = DecodeToBitmap(decoder, bitmap);
   EXPECT_EQ(FXCODEC_STATUS::kDecodeFinished, status);
   EXPECT_THAT(bitmap->GetScanline(0),
               ElementsAre(0xc0, 0x80, 0x40, 0xff, 0xc0, 0x80, 0x40, 0xff, 0xc0,
@@ -568,27 +633,26 @@
       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
       0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
 
-  auto decoder = std::make_unique<ProgressiveDecoder>();
+  ProgressiveDecoder decoder;
 
   auto source = pdfium::MakeRetain<CFX_ReadOnlySpanStream>(kInput);
   CFX_DIBAttribute attr;
   FXCODEC_STATUS status =
-      decoder->LoadImageInfo(source, FXCODEC_IMAGE_GIF, &attr, true);
+      decoder.LoadImageInfo(source, FXCODEC_IMAGE_GIF, &attr, true);
   ASSERT_EQ(FXCODEC_STATUS::kFrameReady, status);
 
-  ASSERT_EQ(98, decoder->GetWidth());
-  ASSERT_EQ(6945, decoder->GetHeight());
+  ASSERT_EQ(98, decoder.GetWidth());
+  ASSERT_EQ(6945, decoder.GetHeight());
 
   auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
-  bitmap->Create(decoder->GetWidth(), decoder->GetHeight(),
-                 FXDIB_Format::kArgb);
+  bitmap->Create(decoder.GetWidth(), decoder.GetHeight(), FXDIB_Format::kArgb);
 
   size_t frames;
-  std::tie(status, frames) = decoder->GetFrames();
+  std::tie(status, frames) = decoder.GetFrames();
   ASSERT_EQ(FXCODEC_STATUS::kDecodeReady, status);
   ASSERT_EQ(1u, frames);
 
-  status = DecodeToBitmap(*decoder, bitmap);
+  status = DecodeToBitmap(decoder, bitmap);
   EXPECT_EQ(FXCODEC_STATUS::kError, status);
 }
 #endif  // PDF_ENABLE_XFA_GIF