Support indirect objects for /Filter arrays

Other PDF viewers support using indirect references for /Filter arrays.
While not in the PDF spec, support indirect references as well.

Fixed: pdfium:1986
Change-Id: Ib92a9213bb8ec70523b041a120158aacdf7f4d43
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/104430
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Andy Phan <andyphan@chromium.org>
diff --git a/core/fpdfapi/parser/fpdf_parser_decode.cpp b/core/fpdfapi/parser/fpdf_parser_decode.cpp
index baf65f5..3e71a58 100644
--- a/core/fpdfapi/parser/fpdf_parser_decode.cpp
+++ b/core/fpdfapi/parser/fpdf_parser_decode.cpp
@@ -94,8 +94,10 @@
     return true;
 
   for (size_t i = 0; i < count; ++i) {
-    if (!pDecoders->GetObjectAt(i)->IsName())
+    RetainPtr<const CPDF_Object> object = pDecoders->GetDirectObjectAt(i);
+    if (!object || !object->IsName()) {
       return false;
+    }
   }
 
   if (count == 1)
diff --git a/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp b/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp
index f88bf38..2c2074b 100644
--- a/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp
+++ b/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp
@@ -8,7 +8,9 @@
 
 #include "core/fpdfapi/parser/cpdf_array.h"
 #include "core/fpdfapi/parser/cpdf_dictionary.h"
+#include "core/fpdfapi/parser/cpdf_indirect_object_holder.h"
 #include "core/fpdfapi/parser/cpdf_name.h"
+#include "core/fpdfapi/parser/cpdf_reference.h"
 #include "core/fpdfapi/parser/cpdf_string.h"
 #include "core/fxcrt/fx_memory_wrappers.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -115,6 +117,62 @@
   }
 }
 
+TEST(ParserDecodeTest, ValidateDecoderPipelineWithIndirectObjects) {
+  {
+    // Valid 2 decoder pipeline with indirect objects.
+    CPDF_IndirectObjectHolder objects_holder;
+    auto decoder = pdfium::MakeRetain<CPDF_Name>(nullptr, "FlateDecode");
+    uint32_t decoder_number =
+        objects_holder.AddIndirectObject(std::move(decoder));
+
+    auto decoders = pdfium::MakeRetain<CPDF_Array>();
+    decoders->AppendNew<CPDF_Reference>(&objects_holder, decoder_number);
+    decoders->AppendNew<CPDF_Name>("LZW");
+    EXPECT_TRUE(ValidateDecoderPipeline(decoders.Get()));
+  }
+  {
+    // Valid 5 decoder pipeline with indirect objects, with an image decoder at
+    // the end.
+    CPDF_IndirectObjectHolder objects_holder;
+    auto decoder = pdfium::MakeRetain<CPDF_Name>(nullptr, "LZW");
+    uint32_t decoder_number =
+        objects_holder.AddIndirectObject(std::move(decoder));
+
+    auto decoders = pdfium::MakeRetain<CPDF_Array>();
+    decoders->AppendNew<CPDF_Name>("RunLengthDecode");
+    decoders->AppendNew<CPDF_Name>("ASCII85Decode");
+    decoders->AppendNew<CPDF_Name>("FlateDecode");
+    decoders->AppendNew<CPDF_Reference>(&objects_holder, decoder_number);
+    decoders->AppendNew<CPDF_Name>("DCTDecode");
+    EXPECT_TRUE(ValidateDecoderPipeline(decoders.Get()));
+  }
+  {
+    // Invalid 2 decoder pipeline due to wrong type indirect object.
+    CPDF_IndirectObjectHolder objects_holder;
+    auto decoder =
+        pdfium::MakeRetain<CPDF_String>(nullptr, "FlateDecode", false);
+    uint32_t decoder_number =
+        objects_holder.AddIndirectObject(std::move(decoder));
+
+    auto decoders = pdfium::MakeRetain<CPDF_Array>();
+    decoders->AppendNew<CPDF_Reference>(&objects_holder, decoder_number);
+    decoders->AppendNew<CPDF_Name>("LZW");
+    EXPECT_FALSE(ValidateDecoderPipeline(decoders.Get()));
+  }
+  {
+    // Invalid 2 decoder pipeline due to invalid indirect object.
+    CPDF_IndirectObjectHolder objects_holder;
+    auto decoder = pdfium::MakeRetain<CPDF_Name>(nullptr, "DCTDecode");
+    uint32_t decoder_number =
+        objects_holder.AddIndirectObject(std::move(decoder));
+
+    auto decoders = pdfium::MakeRetain<CPDF_Array>();
+    decoders->AppendNew<CPDF_Reference>(&objects_holder, decoder_number);
+    decoders->AppendNew<CPDF_Name>("LZW");
+    EXPECT_FALSE(ValidateDecoderPipeline(decoders.Get()));
+  }
+}
+
 // TODO(thestig): Test decoder params.
 TEST(ParserDecodeTest, GetDecoderArray) {
   {
diff --git a/testing/SUPPRESSIONS b/testing/SUPPRESSIONS
index b224dad..b3409bf 100644
--- a/testing/SUPPRESSIONS
+++ b/testing/SUPPRESSIONS
@@ -361,9 +361,6 @@
 # TODO(pdfium:1973): Remove after associated bug is fixed
 bug_1973.in * * * *
 
-# TODO(pdfium:1986): Remove after associated bug is fixed
-bug_1986.in * * * *
-
 # TODO(chromium:237527): Remove after associated bug is fixed
 bug_237527_1.in * * * *