Remove |offsets| parameter from CJPX_Decoder::Decode().

The decoder does not need this level of flexibility. Replace it with
a |swap_rgb| parameter and calculate the offsets internally in a
foolproof manner.

Also rename a local variable in one caller to better describe what it
represents and to avoid Hungarian notation.

Change-Id: I6948517dd4af03d942be08e3e597c1c667e71396
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/65791
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfapi/page/cpdf_dib.cpp b/core/fpdfapi/page/cpdf_dib.cpp
index 4dbb815..6976a0d 100644
--- a/core/fpdfapi/page/cpdf_dib.cpp
+++ b/core/fpdfapi/page/cpdf_dib.cpp
@@ -8,7 +8,6 @@
 
 #include <algorithm>
 #include <memory>
-#include <numeric>
 #include <utility>
 #include <vector>
 
@@ -641,6 +640,7 @@
       break;
 
     case JpxDecodeAction::kUseRgb:
+      DCHECK(image_info.components >= 3);
       swap_rgb = true;
       m_pColorSpace = nullptr;
       break;
@@ -671,18 +671,13 @@
     format = FXDIB_Rgb;
   }
 
-  auto pCachedBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
-  if (!pCachedBitmap->Create(image_info.width, image_info.height, format))
+  auto result_bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
+  if (!result_bitmap->Create(image_info.width, image_info.height, format))
     return nullptr;
 
-  pCachedBitmap->Clear(0xFFFFFFFF);
-  // Fill |output_offsets| with 0, 1, ... N.
-  std::vector<uint8_t> output_offsets(image_info.components);
-  std::iota(output_offsets.begin(), output_offsets.end(), 0);
-  if (swap_rgb)
-    std::swap(output_offsets[0], output_offsets[2]);
-  if (!decoder->Decode(pCachedBitmap->GetBuffer(), pCachedBitmap->GetPitch(),
-                       output_offsets)) {
+  result_bitmap->Clear(0xFFFFFFFF);
+  if (!decoder->Decode(result_bitmap->GetBuffer(), result_bitmap->GetPitch(),
+                       swap_rgb)) {
     return nullptr;
   }
 
@@ -690,7 +685,7 @@
       m_bpc < 8) {
     int scale = 8 - m_bpc;
     for (uint32_t row = 0; row < image_info.height; ++row) {
-      uint8_t* scanline = pCachedBitmap->GetWritableScanline(row);
+      uint8_t* scanline = result_bitmap->GetWritableScanline(row);
       for (uint32_t col = 0; col < image_info.width; ++col) {
         *scanline = (*scanline) >> scale;
         ++scanline;
@@ -698,7 +693,7 @@
     }
   }
   m_bpc = 8;
-  return pCachedBitmap;
+  return result_bitmap;
 }
 
 CPDF_DIB::LoadState CPDF_DIB::StartLoadMask() {
diff --git a/core/fxcodec/jpx/cjpx_decoder.cpp b/core/fxcodec/jpx/cjpx_decoder.cpp
index 986d2f1..95f76ff 100644
--- a/core/fxcodec/jpx/cjpx_decoder.cpp
+++ b/core/fxcodec/jpx/cjpx_decoder.cpp
@@ -9,7 +9,6 @@
 #include <algorithm>
 #include <limits>
 #include <utility>
-#include <vector>
 
 #include "core/fxcodec/jpx/jpx_decode_utils.h"
 #include "core/fxcrt/fx_safe_types.h"
@@ -493,21 +492,21 @@
   return {m_Image->x1, m_Image->y1, m_Image->numcomps};
 }
 
-bool CJPX_Decoder::Decode(uint8_t* dest_buf,
-                          uint32_t pitch,
-                          pdfium::span<const uint8_t> offsets) {
+bool CJPX_Decoder::Decode(uint8_t* dest_buf, uint32_t pitch, bool swap_rgb) {
   if (m_Image->comps[0].w != m_Image->x1 || m_Image->comps[0].h != m_Image->y1)
     return false;
 
-  if (pitch<(m_Image->comps[0].w * 8 * m_Image->numcomps + 31)>> 5 << 2) {
+  if (pitch<(m_Image->comps[0].w * 8 * m_Image->numcomps + 31)>> 5 << 2)
     return false;
-  }
+
+  if (swap_rgb && m_Image->numcomps < 3)
+    return false;
 
   memset(dest_buf, 0xff, m_Image->y1 * pitch);
   std::vector<uint8_t*> channel_bufs(m_Image->numcomps);
   std::vector<int> adjust_comps(m_Image->numcomps);
   for (uint32_t i = 0; i < m_Image->numcomps; i++) {
-    channel_bufs[i] = dest_buf + offsets[i];
+    channel_bufs[i] = dest_buf + i;
     adjust_comps[i] = m_Image->comps[i].prec - 8;
     if (i > 0) {
       if (m_Image->comps[i].dx != m_Image->comps[i - 1].dx ||
@@ -517,6 +516,9 @@
       }
     }
   }
+  if (swap_rgb)
+    std::swap(channel_bufs[0], channel_bufs[2]);
+
   uint32_t width = m_Image->comps[0].w;
   uint32_t height = m_Image->comps[0].h;
   for (uint32_t channel = 0; channel < m_Image->numcomps; ++channel) {
diff --git a/core/fxcodec/jpx/cjpx_decoder.h b/core/fxcodec/jpx/cjpx_decoder.h
index 0fdccb9..4d9883c 100644
--- a/core/fxcodec/jpx/cjpx_decoder.h
+++ b/core/fxcodec/jpx/cjpx_decoder.h
@@ -8,6 +8,7 @@
 #define CORE_FXCODEC_JPX_CJPX_DECODER_H_
 
 #include <memory>
+#include <vector>
 
 #include "core/fxcrt/unowned_ptr.h"
 #include "third_party/base/span.h"
@@ -44,9 +45,9 @@
   bool Init(pdfium::span<const uint8_t> src_data);
   JpxImageInfo GetInfo() const;
   bool StartDecode();
-  bool Decode(uint8_t* dest_buf,
-              uint32_t pitch,
-              pdfium::span<const uint8_t> offsets);
+
+  // |swap_rgb| can only be set for images with 3 or more components.
+  bool Decode(uint8_t* dest_buf, uint32_t pitch, bool swap_rgb);
 
  private:
   const ColorSpaceOption m_ColorSpaceOption;
diff --git a/testing/fuzzers/pdf_jpx_fuzzer.cc b/testing/fuzzers/pdf_jpx_fuzzer.cc
index 89705dd..3986ae2 100644
--- a/testing/fuzzers/pdf_jpx_fuzzer.cc
+++ b/testing/fuzzers/pdf_jpx_fuzzer.cc
@@ -71,10 +71,8 @@
           static_cast<uint32_t>(bitmap->GetHeight()))
     return 0;
 
-  std::vector<uint8_t> output_offsets(image_info.components);
-  for (uint32_t i = 0; i < image_info.components; ++i)
-    output_offsets[i] = i;
+  decoder->Decode(bitmap->GetBuffer(), bitmap->GetPitch(),
+                  /*swap_rgb=*/false);
 
-  decoder->Decode(bitmap->GetBuffer(), bitmap->GetPitch(), output_offsets);
   return 0;
 }