Do not let CPDF_Array::SetNewAt() and friends take a CPDF_Stream

Use std::enable_if() to disallow generating the templated versions of
SetNewAt(), AppendNew(), and InsertNewAt() that takes a CPDF_Stream.
Then update affected tests to pass in CPDF_Stream properly using
CPDF_Reference.

Bug: pdfium:2119
Change-Id: I0bfb36f1d693f8c2a5e362fa80560e443a97db8b
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/116370
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Thomas Sepez <tsepez@google.com>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/parser/cpdf_array.h b/core/fpdfapi/parser/cpdf_array.h
index a103133..b9641bc 100644
--- a/core/fpdfapi/parser/cpdf_array.h
+++ b/core/fpdfapi/parser/cpdf_array.h
@@ -83,6 +83,9 @@
   template <typename T, typename... Args>
   typename std::enable_if<!CanInternStrings<T>::value, RetainPtr<T>>::type
   AppendNew(Args&&... args) {
+    static_assert(!std::is_same<T, CPDF_Stream>::value,
+                  "Cannot append a CPDF_Stream directly. Add it indirectly as "
+                  "a `CPDF_Reference` instead.");
     return pdfium::WrapRetain(static_cast<T*>(
         AppendInternal(pdfium::MakeRetain<T>(std::forward<Args>(args)...))));
   }
@@ -95,6 +98,9 @@
   template <typename T, typename... Args>
   typename std::enable_if<!CanInternStrings<T>::value, RetainPtr<T>>::type
   SetNewAt(size_t index, Args&&... args) {
+    static_assert(!std::is_same<T, CPDF_Stream>::value,
+                  "Cannot set a CPDF_Stream directly. Add it indirectly as a "
+                  "`CPDF_Reference` instead.");
     return pdfium::WrapRetain(static_cast<T*>(SetAtInternal(
         index, pdfium::MakeRetain<T>(std::forward<Args>(args)...))));
   }
@@ -107,6 +113,9 @@
   template <typename T, typename... Args>
   typename std::enable_if<!CanInternStrings<T>::value, RetainPtr<T>>::type
   InsertNewAt(size_t index, Args&&... args) {
+    static_assert(!std::is_same<T, CPDF_Stream>::value,
+                  "Cannot insert a CPDF_Stream directly. Add it indirectly as "
+                  "a `CPDF_Reference` instead.");
     return pdfium::WrapRetain(static_cast<T*>(InsertAtInternal(
         index, pdfium::MakeRetain<T>(std::forward<Args>(args)...))));
   }
diff --git a/core/fpdfapi/parser/cpdf_object_unittest.cpp b/core/fpdfapi/parser/cpdf_object_unittest.cpp
index ed366a2..2d1ea04 100644
--- a/core/fpdfapi/parser/cpdf_object_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_object_unittest.cpp
@@ -636,6 +636,8 @@
   }
   {
     // Stream array.
+    CPDF_IndirectObjectHolder object_holder;
+
     RetainPtr<CPDF_Dictionary> vals[3];
     RetainPtr<CPDF_Stream> stream_vals[3];
     auto arr = pdfium::MakeRetain<CPDF_Array>();
@@ -649,9 +651,11 @@
         vals[i]->SetNewFor<CPDF_Number>(key.c_str(), value);
       }
       static constexpr uint8_t kContents[] = "content: this is a stream";
-      stream_vals[i] = arr->AppendNew<CPDF_Stream>(
+      stream_vals[i] = object_holder.NewIndirect<CPDF_Stream>(
           DataVector<uint8_t>(std::begin(kContents), std::end(kContents)),
           vals[i]);
+      arr->AppendNew<CPDF_Reference>(&object_holder,
+                                     stream_vals[i]->GetObjNum());
     }
     for (size_t i = 0; i < 3; ++i) {
       TestArrayAccessors(arr.Get(), i,           // Array and index.
@@ -666,6 +670,8 @@
   }
   {
     // Mixed array.
+
+    CPDF_IndirectObjectHolder object_holder;
     auto arr = pdfium::MakeRetain<CPDF_Array>();
     arr->InsertNewAt<CPDF_Boolean>(0, true);
     arr->InsertNewAt<CPDF_Boolean>(1, false);
@@ -693,9 +699,10 @@
     static constexpr uint8_t kData[] = "A stream for test";
     // The data buffer will be owned by stream object, so it needs to be
     // dynamically allocated.
-    CPDF_Stream* stream_val = arr->InsertNewAt<CPDF_Stream>(
-        13, DataVector<uint8_t>(std::begin(kData), std::end(kData)),
-        stream_dict);
+    auto stream_val = object_holder.NewIndirect<CPDF_Stream>(
+        DataVector<uint8_t>(std::begin(kData), std::end(kData)), stream_dict);
+    arr->InsertNewAt<CPDF_Reference>(13, &object_holder,
+                                     stream_val->GetObjNum());
     const char* const expected_str[] = {
         "true",          "false", "0",    "-1234", "2345", "0.05", "",
         "It is a test!", "NAME",  "test", "",      "",     "",     ""};