Introduce CPDF_Array::Contains()

Use Contains() in CPDF_OCContext in place of FindGroup(). Note
that FindGroup() should have probably returned a bool in the first
place, since we only test for a found/not-found result.

-- add unit test.
-- slightly re-order header to match cpp.
-- de-dup some code with calls to GetObjectAt().

Change-Id: I4ce31652f212e83014555e6b282c27cba5e90455
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/87370
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/page/cpdf_occontext.cpp b/core/fpdfapi/page/cpdf_occontext.cpp
index 21b8ec6..1318ad8 100644
--- a/core/fpdfapi/page/cpdf_occontext.cpp
+++ b/core/fpdfapi/page/cpdf_occontext.cpp
@@ -14,17 +14,6 @@
 
 namespace {
 
-int32_t FindGroup(const CPDF_Array* pArray, const CPDF_Dictionary* pGroupDict) {
-  if (!pArray || !pGroupDict)
-    return -1;
-
-  for (size_t i = 0; i < pArray->size(); i++) {
-    if (pArray->GetDictAt(i) == pGroupDict)
-      return i;
-  }
-  return -1;
-}
-
 bool HasIntent(const CPDF_Dictionary* pDict,
                ByteStringView csElement,
                ByteStringView csDef) {
@@ -56,7 +45,7 @@
   if (!pOCGs)
     return nullptr;
 
-  if (FindGroup(pOCGs, pOCGDict) < 0)
+  if (!pOCGs->Contains(pOCGDict))
     return nullptr;
 
   CPDF_Dictionary* pConfig = pOCProperties->GetDictFor("D");
@@ -109,15 +98,13 @@
 
   bool bState = pConfig->GetStringFor("BaseState", "ON") != "OFF";
   CPDF_Array* pArray = pConfig->GetArrayFor("ON");
-  if (pArray) {
-    if (FindGroup(pArray, pOCGDict) >= 0)
-      bState = true;
-  }
+  if (pArray && pArray->Contains(pOCGDict))
+    bState = true;
+
   pArray = pConfig->GetArrayFor("OFF");
-  if (pArray) {
-    if (FindGroup(pArray, pOCGDict) >= 0)
-      bState = false;
-  }
+  if (pArray && pArray->Contains(pOCGDict))
+    bState = false;
+
   pArray = pConfig->GetArrayFor("AS");
   if (!pArray)
     return bState;
@@ -135,7 +122,7 @@
     if (!pOCGs)
       continue;
 
-    if (FindGroup(pOCGs, pOCGDict) < 0)
+    if (!pOCGs->Contains(pOCGDict))
       continue;
 
     CPDF_Dictionary* pState = pUsage->GetDictFor(csConfig);
diff --git a/core/fpdfapi/parser/cpdf_array.cpp b/core/fpdfapi/parser/cpdf_array.cpp
index 719d918..10d8538 100644
--- a/core/fpdfapi/parser/cpdf_array.cpp
+++ b/core/fpdfapi/parser/cpdf_array.cpp
@@ -88,6 +88,14 @@
                     GetNumberAt(3), GetNumberAt(4), GetNumberAt(5));
 }
 
+bool CPDF_Array::Contains(const CPDF_Object* pThat) const {
+  for (size_t i = 0; i < m_Objects.size(); ++i) {
+    if (GetDirectObjectAt(i) == pThat)
+      return true;
+  }
+  return false;
+}
+
 CPDF_Object* CPDF_Array::GetObjectAt(size_t index) {
   if (index >= m_Objects.size())
     return nullptr;
@@ -101,15 +109,13 @@
 }
 
 CPDF_Object* CPDF_Array::GetDirectObjectAt(size_t index) {
-  if (index >= m_Objects.size())
-    return nullptr;
-  return m_Objects[index]->GetDirect();
+  CPDF_Object* pObj = GetObjectAt(index);
+  return pObj ? pObj->GetDirect() : nullptr;
 }
 
 const CPDF_Object* CPDF_Array::GetDirectObjectAt(size_t index) const {
-  if (index >= m_Objects.size())
-    return nullptr;
-  return m_Objects[index]->GetDirect();
+  const CPDF_Object* pObj = GetObjectAt(index);
+  return pObj ? pObj->GetDirect() : nullptr;
 }
 
 ByteString CPDF_Array::GetStringAt(size_t index) const {
diff --git a/core/fpdfapi/parser/cpdf_array.h b/core/fpdfapi/parser/cpdf_array.h
index d3288bd..5c0c255 100644
--- a/core/fpdfapi/parser/cpdf_array.h
+++ b/core/fpdfapi/parser/cpdf_array.h
@@ -66,8 +66,10 @@
   CPDF_Array* GetArrayAt(size_t index);
   const CPDF_Array* GetArrayAt(size_t index) const;
 
-  CFX_Matrix GetMatrix() const;
   CFX_FloatRect GetRect() const;
+  CFX_Matrix GetMatrix() const;
+
+  bool Contains(const CPDF_Object* pThat) const;
 
   // Creates object owned by the array, returns unowned pointer to it.
   // We have special cases for objects that can intern strings from
diff --git a/core/fpdfapi/parser/cpdf_array_unittest.cpp b/core/fpdfapi/parser/cpdf_array_unittest.cpp
index e8c143b..a70599d 100644
--- a/core/fpdfapi/parser/cpdf_array_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_array_unittest.cpp
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "core/fpdfapi/parser/cpdf_boolean.h"
+#include "core/fpdfapi/parser/cpdf_dictionary.h"
 #include "core/fpdfapi/parser/cpdf_number.h"
 #include "core/fpdfapi/parser/cpdf_reference.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -188,6 +189,18 @@
   }
 }
 
+TEST(cpdf_array, Contains) {
+  auto arr = pdfium::MakeRetain<CPDF_Array>();
+  auto dict0 = pdfium::MakeRetain<CPDF_Dictionary>();
+  auto dict1 = pdfium::MakeRetain<CPDF_Dictionary>();
+  auto dict2 = pdfium::MakeRetain<CPDF_Dictionary>();
+  arr->Append(dict0);
+  arr->Append(dict1);
+  EXPECT_TRUE(arr->Contains(dict0.Get()));
+  EXPECT_TRUE(arr->Contains(dict1.Get()));
+  EXPECT_FALSE(arr->Contains(dict2.Get()));
+}
+
 TEST(cpdf_array, Iterator) {
   const int elems[] = {-23, -11,     3,         455,   2345877,
                        0,   7895330, -12564334, 10000, -100000};