Add CPDF_Array::GetMutableObjectAt()

Change-Id: I57256d1f30bd8b0a4dd926bf09825128a673c115
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/94690
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfapi/edit/cpdf_pagecontentmanager.cpp b/core/fpdfapi/edit/cpdf_pagecontentmanager.cpp
index 3a2d1f5..9f8832f 100644
--- a/core/fpdfapi/edit/cpdf_pagecontentmanager.cpp
+++ b/core/fpdfapi/edit/cpdf_pagecontentmanager.cpp
@@ -46,20 +46,20 @@
 
 CPDF_PageContentManager::~CPDF_PageContentManager() = default;
 
+// TODO(tsepez): return retained reference.
 CPDF_Stream* CPDF_PageContentManager::GetStreamByIndex(size_t stream_index) {
   if (contents_stream_)
     return stream_index == 0 ? contents_stream_.Get() : nullptr;
 
-  if (contents_array_) {
-    CPDF_Reference* stream_reference =
-        ToReference(contents_array_->GetObjectAt(stream_index));
-    if (!stream_reference)
-      return nullptr;
+  if (!contents_array_)
+    return nullptr;
 
-    return stream_reference->GetDirect()->AsStream();
-  }
+  RetainPtr<CPDF_Reference> stream_reference =
+      ToReference(contents_array_->GetMutableObjectAt(stream_index));
+  if (!stream_reference)
+    return nullptr;
 
-  return nullptr;
+  return stream_reference->GetDirect()->AsStream();
 }
 
 size_t CPDF_PageContentManager::AddStream(fxcrt::ostringstream* buf) {
diff --git a/core/fpdfapi/page/cpdf_streamcontentparser.cpp b/core/fpdfapi/page/cpdf_streamcontentparser.cpp
index 55ff2e9..9cc2ed6 100644
--- a/core/fpdfapi/page/cpdf_streamcontentparser.cpp
+++ b/core/fpdfapi/page/cpdf_streamcontentparser.cpp
@@ -213,7 +213,7 @@
 
 void ReplaceAbbrInArray(CPDF_Array* pArray) {
   for (size_t i = 0; i < pArray->size(); ++i) {
-    CPDF_Object* pElement = pArray->GetObjectAt(i);
+    RetainPtr<CPDF_Object> pElement = pArray->GetMutableObjectAt(i);
     if (pElement->IsName()) {
       ByteString name = pElement->GetString();
       ByteStringView fullname = FindFullName(
@@ -221,7 +221,7 @@
       if (!fullname.IsEmpty())
         pArray->SetNewAt<CPDF_Name>(i, ByteString(fullname));
     } else {
-      ReplaceAbbr(pElement);
+      ReplaceAbbr(pElement.Get());
     }
   }
 }
diff --git a/core/fpdfapi/parser/cpdf_array.cpp b/core/fpdfapi/parser/cpdf_array.cpp
index 8d5dd1b..869da53 100644
--- a/core/fpdfapi/parser/cpdf_array.cpp
+++ b/core/fpdfapi/parser/cpdf_array.cpp
@@ -101,10 +101,8 @@
   return Find(pThat).has_value();
 }
 
-CPDF_Object* CPDF_Array::GetObjectAt(size_t index) {
-  if (index >= m_Objects.size())
-    return nullptr;
-  return m_Objects[index].Get();
+RetainPtr<CPDF_Object> CPDF_Array::GetMutableObjectAt(size_t index) {
+  return pdfium::WrapRetain(const_cast<CPDF_Object*>(GetObjectAt(index)));
 }
 
 const CPDF_Object* CPDF_Array::GetObjectAt(size_t index) const {
diff --git a/core/fpdfapi/parser/cpdf_array.h b/core/fpdfapi/parser/cpdf_array.h
index 201a2a1..12ecfca 100644
--- a/core/fpdfapi/parser/cpdf_array.h
+++ b/core/fpdfapi/parser/cpdf_array.h
@@ -42,10 +42,10 @@
   bool IsEmpty() const { return m_Objects.empty(); }
   size_t size() const { return m_Objects.size(); }
 
-  // The GetObjectAt() methods tolerate out-of-bounds indices and return
+  // The Get*ObjectAt() methods tolerate out-of-bounds indices and return
   // nullptr in those cases. Otherwise, for in-bound indices, the result
   // is never nullptr.
-  CPDF_Object* GetObjectAt(size_t index);
+  RetainPtr<CPDF_Object> GetMutableObjectAt(size_t index);
   const CPDF_Object* GetObjectAt(size_t index) const;
 
   // The Get*DirectObjectAt() methods tolerate out-of-bounds indices and
diff --git a/core/fpdfapi/parser/cpdf_array_unittest.cpp b/core/fpdfapi/parser/cpdf_array_unittest.cpp
index 009575b..4833a08 100644
--- a/core/fpdfapi/parser/cpdf_array_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_array_unittest.cpp
@@ -151,9 +151,9 @@
     RetainPtr<CPDF_Array> arr2 = ToArray(arr->CloneDirectObject());
     ASSERT_EQ(arr->size(), arr2->size());
     for (size_t i = 0; i < kNumOfRows; ++i) {
-      CPDF_Array* arr_elem = arr->GetObjectAt(i)->AsArray();
-      CPDF_Array* arr1_elem = arr1->GetObjectAt(i)->AsArray();
-      CPDF_Array* arr2_elem = arr2->GetObjectAt(i)->AsArray();
+      const CPDF_Array* arr_elem = arr->GetObjectAt(i)->AsArray();
+      const CPDF_Array* arr1_elem = arr1->GetObjectAt(i)->AsArray();
+      const CPDF_Array* arr2_elem = arr2->GetObjectAt(i)->AsArray();
       EXPECT_NE(arr_elem, arr1_elem);
       EXPECT_NE(arr_elem, arr2_elem);
       for (size_t j = 0; j < kNumOfRowElems; ++j) {
diff --git a/core/fpdfapi/parser/cpdf_data_avail.cpp b/core/fpdfapi/parser/cpdf_data_avail.cpp
index 25d61e7..3cde64b 100644
--- a/core/fpdfapi/parser/cpdf_data_avail.cpp
+++ b/core/fpdfapi/parser/cpdf_data_avail.cpp
@@ -551,7 +551,7 @@
 
   pPageNode->m_type = PageNode::Type::kPages;
   for (size_t i = 0; i < pArray->size(); ++i) {
-    CPDF_Reference* pKid = ToReference(pArray->GetObjectAt(i));
+    const CPDF_Reference* pKid = ToReference(pArray->GetObjectAt(i));
     if (!pKid)
       continue;
 
@@ -616,7 +616,7 @@
     case CPDF_Object::kArray: {
       CPDF_Array* pKidsArray = pKids->AsArray();
       for (size_t i = 0; i < pKidsArray->size(); ++i) {
-        CPDF_Reference* pKid = ToReference(pKidsArray->GetObjectAt(i));
+        const CPDF_Reference* pKid = ToReference(pKidsArray->GetObjectAt(i));
         if (!pKid)
           continue;
 
diff --git a/core/fpdfapi/parser/cpdf_object_unittest.cpp b/core/fpdfapi/parser/cpdf_object_unittest.cpp
index b42a7dd..6298e4e 100644
--- a/core/fpdfapi/parser/cpdf_object_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_object_unittest.cpp
@@ -810,7 +810,7 @@
   auto array = pdfium::MakeRetain<CPDF_Array>();
   array->AppendNew<CPDF_Reference>(&objects_holder, 1234);
   ASSERT_EQ(1U, array->size());
-  CPDF_Object* obj = array->GetObjectAt(0);
+  const CPDF_Object* obj = array->GetObjectAt(0);
   ASSERT_TRUE(obj);
   EXPECT_TRUE(obj->IsReference());
 
@@ -820,7 +820,7 @@
 
   RetainPtr<CPDF_Array> cloned_array = ToArray(std::move(cloned_array_object));
   ASSERT_EQ(0U, cloned_array->size());
-  CPDF_Object* cloned_obj = cloned_array->GetObjectAt(0);
+  const CPDF_Object* cloned_obj = cloned_array->GetObjectAt(0);
   EXPECT_FALSE(cloned_obj);
 }
 
@@ -942,7 +942,7 @@
     // Cloned object should be the same as the original.
     ASSERT_TRUE(cloned_array);
     EXPECT_EQ(1u, cloned_array->size());
-    CPDF_Object* cloned_dict = cloned_array->GetObjectAt(0);
+    const CPDF_Object* cloned_dict = cloned_array->GetObjectAt(0);
     ASSERT_TRUE(cloned_dict);
     ASSERT_TRUE(cloned_dict->IsDictionary());
     // Recursively referenced object is not cloned.
@@ -972,7 +972,7 @@
     RetainPtr<CPDF_Array> arr_obj = pdfium::MakeRetain<CPDF_Array>();
     arr_obj->InsertNewAt<CPDF_Reference>(0, &objects_holder,
                                          dict_obj->GetObjNum());
-    CPDF_Object* elem0 = arr_obj->GetObjectAt(0);
+    const CPDF_Object* elem0 = arr_obj->GetObjectAt(0);
     dict_obj->SetFor("arr", std::move(arr_obj));
     EXPECT_EQ(1u, dict_obj->GetObjNum());
     ASSERT_TRUE(elem0);
diff --git a/core/fpdfapi/parser/cpdf_reference.h b/core/fpdfapi/parser/cpdf_reference.h
index d0f2be7..37f47a8 100644
--- a/core/fpdfapi/parser/cpdf_reference.h
+++ b/core/fpdfapi/parser/cpdf_reference.h
@@ -63,4 +63,8 @@
   return obj ? obj->AsReference() : nullptr;
 }
 
+inline RetainPtr<CPDF_Reference> ToReference(RetainPtr<CPDF_Object> obj) {
+  return RetainPtr<CPDF_Reference>(ToReference(obj.Get()));
+}
+
 #endif  // CORE_FPDFAPI_PARSER_CPDF_REFERENCE_H_
diff --git a/fpdfsdk/fpdf_ppo.cpp b/fpdfsdk/fpdf_ppo.cpp
index b42d1dc..2d544eb 100644
--- a/fpdfsdk/fpdf_ppo.cpp
+++ b/fpdfsdk/fpdf_ppo.cpp
@@ -316,7 +316,7 @@
     case CPDF_Object::kArray: {
       CPDF_Array* pArray = pObj->AsArray();
       for (size_t i = 0; i < pArray->size(); ++i) {
-        if (!UpdateReference(pArray->GetObjectAt(i)))
+        if (!UpdateReference(pArray->GetMutableObjectAt(i).Get()))
           return false;
       }
       return true;
diff --git a/fpdfsdk/fpdf_save.cpp b/fpdfsdk/fpdf_save.cpp
index bcaea81..c82faeb 100644
--- a/fpdfsdk/fpdf_save.cpp
+++ b/fpdfsdk/fpdf_save.cpp
@@ -75,10 +75,10 @@
       iDataSetsIndex = i + 1;
   }
 
-  CPDF_Stream* pFormStream = nullptr;
+  RetainPtr<CPDF_Stream> pFormStream;
   if (iFormIndex != -1) {
     // Get form CPDF_Stream
-    CPDF_Object* pFormPDFObj = pArray->GetObjectAt(iFormIndex);
+    RetainPtr<CPDF_Object> pFormPDFObj = pArray->GetMutableObjectAt(iFormIndex);
     if (pFormPDFObj->IsReference()) {
       CPDF_Object* pFormDirectObj = pFormPDFObj->GetDirect();
       if (pFormDirectObj && pFormDirectObj->IsStream()) {
@@ -89,10 +89,11 @@
     }
   }
 
-  CPDF_Stream* pDataSetsStream = nullptr;
+  RetainPtr<CPDF_Stream> pDataSetsStream;
   if (iDataSetsIndex != -1) {
     // Get datasets CPDF_Stream
-    CPDF_Object* pDataSetsPDFObj = pArray->GetObjectAt(iDataSetsIndex);
+    RetainPtr<CPDF_Object> pDataSetsPDFObj =
+        pArray->GetMutableObjectAt(iDataSetsIndex);
     if (pDataSetsPDFObj->IsReference()) {
       CPDF_Reference* pDataSetsRefObj = pDataSetsPDFObj->AsReference();
       CPDF_Object* pDataSetsDirectObj = pDataSetsRefObj->GetDirect();